failproofai 0.0.11-beta.9 → 0.0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.next/standalone/.next/BUILD_ID +1 -1
- package/.next/standalone/.next/build-manifest.json +3 -3
- package/.next/standalone/.next/prerender-manifest.json +3 -3
- package/.next/standalone/.next/required-server-files.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_global-error.html +1 -1
- package/.next/standalone/.next/server/app/_global-error.rsc +7 -7
- package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +7 -7
- package/.next/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_not-found.html +1 -1
- package/.next/standalone/.next/server/app/_not-found.rsc +15 -15
- package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +15 -15
- package/.next/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +10 -10
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/api/audit/invite/route.js +1 -1
- package/.next/standalone/.next/server/app/api/audit/invite/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/audit/run/route.js +1 -1
- package/.next/standalone/.next/server/app/api/audit/run/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/login-request/route.js +1 -1
- package/.next/standalone/.next/server/app/api/auth/login-request/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/login-verify/route.js +1 -1
- package/.next/standalone/.next/server/app/api/auth/login-verify/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/logout/route.js +1 -1
- package/.next/standalone/.next/server/app/api/auth/logout/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/reminder/route.js +1 -1
- package/.next/standalone/.next/server/app/api/auth/reminder/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/status/route.js +1 -1
- package/.next/standalone/.next/server/app/api/auth/status/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/audit/page/server-reference-manifest.json +2 -2
- package/.next/standalone/.next/server/app/audit/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/audit/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/index.html +1 -1
- package/.next/standalone/.next/server/app/index.rsc +15 -15
- package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +15 -15
- package/.next/standalone/.next/server/app/index.segments/_head.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/index.segments/_index.segment.rsc +10 -10
- package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +8 -8
- package/.next/standalone/.next/server/app/policies/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/policies/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/project/[name]/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/project/[name]/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/project/[name]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/react-loadable-manifest.json +2 -2
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/server-reference-manifest.json +2 -2
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/projects/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/projects/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/chunks/[externals]__1_g_b3t._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0dwpg-h._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0lnenda._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__13i_sva._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1_mqemn._.js +1 -1
- package/.next/standalone/.next/server/chunks/node_modules_0-tu4ot._.js +1 -1
- package/.next/standalone/.next/server/chunks/node_modules_1bnh1y0._.js +1 -1
- package/.next/standalone/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_17k9e3w.js +3 -3
- package/.next/standalone/.next/server/chunks/node_modules_posthog-node_dist_entrypoints_index_node_mjs_01r25oi._.js +1 -1
- package/.next/standalone/.next/server/chunks/node_modules_posthog-node_dist_entrypoints_index_node_mjs_09z9-p7._.js +1 -1
- package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4v._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0e446gb._.js → [root-of-the-server]__00uwqi6._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0808sha._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0e4-6d8._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0ehe24g._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0g253ve._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0k65l27._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0wprfyc._.js → [root-of-the-server]__0kjb_s4._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0vxf0_g._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__12mcauo._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1mt35_w._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1pcxxwg._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1uvfwgr._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/_11_p9y8._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47._.js +49 -21
- package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_1kp6l3x._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_19dqvpc._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/{node_modules_html-to-image_es_index_0y4a-0q.js → node_modules_html-to-image_es_index_0ihmbv4.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/node_modules_posthog-node_dist_entrypoints_index_node_mjs_11bnuzn._.js +1 -1
- package/.next/standalone/.next/server/middleware-build-manifest.js +3 -3
- package/.next/standalone/.next/server/pages/404.html +1 -1
- package/.next/standalone/.next/server/pages/500.html +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.json +10 -10
- package/.next/standalone/.next/static/chunks/{3ty6dhcuogout.js → 02fywjt0by40a.js} +1 -1
- package/.next/standalone/.next/static/chunks/0xdx2ehtbdoeg.js +1 -0
- package/.next/standalone/.next/static/chunks/{07_d165p5h5ys.js → 1-a5rvq67k7ed.js} +1 -1
- package/.next/standalone/.next/static/chunks/{3nj6g3xu9uy78.js → 15csyj1_rf0-w.js} +1 -1
- package/.next/standalone/.next/static/chunks/1o0xa47736gi9.css +2 -0
- package/.next/standalone/.next/static/chunks/24cv31x607n7k.js +1 -0
- package/.next/standalone/.next/static/chunks/2n_s8v1ae38_a.js +69 -0
- package/.next/standalone/.next/static/chunks/{277oc363p56n6.js → 2y-jmvrjxz60x.js} +2 -2
- package/.next/standalone/.next/static/chunks/{1kvadxkgnapyj.js → 3eik_d9qrvoft.js} +1 -1
- package/.next/standalone/.next/static/chunks/{168k-8z6k7e8z.css → 3i27c3hcriawq.css} +1 -1
- package/.next/standalone/.next/static/chunks/{2z42u62k-8-_q.js → 3v61675vr6jav.js} +1 -1
- package/.next/standalone/app/api/audit/invite/route.ts +10 -1
- package/.next/standalone/app/api/audit/run/route.ts +35 -0
- package/.next/standalone/app/api/auth/login-request/route.ts +2 -2
- package/.next/standalone/app/api/auth/login-verify/route.ts +10 -2
- package/.next/standalone/app/audit/_components/audit-dashboard.tsx +9 -1
- package/.next/standalone/app/audit/_components/audit-poster.tsx +11 -7
- package/.next/standalone/app/audit/_components/auth-dialog.tsx +6 -4
- package/.next/standalone/app/audit/_components/come-back-better-section.tsx +23 -3
- package/.next/standalone/app/audit/_components/invite-dialog.tsx +6 -3
- package/.next/standalone/app/audit/_components/share-templates.ts +58 -28
- package/.next/standalone/app/audit/audit-styles.css +17 -22
- package/.next/standalone/app/globals.css +27 -2
- package/.next/standalone/app/policies/hooks-client.tsx +33 -24
- package/.next/standalone/components/reach-developers.tsx +10 -25
- package/.next/standalone/lib/auth/api-server-client.ts +5 -2
- package/.next/standalone/lib/client-telemetry.ts +4 -0
- package/.next/standalone/package.json +6 -4
- package/.next/standalone/server.js +1 -1
- package/README.md +2 -2
- package/bin/failproofai.mjs +24 -5
- package/dist/cli.mjs +2328 -381
- package/lib/auth/api-server-client.ts +5 -2
- package/lib/client-telemetry.ts +4 -0
- package/package.json +6 -4
- package/scripts/launch.ts +30 -4
- package/scripts/postinstall.mjs +10 -1
- package/scripts/skew-log-filter.ts +46 -0
- package/scripts/validate-mdx.ts +139 -0
- package/src/audit/cli.ts +330 -0
- package/src/audit/open-browser.ts +69 -0
- package/src/auth/cli.ts +16 -13
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1r1h8v9._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1uatkiv._.js +0 -3
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1y6gxxb._.js +0 -3
- package/.next/standalone/.next/static/chunks/28mkxkl_d91-l.js +0 -1
- package/.next/standalone/.next/static/chunks/28x7jvo3kxd3u.js +0 -41
- package/.next/standalone/.next/static/chunks/29nrs5xs9c4hx.css +0 -2
- package/.next/standalone/.next/static/chunks/29tg7deqmq32l.js +0 -1
- /package/.next/standalone/.next/static/{NYPiJP6Rv_exQdSFVS8HP → P_MIRSeoE296wkbE-Icin}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{NYPiJP6Rv_exQdSFVS8HP → P_MIRSeoE296wkbE-Icin}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/.next/static/{NYPiJP6Rv_exQdSFVS8HP → P_MIRSeoE296wkbE-Icin}/_ssgManifest.js +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
.empty-section,.running-section{padding-top:80px;padding-bottom:96px}.empty-panel,.running-panel{background:var(--bg-2);border:1px solid var(--line-2);flex-direction:column;padding:48px 56px;display:flex}.empty-glyph{text-align:center;align-self:center;margin-bottom:28px}.empty-glyph-grid{border:1px solid var(--line-2);background:var(--bg);grid-template-rows:repeat(6,14px);grid-template-columns:repeat(6,14px);gap:3px;margin:0 auto 14px;padding:16px;display:grid}.empty-glyph-grid .px{background:0 0}.empty-glyph-grid .px.on{background:var(--accent-pink)}.empty-glyph-label{font-family:var(--font-mono);letter-spacing:.22em;text-transform:uppercase;color:var(--dim);font-size:11px}.empty-headline{font-family:var(--font-display);letter-spacing:.1em;text-transform:lowercase;color:var(--ink);text-wrap:balance;text-align:center;margin:0 0 16px;font-size:clamp(32px,4.6vw,48px);line-height:1.05}.empty-sub{font-family:var(--font-mono);color:var(--ink-2);text-align:center;max-width:580px;margin:0 auto 32px;font-size:14px;line-height:1.65}.empty-actions{flex-direction:column;align-items:center;gap:12px;display:flex}.empty-cta{letter-spacing:.08em;padding:12px 24px;font-size:14px;text-decoration:none}.empty-meta{font-family:var(--font-mono);letter-spacing:.15em;text-transform:uppercase;color:var(--dim);font-size:11px}.running-panel{padding:36px 40px}.running-header{border-bottom:1px dashed var(--line);font-family:var(--font-mono);align-items:center;gap:10px;margin-bottom:22px;padding-bottom:18px;font-size:13px;display:flex}.running-prompt{color:var(--accent-green)}.running-cmd{color:var(--ink);letter-spacing:.02em}.running-cursor{color:var(--accent-pink);margin-left:4px;animation:.9s steps(2,end) infinite cursor-blink}@keyframes cursor-blink{50%{opacity:0}}.running-stages{flex-direction:column;margin:0 0 28px;padding:0;list-style:none;display:flex}.running-stage{border-bottom:1px dashed var(--line);font-family:var(--font-mono);grid-template-columns:28px 1fr auto;align-items:start;gap:14px;padding:12px 0;display:grid}.running-stage:last-child{border-bottom:none}.running-marker{font-family:var(--font-mono);letter-spacing:-1px;margin-top:1px;font-size:12px}.running-stage.queued{color:var(--dim)}.running-stage.queued .running-marker{color:var(--line-2)}.running-stage.active{color:var(--ink)}.running-stage.active .running-marker{color:var(--accent-pink)}.running-stage.done{color:var(--ink-2)}.running-stage.done .running-marker{color:var(--accent-green)}.running-stage.done .running-stage-label{text-decoration:line-through;-webkit-text-decoration-color:var(--line-2);text-decoration-color:var(--line-2)}.running-stage-label{letter-spacing:.04em;font-size:13px}.running-stage-detail{color:var(--ink-2);letter-spacing:.02em;margin-top:4px;font-size:11px}.running-stage-spin{font-family:var(--font-mono);color:var(--accent-pink);align-self:center;font-size:16px;animation:.7s steps(4,end) infinite spin-step}@keyframes spin-step{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.running-bar-label{font-family:var(--font-mono);letter-spacing:.22em;text-transform:uppercase;color:var(--ink-2);justify-content:space-between;margin-bottom:8px;font-size:10px;display:flex}.running-bar-track{background:var(--bg);border:1px solid var(--line);height:6px;position:relative;overflow:hidden}.running-bar-fill{background:linear-gradient(90deg, var(--accent-pink) 0%, #e89aaf 100%);height:100%;transition:width .6s cubic-bezier(.22,1,.36,1);position:relative}.running-bar-fill:after{content:"";background:linear-gradient(90deg,#0000 0% 40%,#ffffff59 50%,#0000 60% 100%);animation:1.6s linear infinite bar-shine;position:absolute;inset:0}@keyframes bar-shine{0%{transform:translate(-100%)}to{transform:translate(100%)}}.running-foot{font-family:var(--font-mono);letter-spacing:.05em;color:var(--dim);text-align:center;margin-top:22px;font-size:11px}@media (max-width:720px){.empty-panel,.running-panel{padding:32px 24px}}.report{width:100%;max-width:clamp(720px,92vw,1480px);margin:0 auto;padding:0 clamp(20px,3vw,48px)}.section{border-bottom:1px solid var(--line);padding:64px 0;position:relative}.section:last-child{border-bottom:none}.section-mast{flex-wrap:wrap;justify-content:space-between;align-items:baseline;gap:24px;margin-bottom:28px;display:flex}.section-label{font-family:var(--font-mono);letter-spacing:.2em;text-transform:uppercase;color:var(--accent-green);align-items:baseline;gap:10px;font-size:11px;display:inline-flex}.section-label .glyph{color:var(--accent-pink);letter-spacing:-2px}.section-meta{font-family:var(--font-mono);letter-spacing:.18em;text-transform:uppercase;color:var(--dim);font-size:11px}.section-meta .g{color:var(--accent-green)}.section-meta .p{color:var(--accent-pink)}.section-h{font-family:var(--font-display);letter-spacing:.11em;color:var(--ink);text-transform:lowercase;text-wrap:balance;margin:0 0 18px;font-size:clamp(28px,4vw,44px);font-weight:400;line-height:1.05}.report-footer{border-top:1px solid var(--line);background:var(--bg);text-align:center;font-family:var(--font-mono);letter-spacing:.15em;text-transform:uppercase;color:var(--dim);padding:48px 32px 24px;font-size:11px}.report-footer--fixed{z-index:10;padding:16px 32px;position:fixed;bottom:0;left:0;right:0}.report-footer .brand-mark{color:var(--accent-pink);font-family:var(--font-mono);letter-spacing:-2px;margin-right:6px;font-size:14px;font-weight:700}.auth-dialog-backdrop{z-index:10000;-webkit-backdrop-filter:blur(6px);background:#08080ab3;place-items:center;padding:32px 16px;display:grid;position:fixed;inset:0}.auth-dialog{border:1px solid var(--line-2);background:var(--bg-2);width:100%;max-width:420px;font-family:var(--font-mono);color:var(--ink);padding:28px 28px 24px;position:relative}.auth-close{font-family:var(--font-mono);color:var(--dim);cursor:pointer;background:0 0;border:none;padding:4px 8px;font-size:20px;line-height:1;transition:color .12s;position:absolute;top:12px;right:14px}.auth-close:hover{color:var(--accent-pink)}.auth-close:disabled{color:var(--line-2);cursor:not-allowed}.auth-headline{font-family:var(--font-mono);letter-spacing:0;text-transform:none;color:var(--ink);margin:0 0 8px;font-size:18px;font-weight:600;line-height:1.3}.auth-sub{font-family:var(--font-mono);color:var(--ink-2);margin:0 0 18px;font-size:12px;line-height:1.55}.auth-sub .auth-email{color:var(--accent-pink)}.auth-sub .auth-ok{color:var(--accent-green);margin-right:6px}.auth-form{flex-direction:column;gap:10px;display:flex}.auth-field-label{font-family:var(--font-mono);letter-spacing:.22em;text-transform:uppercase;color:var(--accent-green);font-size:10px}.auth-input{background:var(--bg);border:1px solid var(--line-2);width:100%;color:var(--ink);font-family:var(--font-mono);letter-spacing:.03em;outline:none;padding:11px 14px;font-size:14px;transition:border-color .12s,box-shadow .12s}.auth-input:focus{border-color:var(--accent-pink);box-shadow:0 0 0 1px var(--accent-pink-soft)}.auth-input:disabled{opacity:.55;cursor:not-allowed}.auth-input-code{letter-spacing:.5em;text-align:center;font-variant-numeric:tabular-nums;font-size:18px}.auth-input::placeholder{color:var(--dim)}.auth-error{font-family:var(--font-mono);color:var(--accent-pink);background:var(--accent-pink-bg);border:1px solid var(--accent-pink);letter-spacing:.02em;border-left-width:3px;margin-top:4px;padding:8px 12px;font-size:12px}.auth-actions{flex-wrap:wrap;gap:10px;margin-top:14px;display:flex}.auth-btn{font-family:var(--font-mono);letter-spacing:.06em;border:1px solid var(--line-2);color:var(--ink);cursor:pointer;background:0 0;align-items:center;gap:8px;padding:10px 16px;font-size:12px;transition:all .12s;display:inline-flex}.auth-btn:hover:not(:disabled){border-color:var(--ink);background:#ffffff0a}.auth-btn:disabled{opacity:.45;cursor:not-allowed}.auth-btn.primary{border-color:var(--accent-pink);color:var(--accent-pink);background:var(--accent-pink-bg)}.auth-btn.primary:hover:not(:disabled){background:var(--accent-pink);color:var(--bg)}.auth-back{font-family:var(--font-mono);letter-spacing:.1em;color:var(--dim);cursor:pointer;background:0 0;border:none;align-self:flex-start;margin-top:4px;padding:6px 0;font-size:11px;transition:color .12s}.auth-back:hover:not(:disabled){color:var(--ink-2)}.auth-back:disabled{opacity:.45;cursor:not-allowed}@media (max-width:520px){.auth-dialog{padding:26px 22px 22px}.auth-actions{flex-direction:column;align-items:stretch}.auth-btn{justify-content:center}}.auth-status-pill{border:1px dashed var(--line-2);font-family:var(--font-mono);letter-spacing:.1em;color:var(--ink-2);align-items:center;gap:8px;margin-top:16px;padding:6px 10px;font-size:11px;display:inline-flex}.auth-status-pill .dot{background:var(--accent-green);width:7px;height:7px;display:inline-block;box-shadow:0 0 6px #66d1b58c}.auth-status-pill .email{color:var(--accent-green)}@media (max-width:960px){.report{padding:0 20px}.archetype-frame{padding:32px 24px}.arch-body{grid-template-columns:1fr;gap:32px}.arch-meta-grid,.score-grid{grid-template-columns:1fr;gap:16px}.finding-body{grid-template-columns:1fr}.finding-block{border-right:none!important}.policies-grid,.share-grid{grid-template-columns:1fr}.strength-row{grid-template-columns:40px 1fr}.strength-metric{text-align:left;grid-column:2;margin-top:6px}.return-hook{padding:28px 24px}}@media (prefers-reduced-motion:reduce){.running-cursor,.running-stage-spin,.running-bar-fill:after,.auth-status-pill .dot{animation:none}.running-bar-fill{transition:none}}.audit-progress-strip{z-index:60;background:var(--bg-2);border-bottom:1px solid var(--accent-pink);font-family:var(--font-mono);animation:.22s cubic-bezier(.22,1,.36,1) audit-progress-slide-in;position:sticky;top:0;left:0;right:0}.audit-progress-strip--failed{border-bottom-color:var(--accent-pink);background:linear-gradient(to right, var(--accent-pink-bg), var(--bg-2))}.audit-progress-strip__inner{justify-content:space-between;align-items:center;gap:16px;max-width:1480px;margin:0 auto;padding:12px clamp(20px,3vw,48px);display:flex;position:relative}.audit-progress-strip__label{color:var(--ink);letter-spacing:.06em;text-transform:lowercase;align-items:center;gap:10px;font-size:12px;display:inline-flex}.audit-progress-strip--failed .audit-progress-strip__label{color:var(--accent-pink)}.audit-progress-strip__elapsed{font-variant-numeric:tabular-nums;color:var(--accent-pink);letter-spacing:.08em;font-size:12px}.audit-progress-strip__spinner{border:1.5px solid var(--accent-pink);background:0 0;border-top-color:#0000;border-radius:50%;width:9px;height:9px;animation:.8s linear infinite audit-progress-spin}.audit-progress-strip__x{border:1px solid var(--accent-pink);width:14px;height:14px;color:var(--accent-pink);justify-content:center;align-items:center;font-size:11px;line-height:1;display:inline-flex}.audit-progress-strip__dismiss{border:1px solid var(--line-2);color:var(--ink-2);font-family:var(--font-mono);text-transform:lowercase;letter-spacing:.06em;cursor:pointer;background:0 0;padding:5px 10px;font-size:11px;transition:border-color .14s,color .14s}.audit-progress-strip__dismiss:hover{border-color:var(--accent-pink);color:var(--accent-pink)}.audit-progress-strip__pulse{background:linear-gradient(90deg, transparent 0%, var(--accent-pink) 20%, var(--accent-pink) 80%, transparent 100%);transform-origin:0;height:1px;animation:2.4s cubic-bezier(.55,.1,.45,.9) infinite audit-progress-pulse;position:absolute;bottom:-1px;left:0;right:0}@keyframes audit-progress-spin{to{transform:rotate(360deg)}}@keyframes audit-progress-pulse{0%{opacity:.4;transform:scaleX(0)translate(0%)}50%{opacity:1;transform:scaleX(.6)translate(20%)}to{opacity:.2;transform:scaleX(0)translate(100%)}}@keyframes audit-progress-slide-in{0%{opacity:0;transform:translateY(-100%)}to{opacity:1;transform:translateY(0)}}@media (prefers-reduced-motion:reduce){.audit-progress-strip{animation:none}.audit-progress-strip__spinner{border-top-color:var(--accent-pink);animation:none}.audit-progress-strip__pulse{opacity:.4;animation:none;transform:scaleX(.4)translate(30%)}}.poster-section{border-bottom:1px solid var(--line);flex-direction:column;gap:14px;height:calc(100vh - 52px);padding:20px 0 16px;display:flex}.poster{border:1px dashed var(--accent-pink-soft);background:var(--bg-2);flex-direction:column;flex:auto;width:100%;max-width:980px;min-height:0;margin:0 auto;padding:22px 40px;display:flex;position:relative;overflow:hidden}.poster-head{flex:none}.poster-body{flex:auto}.poster-foot{flex:none}.poster-head{border-bottom:1px dashed var(--line);font-family:var(--font-mono);letter-spacing:.04em;flex-wrap:wrap;justify-content:space-between;align-items:baseline;gap:18px;padding-bottom:12px;font-size:11px;display:flex}.poster-wordmark{color:var(--ink);align-items:center;gap:8px;display:inline-flex}.poster-wordmark .poster-logo{width:auto;height:14px;display:block}.poster-wordmark .poster-sep{color:var(--dim);margin:0 2px}.poster-meta{color:var(--dim)}.poster-meta .poster-ix{color:var(--accent-pink)}.poster-meta .of,.poster-meta .poster-sep{color:var(--dim)}.poster-body{text-align:center;flex-direction:column;justify-content:center;align-items:center;gap:clamp(14px,2.6vh,30px);min-height:0;padding:clamp(6px,1.4vh,16px) 0;display:flex}.poster-sigil .sigil{background:var(--bg);border:1px solid var(--line-2);grid-template-rows:repeat(8,clamp(10px,1.7vh,16px));grid-template-columns:repeat(8,clamp(10px,1.7vh,16px));gap:2px;padding:clamp(6px,1vh,10px);display:grid}.poster-persona{flex-direction:column;align-items:center;gap:clamp(6px,1.2vh,14px);min-width:0;display:flex}.poster-persona .persona-name{font-family:var(--font-display);letter-spacing:.03em;color:var(--ink);text-transform:lowercase;text-wrap:balance;margin:0;font-size:clamp(32px,6.5vh,64px);line-height:.95}.poster-persona .persona-keywords{font-family:var(--font-display);letter-spacing:.06em;text-transform:lowercase;font-size:clamp(16px,2.2vh,22px)}.poster-persona .persona-keywords .kw-0{color:var(--accent-green)}.poster-persona .persona-keywords .kw-1{color:var(--ink)}.poster-persona .persona-keywords .kw-2{color:var(--accent-pink)}.poster-persona .persona-keywords .kw-sep{color:var(--dim);margin:0 10px}.poster-persona .persona-rarity{font-family:var(--font-mono);color:var(--accent-green);letter-spacing:.02em;font-size:clamp(11px,1.3vh,13px)}.poster-persona .persona-rarity .lbl{color:var(--dim)}.poster-persona .persona-rarity .pct{color:var(--accent-pink);font-weight:600}.poster-score{justify-content:center;align-items:baseline;gap:clamp(10px,1.4vh,16px);display:flex}.poster-score .score-n{font-family:var(--font-mono);letter-spacing:-.02em;color:var(--accent-pink);font-variant-numeric:tabular-nums;font-size:clamp(56px,11vh,112px);font-weight:700;line-height:1}.poster-score .score-of{font-family:var(--font-mono);color:var(--dim);letter-spacing:.04em;margin-right:clamp(12px,2vh,28px);font-size:clamp(16px,2vh,22px);line-height:1}.poster-score .score-rank{font-family:var(--font-mono);letter-spacing:.32em;text-transform:uppercase;color:var(--accent-green);border:1px solid var(--accent-green);white-space:nowrap;background:#66d1b50d;padding:6px 14px;font-size:clamp(10px,1.3vh,12px);line-height:1}.poster-sigil .sigil .px{background:0 0}.poster-sigil .sigil .px.on{background:var(--ink)}.poster-sigil .sigil .px.p{background:var(--accent-pink)}.poster-sigil .sigil .px.g{background:var(--accent-green)}.poster-sigil .sigil .px.d{background:var(--dim)}.poster-foot{border-top:1px dashed var(--line);font-family:var(--font-mono);justify-content:flex-end;padding-top:10px;font-size:10px;display:flex}.poster-cta{color:var(--accent-green);letter-spacing:.04em}.poster-cta .arrow{color:var(--accent-pink);margin:0 4px}.poster-share-row{flex:none;grid-template-columns:repeat(3,1fr);gap:10px;max-width:980px;margin:0 auto;display:grid}.poster-share-btn{border:1px solid var(--line-2);background:var(--bg-2);color:var(--ink);font-family:var(--font-mono);letter-spacing:.04em;cursor:pointer;justify-content:center;align-items:center;gap:10px;padding:12px 16px;font-size:12px;transition:border-color .14s,color .14s,background .14s;display:inline-flex}.poster-share-btn:hover{border-color:var(--accent-pink);color:var(--accent-pink);background:var(--accent-pink-bg)}.poster-share-btn:disabled{opacity:.55;cursor:wait}.poster-share-btn:focus-visible,.cadence-btn:focus-visible,.invite-btn:focus-visible,.install-all-btn:focus-visible,.copy-icon-btn:focus-visible,.fix-install-btn:focus-visible{outline:2px solid var(--accent-pink);outline-offset:2px}.poster-share-btn .mark{color:var(--accent-pink);font-weight:700}.poster-scroll-hint{text-align:center;font-family:var(--font-mono);letter-spacing:.22em;text-transform:uppercase;color:var(--dim);flex:none;margin:0;font-size:10px}.poster-scroll-hint .arrow{color:var(--accent-pink);margin-left:6px}@media (max-width:720px){.poster{padding:24px 22px}.poster-body{gap:28px;padding:12px 0}.poster-share-row{grid-template-columns:1fr}.poster-head{font-size:10px}.poster-score .score-n{font-size:clamp(72px,18vw,120px)}.poster-persona .persona-name{font-size:clamp(36px,9vw,56px)}}.audit-sec{border-bottom:1px solid var(--line);padding:48px 0}.audit-sec:last-child{border-bottom:none}.audit-sec-head{justify-content:space-between;align-items:baseline;gap:16px;margin-bottom:6px;display:flex}.audit-sec-eyebrow{font-family:var(--font-mono);letter-spacing:.2em;text-transform:uppercase;color:var(--accent-green);font-size:11px}.audit-sec-eyebrow .ix{color:var(--dim);margin-right:8px}.audit-sec-meta{font-family:var(--font-mono);color:var(--dim);letter-spacing:.04em;font-size:11px}.audit-sec-meta strong{color:var(--ink);font-weight:600}.audit-sec-title{font-family:var(--font-mono);letter-spacing:-.01em;color:var(--ink);margin:4px 0 18px;font-size:18px;font-weight:600}.strength-list{flex-direction:column;display:flex}.strength-row{border-bottom:1px dashed var(--line);font-family:var(--font-mono);grid-template-columns:24px 1fr auto;align-items:baseline;gap:14px;padding:12px 0;display:grid}.strength-row:last-child{border-bottom:none}.strength-check{color:var(--accent-green);font-size:14px;line-height:1}.strength-body{flex-direction:column;gap:2px;min-width:0;display:flex}.strength-headline{color:var(--ink);letter-spacing:.02em;font-size:13px}.strength-detail{color:var(--ink-2);letter-spacing:.02em;font-size:11px}.strength-metric{font-family:var(--font-display);letter-spacing:.04em;color:var(--accent-green);text-align:right;white-space:nowrap;font-size:22px;line-height:1}.strength-metric .unit{font-family:var(--font-mono);letter-spacing:.18em;text-transform:uppercase;color:var(--dim);margin-top:4px;font-size:9px;display:block}.quirks-table{font-family:var(--font-mono)}.quirks-thead,.quirks-row{grid-template-columns:80px 1fr 90px 100px;align-items:center;gap:14px;display:grid}.quirks-thead{border-bottom:1px solid var(--line);color:var(--dim);letter-spacing:.18em;text-transform:uppercase;padding:0 0 8px;font-size:10px}.quirks-thead span:last-child{text-align:right}.quirks-row{border-bottom:1px dashed var(--line);padding:12px 0;font-size:12px}.quirks-row:last-child{border-bottom:none}.q-when{color:var(--dim);font-size:11px}.q-what{flex-direction:column;gap:2px;min-width:0;display:flex}.q-title{color:var(--ink);font-size:12px}.q-policy{color:var(--dim);font-size:10px}.q-policy code{color:var(--accent-green);background:0 0}.q-pill{border:1px solid var(--line-2);text-align:center;letter-spacing:.12em;text-transform:uppercase;justify-self:start;padding:2px 8px;font-size:10px}.q-pill-high{color:var(--accent-pink);background:#e4587c0f;border-color:#e4587c66}.q-pill-medium{color:var(--amber);background:var(--amber-bg);border-color:#e8c46a66}.q-pill-low{color:var(--ink-2)}.q-recur{text-align:right;color:var(--dim);letter-spacing:.04em;font-size:10px}.audit-sec-sub{font-family:var(--font-mono);color:var(--ink-2);margin:-10px 0 18px;font-size:12px;line-height:1.55}.audit-sec-sub strong{color:var(--ink);font-weight:600}.install-all-btn{border:1px solid var(--accent-pink);background:var(--accent-pink-bg);color:var(--accent-pink);font-family:var(--font-mono);letter-spacing:.18em;text-transform:uppercase;cursor:pointer;padding:8px 14px;font-size:11px;transition:background-color .14s}.install-all-btn:hover{background:#e4587c2e}.fix-list{flex-direction:column;display:flex}.fix-row{border-bottom:1px dashed var(--line);grid-template-columns:1fr minmax(280px,auto);align-items:center;gap:24px;padding:14px 0;display:grid}.fix-row:last-child{border-bottom:none}.fix-row-info{flex-direction:column;gap:4px;min-width:0;display:flex}.fix-name{font-family:var(--font-mono);color:var(--ink);letter-spacing:.01em;font-size:13px;font-weight:500}.fix-desc{font-family:var(--font-mono);color:var(--ink-2);font-size:11px;line-height:1.55}.fix-row-cmd{align-items:stretch;gap:6px;min-width:0;display:flex}.fix-cmd-code{min-width:0;font-family:var(--font-mono);color:var(--accent-green);background:var(--bg);border:1px solid var(--line);letter-spacing:.02em;white-space:nowrap;flex:1;align-items:center;padding:8px 12px;font-size:11px;display:flex;overflow-x:auto}.copy-icon-btn{border:1px solid var(--line);background:var(--bg);color:var(--ink-2);font-family:var(--font-mono);cursor:pointer;justify-content:center;align-items:center;min-width:36px;padding:0 10px;font-size:12px;transition:color .14s,border-color .14s;display:inline-flex}.copy-icon-btn:hover{color:var(--accent-pink);border-color:var(--accent-pink)}.cbb-grid{grid-template-columns:1fr 1fr;gap:14px;display:grid}.cbb-card{border:1px solid var(--line-2);background:var(--bg-2);flex-direction:column;gap:12px;padding:18px 20px;display:flex}.cbb-card-title{font-family:var(--font-mono);color:var(--ink);letter-spacing:.02em;font-size:14px}.cbb-card-sub{font-family:var(--font-mono);color:var(--ink-2);font-size:11px;line-height:1.55}.cadence-row{flex-wrap:wrap;gap:8px;margin-top:2px;display:flex}.cadence-btn{font-family:var(--font-mono);letter-spacing:.04em;border:1px solid var(--line-2);color:var(--ink);cursor:pointer;background:0 0;padding:6px 12px;font-size:11px;transition:border-color .14s,color .14s,background-color .14s}.cadence-btn:hover{border-color:var(--accent-pink);color:var(--accent-pink)}.cadence-btn.on{border-color:var(--accent-pink);background:var(--accent-pink-bg);color:var(--accent-pink)}.cadence-btn:disabled{opacity:.5;cursor:not-allowed}.cbb-link{color:var(--accent-green);font-family:var(--font-mono);letter-spacing:.04em;cursor:pointer;background:0 0;border:none;align-self:flex-start;padding:0;font-size:11px}.cbb-link:hover{color:var(--accent-pink)}.cbb-link:disabled{opacity:.55;cursor:wait}.perks-progress{background:var(--bg);border:1px solid var(--line-2);height:6px;margin:4px 0;position:relative}.perks-progress span{background:var(--accent-pink);height:100%;transition:width .24s;display:block}.perks-meta{font-family:var(--font-mono);color:var(--ink-2);font-size:11px}.perks-meta strong{color:var(--accent-pink);font-weight:600}.invite-btn{border:1px solid var(--accent-pink);background:var(--accent-pink-bg);color:var(--accent-pink);font-family:var(--font-mono);letter-spacing:.18em;text-transform:uppercase;cursor:pointer;align-self:flex-start;padding:8px 14px;font-size:11px;transition:background-color .14s}.invite-btn:hover{background:#e4587c2e}.invite-textarea{resize:vertical;letter-spacing:.02em;width:100%;min-height:90px;font-size:13px;line-height:1.45}.invite-summary{font-family:var(--font-mono);color:var(--dim);flex-wrap:wrap;gap:12px;margin-top:6px;font-size:11px;display:flex}.invite-summary .invite-valid{color:var(--accent-green)}.invite-summary .invite-invalid{color:var(--accent-pink)}.cbb-foot{font-family:var(--font-mono);color:var(--dim);margin-top:4px;font-size:10px}@media (max-width:720px){.cbb-grid{grid-template-columns:1fr}.fix-row{grid-template-columns:1fr;gap:8px}.fix-row-cmd{min-width:0}.quirks-thead,.quirks-row{grid-template-columns:1fr;gap:6px;padding:16px 0}.quirks-thead{display:none}}
|
|
1
|
+
.empty-section,.running-section{padding-top:80px;padding-bottom:96px}.empty-panel,.running-panel{background:var(--bg-2);border:1px solid var(--line-2);flex-direction:column;padding:48px 56px;display:flex}.empty-glyph{text-align:center;align-self:center;margin-bottom:28px}.empty-glyph-grid{border:1px solid var(--line-2);background:var(--bg);grid-template-rows:repeat(6,14px);grid-template-columns:repeat(6,14px);gap:3px;margin:0 auto 14px;padding:16px;display:grid}.empty-glyph-grid .px{background:0 0}.empty-glyph-grid .px.on{background:var(--accent-pink)}.empty-glyph-label{font-family:var(--font-mono);letter-spacing:.22em;text-transform:uppercase;color:var(--dim);font-size:11px}.empty-headline{font-family:var(--font-display);letter-spacing:.1em;text-transform:lowercase;color:var(--ink);text-wrap:balance;text-align:center;margin:0 0 16px;font-size:clamp(32px,4.6vw,48px);line-height:1.05}.empty-sub{font-family:var(--font-mono);color:var(--ink-2);text-align:center;max-width:580px;margin:0 auto 32px;font-size:14px;line-height:1.65}.empty-actions{flex-direction:column;align-items:center;gap:12px;display:flex}.empty-cta{letter-spacing:.08em;padding:12px 24px;font-size:14px;text-decoration:none}.empty-meta{font-family:var(--font-mono);letter-spacing:.15em;text-transform:uppercase;color:var(--dim);font-size:11px}.running-panel{padding:36px 40px}.running-header{border-bottom:1px dashed var(--line);font-family:var(--font-mono);align-items:center;gap:10px;margin-bottom:22px;padding-bottom:18px;font-size:13px;display:flex}.running-prompt{color:var(--accent-green)}.running-cmd{color:var(--ink);letter-spacing:.02em}.running-cursor{color:var(--accent-pink);margin-left:4px;animation:.9s steps(2,end) infinite cursor-blink}@keyframes cursor-blink{50%{opacity:0}}.running-stages{flex-direction:column;margin:0 0 28px;padding:0;list-style:none;display:flex}.running-stage{border-bottom:1px dashed var(--line);font-family:var(--font-mono);grid-template-columns:28px 1fr auto;align-items:start;gap:14px;padding:12px 0;display:grid}.running-stage:last-child{border-bottom:none}.running-marker{font-family:var(--font-mono);letter-spacing:-1px;margin-top:1px;font-size:12px}.running-stage.queued{color:var(--dim)}.running-stage.queued .running-marker{color:var(--line-2)}.running-stage.active{color:var(--ink)}.running-stage.active .running-marker{color:var(--accent-pink)}.running-stage.done{color:var(--ink-2)}.running-stage.done .running-marker{color:var(--accent-green)}.running-stage.done .running-stage-label{text-decoration:line-through;-webkit-text-decoration-color:var(--line-2);text-decoration-color:var(--line-2)}.running-stage-label{letter-spacing:.04em;font-size:13px}.running-stage-detail{color:var(--ink-2);letter-spacing:.02em;margin-top:4px;font-size:11px}.running-stage-spin{font-family:var(--font-mono);color:var(--accent-pink);align-self:center;font-size:16px;animation:.7s steps(4,end) infinite spin-step}@keyframes spin-step{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.running-bar-label{font-family:var(--font-mono);letter-spacing:.22em;text-transform:uppercase;color:var(--ink-2);justify-content:space-between;margin-bottom:8px;font-size:10px;display:flex}.running-bar-track{background:var(--bg);border:1px solid var(--line);height:6px;position:relative;overflow:hidden}.running-bar-fill{background:linear-gradient(90deg, var(--accent-pink) 0%, #e89aaf 100%);height:100%;transition:width .6s cubic-bezier(.22,1,.36,1);position:relative}.running-bar-fill:after{content:"";background:linear-gradient(90deg,#0000 0% 40%,#ffffff59 50%,#0000 60% 100%);animation:1.6s linear infinite bar-shine;position:absolute;inset:0}@keyframes bar-shine{0%{transform:translate(-100%)}to{transform:translate(100%)}}.running-foot{font-family:var(--font-mono);letter-spacing:.05em;color:var(--dim);text-align:center;margin-top:22px;font-size:11px}@media (max-width:720px){.empty-panel,.running-panel{padding:32px 24px}}.report{width:100%;max-width:clamp(720px,92vw,1480px);margin:0 auto;padding:0 clamp(20px,3vw,48px)}.section{border-bottom:1px solid var(--line);padding:64px 0;position:relative}.section:last-child{border-bottom:none}.section-mast{flex-wrap:wrap;justify-content:space-between;align-items:baseline;gap:24px;margin-bottom:28px;display:flex}.section-label{font-family:var(--font-mono);letter-spacing:.2em;text-transform:uppercase;color:var(--accent-green);align-items:baseline;gap:10px;font-size:11px;display:inline-flex}.section-label .glyph{color:var(--accent-pink);letter-spacing:-2px}.section-meta{font-family:var(--font-mono);letter-spacing:.18em;text-transform:uppercase;color:var(--dim);font-size:11px}.section-meta .g{color:var(--accent-green)}.section-meta .p{color:var(--accent-pink)}.section-h{font-family:var(--font-display);letter-spacing:.11em;color:var(--ink);text-transform:lowercase;text-wrap:balance;margin:0 0 18px;font-size:clamp(28px,4vw,44px);font-weight:400;line-height:1.05}.report-footer{border-top:1px solid var(--line);background:var(--bg);text-align:center;font-family:var(--font-mono);letter-spacing:.15em;text-transform:uppercase;color:var(--dim);padding:48px 32px 24px;font-size:11px}.report-footer--fixed{z-index:10;padding:16px 32px;position:fixed;bottom:0;left:0;right:0}.report-footer .brand-mark{color:var(--accent-pink);font-family:var(--font-mono);letter-spacing:-2px;margin-right:6px;font-size:14px;font-weight:700}.auth-dialog-backdrop{z-index:10000;-webkit-backdrop-filter:blur(6px);background:#08080ab3;place-items:center;padding:32px 16px;display:grid;position:fixed;inset:0}.auth-dialog{border:1px solid var(--line-2);background:var(--bg-2);width:100%;max-width:420px;font-family:var(--font-mono);color:var(--ink);padding:28px 28px 24px;position:relative}.auth-close{font-family:var(--font-mono);color:var(--dim);cursor:pointer;background:0 0;border:none;padding:4px 8px;font-size:20px;line-height:1;transition:color .12s;position:absolute;top:12px;right:14px}.auth-close:hover{color:var(--accent-pink)}.auth-close:disabled{color:var(--line-2);cursor:not-allowed}.auth-headline{font-family:var(--font-mono);letter-spacing:0;text-transform:none;color:var(--ink);margin:0 0 8px;font-size:18px;font-weight:600;line-height:1.3}.auth-sub{font-family:var(--font-mono);color:var(--ink-2);margin:0 0 18px;font-size:12px;line-height:1.55}.auth-sub .auth-email{color:var(--accent-pink)}.auth-sub .auth-ok{color:var(--accent-green);margin-right:6px}.auth-form{flex-direction:column;gap:10px;display:flex}.auth-field-label{font-family:var(--font-mono);letter-spacing:.22em;text-transform:uppercase;color:var(--accent-green);font-size:10px}.auth-input{background:var(--bg);border:1px solid var(--line-2);width:100%;color:var(--ink);font-family:var(--font-mono);letter-spacing:.03em;outline:none;padding:11px 14px;font-size:14px;transition:border-color .12s,box-shadow .12s}.auth-input:focus{border-color:var(--accent-pink);box-shadow:0 0 0 1px var(--accent-pink-soft)}.auth-input:disabled{opacity:.55;cursor:not-allowed}.auth-input-code{letter-spacing:.5em;text-align:center;font-variant-numeric:tabular-nums;font-size:18px}.auth-input::placeholder{color:var(--dim)}.auth-error{font-family:var(--font-mono);color:var(--accent-pink);background:var(--accent-pink-bg);border:1px solid var(--accent-pink);letter-spacing:.02em;border-left-width:3px;margin-top:4px;padding:8px 12px;font-size:12px}.auth-actions{flex-wrap:wrap;gap:10px;margin-top:14px;display:flex}.auth-btn{font-family:var(--font-mono);letter-spacing:.06em;border:1px solid var(--line-2);color:var(--ink);cursor:pointer;background:0 0;align-items:center;gap:8px;padding:10px 16px;font-size:12px;transition:all .12s;display:inline-flex}.auth-btn:hover:not(:disabled){border-color:var(--ink);background:#ffffff0a}.auth-btn:disabled{opacity:.45;cursor:not-allowed}.auth-btn.primary{border-color:var(--accent-pink);color:var(--accent-pink);background:var(--accent-pink-bg)}.auth-btn.primary:hover:not(:disabled){background:var(--accent-pink);color:var(--bg)}.auth-back{font-family:var(--font-mono);letter-spacing:.1em;color:var(--dim);cursor:pointer;background:0 0;border:none;align-self:flex-start;margin-top:4px;padding:6px 0;font-size:11px;transition:color .12s}.auth-back:hover:not(:disabled){color:var(--ink-2)}.auth-back:disabled{opacity:.45;cursor:not-allowed}@media (max-width:520px){.auth-dialog{padding:26px 22px 22px}.auth-actions{flex-direction:column;align-items:stretch}.auth-btn{justify-content:center}}.auth-status-pill{border:1px dashed var(--line-2);font-family:var(--font-mono);letter-spacing:.1em;color:var(--ink-2);align-items:center;gap:8px;margin-top:16px;padding:6px 10px;font-size:11px;display:inline-flex}.auth-status-pill .dot{background:var(--accent-green);width:7px;height:7px;display:inline-block;box-shadow:0 0 6px #66d1b58c}.auth-status-pill .email{color:var(--accent-green)}@media (max-width:960px){.report{padding:0 20px}.archetype-frame{padding:32px 24px}.arch-body{grid-template-columns:1fr;gap:32px}.arch-meta-grid,.score-grid{grid-template-columns:1fr;gap:16px}.finding-body{grid-template-columns:1fr}.finding-block{border-right:none!important}.policies-grid,.share-grid{grid-template-columns:1fr}.strength-row{grid-template-columns:40px 1fr}.strength-metric{text-align:left;grid-column:2;margin-top:6px}.return-hook{padding:28px 24px}}@media (prefers-reduced-motion:reduce){.running-cursor,.running-stage-spin,.running-bar-fill:after,.auth-status-pill .dot{animation:none}.running-bar-fill{transition:none}}.audit-progress-strip{z-index:60;background:var(--bg-2);border-bottom:1px solid var(--accent-pink);font-family:var(--font-mono);animation:.22s cubic-bezier(.22,1,.36,1) audit-progress-slide-in;position:sticky;top:0;left:0;right:0}.audit-progress-strip--failed{border-bottom-color:var(--accent-pink);background:linear-gradient(to right, var(--accent-pink-bg), var(--bg-2))}.audit-progress-strip__inner{justify-content:space-between;align-items:center;gap:16px;max-width:1480px;margin:0 auto;padding:12px clamp(20px,3vw,48px);display:flex;position:relative}.audit-progress-strip__label{color:var(--ink);letter-spacing:.06em;text-transform:lowercase;align-items:center;gap:10px;font-size:12px;display:inline-flex}.audit-progress-strip--failed .audit-progress-strip__label{color:var(--accent-pink)}.audit-progress-strip__elapsed{font-variant-numeric:tabular-nums;color:var(--accent-pink);letter-spacing:.08em;font-size:12px}.audit-progress-strip__spinner{border:1.5px solid var(--accent-pink);background:0 0;border-top-color:#0000;border-radius:50%;width:9px;height:9px;animation:.8s linear infinite audit-progress-spin}.audit-progress-strip__x{border:1px solid var(--accent-pink);width:14px;height:14px;color:var(--accent-pink);justify-content:center;align-items:center;font-size:11px;line-height:1;display:inline-flex}.audit-progress-strip__dismiss{border:1px solid var(--line-2);color:var(--ink-2);font-family:var(--font-mono);text-transform:lowercase;letter-spacing:.06em;cursor:pointer;background:0 0;padding:5px 10px;font-size:11px;transition:border-color .14s,color .14s}.audit-progress-strip__dismiss:hover{border-color:var(--accent-pink);color:var(--accent-pink)}.audit-progress-strip__pulse{background:linear-gradient(90deg, transparent 0%, var(--accent-pink) 20%, var(--accent-pink) 80%, transparent 100%);transform-origin:0;height:1px;animation:2.4s cubic-bezier(.55,.1,.45,.9) infinite audit-progress-pulse;position:absolute;bottom:-1px;left:0;right:0}@keyframes audit-progress-spin{to{transform:rotate(360deg)}}@keyframes audit-progress-pulse{0%{opacity:.4;transform:scaleX(0)translate(0%)}50%{opacity:1;transform:scaleX(.6)translate(20%)}to{opacity:.2;transform:scaleX(0)translate(100%)}}@keyframes audit-progress-slide-in{0%{opacity:0;transform:translateY(-100%)}to{opacity:1;transform:translateY(0)}}@media (prefers-reduced-motion:reduce){.audit-progress-strip{animation:none}.audit-progress-strip__spinner{border-top-color:var(--accent-pink);animation:none}.audit-progress-strip__pulse{opacity:.4;animation:none;transform:scaleX(.4)translate(30%)}}.poster-section{border-bottom:1px solid var(--line);flex-direction:column;gap:14px;height:calc(100vh - 52px);padding:20px 0 16px;display:flex}.poster{border:1px dashed var(--accent-pink-soft);background:var(--bg-2);flex-direction:column;flex:auto;width:100%;max-width:980px;min-height:0;margin:0 auto;padding:22px 40px;display:flex;position:relative;overflow:hidden}.poster-head{flex:none}.poster-body{flex:auto}.poster-foot{flex:none}.poster-head{border-bottom:1px dashed var(--line);font-family:var(--font-mono);letter-spacing:.04em;flex-wrap:wrap;justify-content:space-between;align-items:baseline;gap:18px;padding-bottom:12px;font-size:14px;display:flex}.poster-wordmark{color:var(--ink);align-items:center;gap:8px;display:inline-flex}.poster-wordmark .poster-logo{width:auto;height:18px;display:block}.poster-wordmark .poster-sep{color:var(--dim);margin:0 2px}.poster-meta{color:var(--dim)}.poster-meta .poster-ix{color:var(--accent-pink)}.poster-meta .of,.poster-meta .poster-sep{color:var(--dim)}.poster-body{text-align:center;flex-direction:column;justify-content:center;align-items:center;gap:clamp(14px,2.6vh,30px);min-height:0;padding:clamp(6px,1.4vh,16px) 0;display:flex}.poster-sigil .sigil{background:var(--bg);border:1px solid var(--line-2);grid-template-rows:repeat(8,clamp(10px,1.7vh,16px));grid-template-columns:repeat(8,clamp(10px,1.7vh,16px));gap:2px;padding:clamp(6px,1vh,10px);display:grid}.poster-persona{flex-direction:column;align-items:center;gap:clamp(6px,1.2vh,14px);min-width:0;display:flex}.poster-persona .persona-name{font-family:var(--font-display);letter-spacing:.03em;color:var(--ink);text-transform:lowercase;text-wrap:balance;margin:0;font-size:clamp(32px,6.5vh,64px);line-height:.95}.poster-persona .persona-keywords{font-family:var(--font-display);letter-spacing:.06em;text-transform:lowercase;font-size:clamp(16px,2.2vh,22px)}.poster-persona .persona-keywords .kw-0{color:var(--accent-green)}.poster-persona .persona-keywords .kw-1{color:var(--ink)}.poster-persona .persona-keywords .kw-2{color:var(--accent-pink)}.poster-persona .persona-keywords .kw-sep{color:var(--dim);margin:0 10px}.poster-persona .persona-rarity{font-family:var(--font-mono);color:var(--accent-green);letter-spacing:.02em;font-size:clamp(11px,1.3vh,13px)}.poster-persona .persona-rarity .lbl{color:var(--dim)}.poster-persona .persona-rarity .pct{color:var(--accent-pink);font-weight:600}.poster-score{justify-content:center;align-items:baseline;gap:clamp(10px,1.4vh,16px);display:flex}.poster-score .score-n{font-family:var(--font-mono);letter-spacing:-.02em;color:var(--accent-pink);font-variant-numeric:tabular-nums;font-size:clamp(56px,11vh,112px);font-weight:700;line-height:1}.poster-score .score-of{font-family:var(--font-mono);color:var(--dim);letter-spacing:.04em;font-size:clamp(16px,2vh,22px);line-height:1}.poster-sigil .sigil .px{background:0 0}.poster-sigil .sigil .px.on{background:var(--ink)}.poster-sigil .sigil .px.p{background:var(--accent-pink)}.poster-sigil .sigil .px.g{background:var(--accent-green)}.poster-sigil .sigil .px.d{background:var(--dim)}.poster-foot{border-top:1px dashed var(--line);font-family:var(--font-mono);justify-content:space-between;align-items:baseline;padding-top:10px;font-size:14px;display:flex}.poster-brand{color:var(--ink);letter-spacing:.04em;text-shadow:0 0 6px #ffffff80,0 0 14px #ffffff38}.poster-cta{color:var(--accent-green);letter-spacing:.04em}.poster-cta .arrow{color:var(--accent-pink);margin:0 4px}.poster-cta .cta-cmd{text-shadow:0 0 6px #66d1b599,0 0 14px #66d1b54d}.poster-share-row{flex:none;grid-template-columns:repeat(3,1fr);gap:10px;max-width:980px;margin:0 auto;display:grid}.poster-share-btn{border:1px solid var(--line-2);background:var(--bg-2);color:var(--ink);font-family:var(--font-mono);letter-spacing:.04em;cursor:pointer;justify-content:center;align-items:center;gap:10px;padding:12px 16px;font-size:12px;transition:border-color .14s,color .14s,background .14s;display:inline-flex}.poster-share-btn:hover{border-color:var(--accent-pink);color:var(--accent-pink);background:var(--accent-pink-bg)}.poster-share-btn:disabled{opacity:.55;cursor:wait}.poster-share-btn:focus-visible,.cadence-btn:focus-visible,.invite-btn:focus-visible,.install-all-btn:focus-visible,.copy-icon-btn:focus-visible,.fix-install-btn:focus-visible{outline:2px solid var(--accent-pink);outline-offset:2px}.poster-share-btn .mark{color:var(--accent-pink);font-weight:700}.poster-scroll-hint{text-align:center;font-family:var(--font-mono);letter-spacing:.22em;text-transform:uppercase;color:var(--dim);flex:none;margin:0;font-size:10px}.poster-scroll-hint .arrow{color:var(--accent-pink);margin-left:6px}@media (max-width:720px){.poster{padding:24px 22px}.poster-body{gap:28px;padding:12px 0}.poster-share-row{grid-template-columns:1fr}.poster-head{font-size:12px}.poster-score .score-n{font-size:clamp(72px,18vw,120px)}.poster-persona .persona-name{font-size:clamp(36px,9vw,56px)}}.audit-sec{border-bottom:1px solid var(--line);padding:48px 0}.audit-sec:last-child{border-bottom:none}.audit-sec-head{justify-content:space-between;align-items:baseline;gap:16px;margin-bottom:6px;display:flex}.audit-sec-eyebrow{font-family:var(--font-mono);letter-spacing:.2em;text-transform:uppercase;color:var(--accent-green);font-size:11px}.audit-sec-eyebrow .ix{color:var(--dim);margin-right:8px}.audit-sec-meta{font-family:var(--font-mono);color:var(--dim);letter-spacing:.04em;font-size:11px}.audit-sec-meta strong{color:var(--ink);font-weight:600}.audit-sec-title{font-family:var(--font-mono);letter-spacing:-.01em;color:var(--ink);margin:4px 0 18px;font-size:18px;font-weight:600}.strength-list{flex-direction:column;display:flex}.strength-row{border-bottom:1px dashed var(--line);font-family:var(--font-mono);grid-template-columns:24px 1fr auto;align-items:baseline;gap:14px;padding:12px 0;display:grid}.strength-row:last-child{border-bottom:none}.strength-check{color:var(--accent-green);font-size:14px;line-height:1}.strength-body{flex-direction:column;gap:2px;min-width:0;display:flex}.strength-headline{color:var(--ink);letter-spacing:.02em;font-size:13px}.strength-detail{color:var(--ink-2);letter-spacing:.02em;font-size:11px}.strength-metric{font-family:var(--font-display);letter-spacing:.04em;color:var(--accent-green);text-align:right;white-space:nowrap;font-size:22px;line-height:1}.strength-metric .unit{font-family:var(--font-mono);letter-spacing:.18em;text-transform:uppercase;color:var(--dim);margin-top:4px;font-size:9px;display:block}.quirks-table{font-family:var(--font-mono)}.quirks-thead,.quirks-row{grid-template-columns:80px 1fr 90px 100px;align-items:center;gap:14px;display:grid}.quirks-thead{border-bottom:1px solid var(--line);color:var(--dim);letter-spacing:.18em;text-transform:uppercase;padding:0 0 8px;font-size:10px}.quirks-thead span:last-child{text-align:right}.quirks-row{border-bottom:1px dashed var(--line);padding:12px 0;font-size:12px}.quirks-row:last-child{border-bottom:none}.q-when{color:var(--dim);font-size:11px}.q-what{flex-direction:column;gap:2px;min-width:0;display:flex}.q-title{color:var(--ink);font-size:12px}.q-policy{color:var(--dim);font-size:10px}.q-policy code{color:var(--accent-green);background:0 0}.q-pill{border:1px solid var(--line-2);text-align:center;letter-spacing:.12em;text-transform:uppercase;justify-self:start;padding:2px 8px;font-size:10px}.q-pill-high{color:var(--accent-pink);background:#e4587c0f;border-color:#e4587c66}.q-pill-medium{color:var(--amber);background:var(--amber-bg);border-color:#e8c46a66}.q-pill-low{color:var(--ink-2)}.q-recur{text-align:right;color:var(--dim);letter-spacing:.04em;font-size:10px}.audit-sec-sub{font-family:var(--font-mono);color:var(--ink-2);margin:-10px 0 18px;font-size:12px;line-height:1.55}.audit-sec-sub strong{color:var(--ink);font-weight:600}.install-all-btn{border:1px solid var(--accent-pink);background:var(--accent-pink-bg);color:var(--accent-pink);font-family:var(--font-mono);letter-spacing:.18em;text-transform:uppercase;cursor:pointer;padding:8px 14px;font-size:11px;transition:background-color .14s}.install-all-btn:hover{background:#e4587c2e}.fix-list{flex-direction:column;display:flex}.fix-row{border-bottom:1px dashed var(--line);grid-template-columns:1fr minmax(280px,auto);align-items:center;gap:24px;padding:14px 0;display:grid}.fix-row:last-child{border-bottom:none}.fix-row-info{flex-direction:column;gap:4px;min-width:0;display:flex}.fix-name{font-family:var(--font-mono);color:var(--ink);letter-spacing:.01em;font-size:13px;font-weight:500}.fix-desc{font-family:var(--font-mono);color:var(--ink-2);font-size:11px;line-height:1.55}.fix-row-cmd{align-items:stretch;gap:6px;min-width:0;display:flex}.fix-cmd-code{min-width:0;font-family:var(--font-mono);color:var(--accent-green);background:var(--bg);border:1px solid var(--line);letter-spacing:.02em;white-space:nowrap;flex:1;align-items:center;padding:8px 12px;font-size:11px;display:flex;overflow-x:auto}.copy-icon-btn{border:1px solid var(--line);background:var(--bg);color:var(--ink-2);font-family:var(--font-mono);cursor:pointer;justify-content:center;align-items:center;min-width:36px;padding:0 10px;font-size:12px;transition:color .14s,border-color .14s;display:inline-flex}.copy-icon-btn:hover{color:var(--accent-pink);border-color:var(--accent-pink)}.cbb-grid{grid-template-columns:1fr 1fr;gap:14px;display:grid}.cbb-card{border:1px solid var(--line-2);background:var(--bg-2);flex-direction:column;gap:12px;padding:18px 20px;display:flex}.cbb-card-title{font-family:var(--font-mono);color:var(--ink);letter-spacing:.02em;font-size:14px}.cbb-card-sub{font-family:var(--font-mono);color:var(--ink-2);font-size:11px;line-height:1.55}.cadence-row{flex-wrap:wrap;gap:8px;margin-top:2px;display:flex}.cadence-btn{font-family:var(--font-mono);letter-spacing:.04em;border:1px solid var(--line-2);color:var(--ink);cursor:pointer;background:0 0;padding:6px 12px;font-size:11px;transition:border-color .14s,color .14s,background-color .14s}.cadence-btn:hover{border-color:var(--accent-pink);color:var(--accent-pink)}.cadence-btn.on{border-color:var(--accent-pink);background:var(--accent-pink-bg);color:var(--accent-pink)}.cadence-btn:disabled{opacity:.5;cursor:not-allowed}.cbb-link{color:var(--accent-green);font-family:var(--font-mono);letter-spacing:.04em;cursor:pointer;background:0 0;border:none;align-self:flex-start;padding:0;font-size:11px}.cbb-link:hover{color:var(--accent-pink)}.cbb-link:disabled{opacity:.55;cursor:wait}.perks-progress{background:var(--bg);border:1px solid var(--line-2);height:6px;margin:4px 0;position:relative}.perks-progress span{background:var(--accent-pink);height:100%;transition:width .24s;display:block}.perks-meta{font-family:var(--font-mono);color:var(--ink-2);font-size:11px}.perks-meta strong{color:var(--accent-pink);font-weight:600}.invite-btn{border:1px solid var(--accent-pink);background:var(--accent-pink-bg);color:var(--accent-pink);font-family:var(--font-mono);letter-spacing:.18em;text-transform:uppercase;cursor:pointer;align-self:flex-start;padding:8px 14px;font-size:11px;transition:background-color .14s}.invite-btn:hover{background:#e4587c2e}.invite-textarea{resize:vertical;letter-spacing:.02em;width:100%;min-height:90px;font-size:13px;line-height:1.45}.invite-summary{font-family:var(--font-mono);color:var(--dim);flex-wrap:wrap;gap:12px;margin-top:6px;font-size:11px;display:flex}.invite-summary .invite-valid{color:var(--accent-green)}.invite-summary .invite-invalid{color:var(--accent-pink)}.cbb-foot{font-family:var(--font-mono);color:var(--dim);margin-top:4px;font-size:10px}@media (max-width:720px){.cbb-grid{grid-template-columns:1fr}.fix-row{grid-template-columns:1fr;gap:8px}.fix-row-cmd{min-width:0}.quirks-thead,.quirks-row{grid-template-columns:1fr;gap:6px;padding:16px 0}.quirks-thead{display:none}}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,8734,89664,e=>{"use strict";var t=e.i(56420);let a=(0,t.default)("copy",[["rect",{width:"14",height:"14",x:"8",y:"8",rx:"2",ry:"2",key:"17jyea"}],["path",{d:"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2",key:"zix9uf"}]]);e.s(["Copy",0,a],8734);let r=(0,t.default)("check",[["path",{d:"M20 6 9 17l-5-5",key:"1gmf2c"}]]);e.s(["Check",0,r],89664)},84026,29407,16306,82954,e=>{"use strict";var t=e.i(56420);let a=(0,t.default)("shield-check",[["path",{d:"M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z",key:"oel41y"}],["path",{d:"m9 12 2 2 4-4",key:"dzmm74"}]]);e.s(["ShieldCheck",0,a],84026);let r=(0,t.default)("shield-x",[["path",{d:"M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z",key:"oel41y"}],["path",{d:"m14.5 9.5-5 5",key:"17q4r4"}],["path",{d:"m9.5 9.5 5 5",key:"18nt4w"}]]);e.s(["ShieldX",0,r],29407);let l=(0,t.default)("shield-alert",[["path",{d:"M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z",key:"oel41y"}],["path",{d:"M12 8v4",key:"1got3b"}],["path",{d:"M12 16h.01",key:"1drbdi"}]]);e.s(["ShieldAlert",0,l],16306);let s=(0,t.default)("shield",[["path",{d:"M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z",key:"oel41y"}]]);e.s(["Shield",0,s],82954)},66794,
|
|
1
|
+
(globalThis.TURBOPACK||(globalThis.TURBOPACK=[])).push(["object"==typeof document?document.currentScript:void 0,8734,89664,e=>{"use strict";var t=e.i(56420);let a=(0,t.default)("copy",[["rect",{width:"14",height:"14",x:"8",y:"8",rx:"2",ry:"2",key:"17jyea"}],["path",{d:"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2",key:"zix9uf"}]]);e.s(["Copy",0,a],8734);let r=(0,t.default)("check",[["path",{d:"M20 6 9 17l-5-5",key:"1gmf2c"}]]);e.s(["Check",0,r],89664)},84026,29407,16306,82954,e=>{"use strict";var t=e.i(56420);let a=(0,t.default)("shield-check",[["path",{d:"M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z",key:"oel41y"}],["path",{d:"m9 12 2 2 4-4",key:"dzmm74"}]]);e.s(["ShieldCheck",0,a],84026);let r=(0,t.default)("shield-x",[["path",{d:"M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z",key:"oel41y"}],["path",{d:"m14.5 9.5-5 5",key:"17q4r4"}],["path",{d:"m9.5 9.5 5 5",key:"18nt4w"}]]);e.s(["ShieldX",0,r],29407);let l=(0,t.default)("shield-alert",[["path",{d:"M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z",key:"oel41y"}],["path",{d:"M12 8v4",key:"1got3b"}],["path",{d:"M12 16h.01",key:"1drbdi"}]]);e.s(["ShieldAlert",0,l],16306);let s=(0,t.default)("shield",[["path",{d:"M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z",key:"oel41y"}]]);e.s(["Shield",0,s],82954)},66794,80431,e=>{"use strict";let t=(0,e.i(56420).default)("settings",[["path",{d:"M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915",key:"1i5ecw"}],["circle",{cx:"12",cy:"12",r:"3",key:"1v7zrd"}]]);e.s(["Settings",0,t],66794);var a=e.i(95187);let r=(0,a.createServerReference)("60eae94ef10c13087319d3480f89e7ea4be834c6a7",a.callServer,void 0,a.findSourceMapURL,"searchHookActivityAction");e.s(["searchHookActivityAction",0,r],80431)},34713,e=>{"use strict";e.s(["formatDuration",0,function(e){if(e<1e3)return`${e}ms`;let t=e/1e3;if(t<60)return`${t.toFixed(1)}s`;let a=Math.floor(t/60);if(a>=60){let e=Math.floor(a/60);return`${e}h ${a%60}m`}let r=(t%60).toFixed(0);return`${a}m ${r}s`},"formatRelativeTime",0,function(e){let t=Date.now()-e;return t<6e4?`${Math.max(1,Math.floor(t/1e3))}s ago`:t<36e5?`${Math.floor(t/6e4)}m ago`:t<864e5?`${Math.floor(t/36e5)}h ago`:`${Math.floor(t/864e5)}d ago`}])},24071,e=>{"use strict";let t=(0,e.i(56420).default)("chevron-left",[["path",{d:"m15 18-6-6 6-6",key:"1wnfg3"}]]);e.s(["ChevronLeft",0,t],24071)},67927,e=>{"use strict";let t=(0,e.i(56420).default)("chevron-right",[["path",{d:"m9 18 6-6-6-6",key:"mthhwq"}]]);e.s(["ChevronRight",0,t],67927)},73520,e=>{"use strict";var t=e.i(43476),a=e.i(24071),r=e.i(67927);e.s(["default",0,function({currentPage:e,totalPages:l,onPageChange:s}){if(l<=1)return null;let i=e=>`px-3 py-2 text-sm rounded-md transition-colors flex items-center gap-1 bg-muted text-muted-foreground ${e?"opacity-50 cursor-not-allowed":"hover:bg-muted/80"}`;return(0,t.jsxs)("div",{className:"flex items-center justify-center gap-2 py-4",children:[(0,t.jsxs)("button",{onClick:()=>s(e-1),disabled:1===e,className:i(1===e),"aria-label":"Previous page",children:[(0,t.jsx)(a.ChevronLeft,{className:"w-4 h-4"}),(0,t.jsx)("span",{className:"hidden sm:inline",children:"Previous"})]}),(0,t.jsx)("div",{className:"flex items-center gap-1",children:(()=>{if(l<=7)return Array.from({length:l},(e,t)=>t+1);let t=[1],a=Math.max(2,e-1),r=Math.min(l-1,e+1);e<=3&&(r=Math.min(5,l-1)),e>=l-2&&(a=Math.max(2,l-4)),a>2&&t.push("ellipsis-start");for(let e=a;e<=r;e++)t.push(e);return r<l-1&&t.push("ellipsis-end"),t.push(l),t})().map(a=>"string"==typeof a?(0,t.jsx)("span",{className:"px-2 text-muted-foreground",children:"..."},a):(0,t.jsx)("button",{onClick:()=>s(a),className:`min-w-[2.5rem] px-3 py-2 text-sm rounded-md transition-colors ${e===a?"bg-primary text-primary-foreground":"bg-muted text-muted-foreground hover:bg-muted/80"}`,"aria-label":`Page ${a}`,"aria-current":e===a?"page":void 0,children:a},a))}),(0,t.jsxs)("button",{onClick:()=>s(e+1),disabled:e===l,className:i(e===l),"aria-label":"Next page",children:[(0,t.jsx)("span",{className:"hidden sm:inline",children:"Next"}),(0,t.jsx)(r.ChevronRight,{className:"w-4 h-4"})]})]})}])},80060,2711,e=>{"use strict";var t=e.i(18566),a=e.i(71645);function r(e){let t=e.getFullYear(),a=String(e.getMonth()+1).padStart(2,"0"),r=String(e.getDate()).padStart(2,"0");return`${t}-${a}-${r}`}function l(e){var t;if(!e||(t=e,!/^\d{4}-\d{2}-\d{2}$/.test(t)||isNaN(Date.parse(t))))return null;let[a,r,l]=e.split("-").map(Number);return new Date(a,r-1,l,12,0,0)}e.s(["useUrlParams",0,function(){let e=(0,t.useSearchParams)(),r=(0,t.useRouter)(),l=(0,t.usePathname)(),s=(0,a.useRef)(null),i=(0,a.useCallback)(t=>e.get(t),[e]),o=(0,a.useCallback)(()=>new URLSearchParams(e.toString()),[e]),n=(0,a.useCallback)(t=>{s.current&&clearTimeout(s.current),s.current=setTimeout(()=>{let a=new URLSearchParams(e.toString());for(let[e,r]of Object.entries(t))void 0===r||""===r?a.delete(e):a.set(e,r);let s=a.toString(),i=s?`${l}?${s}`:l;r.replace(i,{scroll:!1})},150)},[e,l,r]);return(0,a.useEffect)(()=>()=>{s.current&&clearTimeout(s.current)},[]),{get:i,getAll:o,setAll:n}}],80060),e.s(["dateRangeToParams",0,function(e){let t={};return e.from&&(t.from=r(e.from)),e.to&&(t.to=r(e.to)),t},"keywordsToParam",0,function(e){if(0!==e.length)return e.map(e=>encodeURIComponent(e)).join(",")},"pageToParam",0,function(e){return e<=1?void 0:String(e)},"paramToKeywords",0,function(e){return e?e.split(",").map(e=>decodeURIComponent(e.trim())).filter(e=>e.length>0):[]},"paramToPage",0,function(e){if(!e)return 1;let t=parseInt(e,10);return Number.isFinite(t)&&t>=1?t:1},"paramToPreset",0,function(e){return e&&["all","last-hour","today","last-7-days","last-30-days","custom"].includes(e)?e:"all"},"paramsToDateRange",0,function(e,t){return{from:l(e),to:l(t)}},"presetToParam",0,function(e){return"all"===e?void 0:e}],2711)},24578,e=>{"use strict";let t={claude:{id:"claude",label:"Claude Code",badgeClasses:"bg-orange-500/10 text-orange-400 border-orange-500/20"},codex:{id:"codex",label:"OpenAI Codex",badgeClasses:"bg-purple-500/10 text-purple-400 border-purple-500/20"},copilot:{id:"copilot",label:"GitHub Copilot",badgeClasses:"bg-blue-500/10 text-blue-400 border-blue-500/20"},cursor:{id:"cursor",label:"Cursor Agent",badgeClasses:"bg-emerald-500/10 text-emerald-400 border-emerald-500/20"},opencode:{id:"opencode",label:"OpenCode",badgeClasses:"bg-amber-500/10 text-amber-400 border-amber-500/20"},pi:{id:"pi",label:"Pi",badgeClasses:"bg-pink-500/10 text-pink-400 border-pink-500/20"},gemini:{id:"gemini",label:"Gemini CLI",badgeClasses:"bg-sky-500/10 text-sky-400 border-sky-500/20"}};e.s(["KNOWN_CLI_IDS",0,["claude","codex","copilot","cursor","opencode","pi","gemini"],"getCliBadgeClasses",0,function(e){return t[e]?.badgeClasses??t.claude.badgeClasses},"getCliLabel",0,function(e){return t[e]?.label??e},"isKnownCli",0,function(e){return"string"==typeof e&&Object.prototype.hasOwnProperty.call(t,e)}])},63676,e=>{"use strict";let t=(0,e.i(56420).default)("x",[["path",{d:"M18 6 6 18",key:"1bl5f8"}],["path",{d:"m6 6 12 12",key:"d8bk6v"}]]);e.s(["X",0,t],63676)}]);
|
|
@@ -28,6 +28,7 @@ const EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
|
28
28
|
|
|
29
29
|
interface InviteBody {
|
|
30
30
|
to?: unknown;
|
|
31
|
+
score?: unknown;
|
|
31
32
|
}
|
|
32
33
|
|
|
33
34
|
export async function POST(req: NextRequest): Promise<NextResponse> {
|
|
@@ -132,8 +133,16 @@ export async function POST(req: NextRequest): Promise<NextResponse> {
|
|
|
132
133
|
);
|
|
133
134
|
}
|
|
134
135
|
|
|
136
|
+
// Optional sender audit score (0–100), surfaced in the invite body. Coerce
|
|
137
|
+
// defensively — the value is client-supplied: ignore non-finite garbage,
|
|
138
|
+
// round, then clamp into range before forwarding upstream.
|
|
139
|
+
let score: number | undefined;
|
|
140
|
+
if (typeof body.score === "number" && Number.isFinite(body.score)) {
|
|
141
|
+
score = Math.max(0, Math.min(100, Math.round(body.score)));
|
|
142
|
+
}
|
|
143
|
+
|
|
135
144
|
try {
|
|
136
|
-
const result = await sendInvites(who.auth.access_token, normalised);
|
|
145
|
+
const result = await sendInvites(who.auth.access_token, normalised, score);
|
|
137
146
|
trackEvent("audit_invite_sent", {
|
|
138
147
|
status: "success",
|
|
139
148
|
source: "dashboard",
|
|
@@ -17,6 +17,7 @@ import { writeDashboardCache } from "@/src/audit/dashboard-cache";
|
|
|
17
17
|
import { INTEGRATION_TYPES, type IntegrationType } from "@/src/hooks/types";
|
|
18
18
|
import type { RunAuditOptions } from "@/src/audit/types";
|
|
19
19
|
import { finishRun, tryAcquireRun } from "../_state";
|
|
20
|
+
import { initTelemetry, trackEvent } from "@/lib/telemetry";
|
|
20
21
|
|
|
21
22
|
export const dynamic = "force-dynamic";
|
|
22
23
|
|
|
@@ -52,6 +53,11 @@ function sanitize(body: RunBody): RunAuditOptions {
|
|
|
52
53
|
}
|
|
53
54
|
|
|
54
55
|
export async function POST(request: NextRequest): Promise<NextResponse> {
|
|
56
|
+
// initTelemetry never throws; init up front so every exit path (incl. the
|
|
57
|
+
// 400/409 rejections and the detached run task below) can report. The
|
|
58
|
+
// dashboard is a long-lived process, so trackEvent's background flush
|
|
59
|
+
// delivers even after this handler returns 202.
|
|
60
|
+
await initTelemetry();
|
|
55
61
|
let body: RunBody = {};
|
|
56
62
|
try {
|
|
57
63
|
const raw = await request.text();
|
|
@@ -60,6 +66,7 @@ export async function POST(request: NextRequest): Promise<NextResponse> {
|
|
|
60
66
|
// JSON.parse("null") returns null and JSON.parse("[]") returns an
|
|
61
67
|
// array — both pass the catch but break sanitize()'s field access.
|
|
62
68
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
69
|
+
trackEvent("audit_run_rejected", { source: "dashboard", reason: "non_object_body" });
|
|
63
70
|
return NextResponse.json(
|
|
64
71
|
{ error: "Request body must be a JSON object" },
|
|
65
72
|
{ status: 400 },
|
|
@@ -68,18 +75,31 @@ export async function POST(request: NextRequest): Promise<NextResponse> {
|
|
|
68
75
|
body = parsed as RunBody;
|
|
69
76
|
}
|
|
70
77
|
} catch {
|
|
78
|
+
trackEvent("audit_run_rejected", { source: "dashboard", reason: "invalid_json" });
|
|
71
79
|
return NextResponse.json({ error: "Invalid JSON body" }, { status: 400 });
|
|
72
80
|
}
|
|
73
81
|
|
|
74
82
|
const opts = sanitize(body);
|
|
75
83
|
|
|
76
84
|
if (!tryAcquireRun()) {
|
|
85
|
+
trackEvent("audit_run_rejected", { source: "dashboard", reason: "already_running" });
|
|
77
86
|
return NextResponse.json(
|
|
78
87
|
{ error: "Audit already running", status: "already-running" },
|
|
79
88
|
{ status: 409 },
|
|
80
89
|
);
|
|
81
90
|
}
|
|
82
91
|
|
|
92
|
+
// Mirror the CLI's cli_audit_* funnel for the dashboard path (which shares the
|
|
93
|
+
// same runAudit() core but previously emitted no server telemetry at all).
|
|
94
|
+
trackEvent("audit_run_started", {
|
|
95
|
+
source: "dashboard",
|
|
96
|
+
since: opts.since ?? null,
|
|
97
|
+
no_cache: opts.noCache === true,
|
|
98
|
+
cli_count: opts.clis?.length ?? 0,
|
|
99
|
+
project_count: opts.projects?.length ?? 0,
|
|
100
|
+
});
|
|
101
|
+
const startedAt = Date.now();
|
|
102
|
+
|
|
83
103
|
// Fire-and-forget: a cold, all-history scan can run far longer than any HTTP
|
|
84
104
|
// request should stay open — and longer than Node's `server.requestTimeout`
|
|
85
105
|
// on the standalone production server. Start runAudit() as a detached task in
|
|
@@ -93,8 +113,23 @@ export async function POST(request: NextRequest): Promise<NextResponse> {
|
|
|
93
113
|
// the client (the POST already returned 202), so a failed persist is a
|
|
94
114
|
// failed run from the user's view — surface it instead of reporting OK.
|
|
95
115
|
const persisted = writeDashboardCache(opts, result);
|
|
116
|
+
trackEvent("audit_run_completed", {
|
|
117
|
+
source: "dashboard",
|
|
118
|
+
duration_ms: Date.now() - startedAt,
|
|
119
|
+
events_scanned: result.eventsScanned,
|
|
120
|
+
sessions_scanned: result.transcripts.scanned,
|
|
121
|
+
projects_scanned: result.projectsScanned.length,
|
|
122
|
+
findings: result.results.length,
|
|
123
|
+
total_hits: result.totals.hits,
|
|
124
|
+
persisted,
|
|
125
|
+
});
|
|
96
126
|
finishRun(persisted ? null : "audit finished but its result could not be saved");
|
|
97
127
|
} catch (err) {
|
|
128
|
+
trackEvent("audit_run_failed", {
|
|
129
|
+
source: "dashboard",
|
|
130
|
+
duration_ms: Date.now() - startedAt,
|
|
131
|
+
error_type: err instanceof Error ? err.name : "unknown",
|
|
132
|
+
});
|
|
98
133
|
finishRun(err instanceof Error ? err.message : String(err));
|
|
99
134
|
}
|
|
100
135
|
})();
|
|
@@ -21,11 +21,11 @@ export async function POST(req: NextRequest): Promise<NextResponse> {
|
|
|
21
21
|
try {
|
|
22
22
|
body = (await req.json()) as RequestBody;
|
|
23
23
|
} catch {
|
|
24
|
-
trackEvent("audit_otp_requested", { status: "validation_error", reason: "invalid_json" });
|
|
24
|
+
trackEvent("audit_otp_requested", { status: "validation_error", source: "dashboard", reason: "invalid_json" });
|
|
25
25
|
return NextResponse.json({ code: "validation_error", message: "Invalid JSON body" }, { status: 400 });
|
|
26
26
|
}
|
|
27
27
|
if (typeof body.email !== "string" || !body.email.trim()) {
|
|
28
|
-
trackEvent("audit_otp_requested", { status: "validation_error", reason: "missing_email" });
|
|
28
|
+
trackEvent("audit_otp_requested", { status: "validation_error", source: "dashboard", reason: "missing_email" });
|
|
29
29
|
return NextResponse.json(
|
|
30
30
|
{ code: "validation_error", message: "email is required" },
|
|
31
31
|
{ status: 400 },
|
|
@@ -20,26 +20,32 @@ interface VerifyBody {
|
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
export async function POST(req: NextRequest): Promise<NextResponse> {
|
|
23
|
+
// `initTelemetry` never throws — its internal try/catch is total. Init up
|
|
24
|
+
// front so the validation-400 paths below are tracked too, mirroring
|
|
25
|
+
// /api/auth/login-request.
|
|
26
|
+
await initTelemetry();
|
|
23
27
|
let body: VerifyBody = {};
|
|
24
28
|
try {
|
|
25
29
|
body = (await req.json()) as VerifyBody;
|
|
26
30
|
} catch {
|
|
31
|
+
trackEvent("audit_otp_verified", { status: "validation_error", source: "dashboard", reason: "invalid_json" });
|
|
27
32
|
return NextResponse.json({ code: "validation_error", message: "Invalid JSON body" }, { status: 400 });
|
|
28
33
|
}
|
|
29
34
|
if (typeof body.email !== "string" || !body.email.trim()) {
|
|
35
|
+
trackEvent("audit_otp_verified", { status: "validation_error", source: "dashboard", reason: "missing_email" });
|
|
30
36
|
return NextResponse.json(
|
|
31
37
|
{ code: "validation_error", message: "email is required" },
|
|
32
38
|
{ status: 400 },
|
|
33
39
|
);
|
|
34
40
|
}
|
|
35
41
|
if (typeof body.code !== "string" || !body.code.trim()) {
|
|
42
|
+
trackEvent("audit_otp_verified", { status: "validation_error", source: "dashboard", reason: "missing_code", email: body.email.trim().toLowerCase() });
|
|
36
43
|
return NextResponse.json(
|
|
37
44
|
{ code: "validation_error", message: "code is required" },
|
|
38
45
|
{ status: 400 },
|
|
39
46
|
);
|
|
40
47
|
}
|
|
41
|
-
|
|
42
|
-
await initTelemetry();
|
|
48
|
+
const email = body.email.trim().toLowerCase();
|
|
43
49
|
try {
|
|
44
50
|
const tokens = await verifyLoginCode(body.email, body.code);
|
|
45
51
|
writeAuth(authFromTokenResponse(tokens));
|
|
@@ -72,6 +78,7 @@ export async function POST(req: NextRequest): Promise<NextResponse> {
|
|
|
72
78
|
trackEvent("audit_otp_verified", {
|
|
73
79
|
status: "failed",
|
|
74
80
|
source: "dashboard",
|
|
81
|
+
email,
|
|
75
82
|
error_code: err.code,
|
|
76
83
|
http_status: err.status,
|
|
77
84
|
});
|
|
@@ -87,6 +94,7 @@ export async function POST(req: NextRequest): Promise<NextResponse> {
|
|
|
87
94
|
trackEvent("audit_otp_verified", {
|
|
88
95
|
status: "failed",
|
|
89
96
|
source: "dashboard",
|
|
97
|
+
email,
|
|
90
98
|
error_code: "upstream_unreachable",
|
|
91
99
|
error_message: message.slice(0, 200),
|
|
92
100
|
});
|
|
@@ -104,7 +104,8 @@ export function AuditDashboard({ initial, projectFromUrl, totalCatalogSize }: Pr
|
|
|
104
104
|
if (running) return;
|
|
105
105
|
capture("audit_rerun_clicked", { source, since: "all" });
|
|
106
106
|
setRunning(true);
|
|
107
|
-
|
|
107
|
+
const startedAt = Date.now();
|
|
108
|
+
setRerunStatus({ kind: "running", startedAt });
|
|
108
109
|
try {
|
|
109
110
|
// noCache: an explicit re-audit bypasses the per-transcript cache and
|
|
110
111
|
// re-scans from scratch — never a silent no-op that returns the identical
|
|
@@ -114,6 +115,11 @@ export function AuditDashboard({ initial, projectFromUrl, totalCatalogSize }: Pr
|
|
|
114
115
|
// fast cached path — it's a first scan, not a re-audit.
|
|
115
116
|
await triggerRun({ cli: [], since: "all", noCache: true });
|
|
116
117
|
await refreshFromCache();
|
|
118
|
+
capture("audit_rerun_succeeded", {
|
|
119
|
+
source,
|
|
120
|
+
since: "all",
|
|
121
|
+
duration_ms: Date.now() - startedAt,
|
|
122
|
+
});
|
|
117
123
|
setRerunStatus({ kind: "idle" });
|
|
118
124
|
} catch (err) {
|
|
119
125
|
const kind = err instanceof RerunError ? err.kind : "network";
|
|
@@ -122,6 +128,7 @@ export function AuditDashboard({ initial, projectFromUrl, totalCatalogSize }: Pr
|
|
|
122
128
|
source,
|
|
123
129
|
since: "all",
|
|
124
130
|
cli_filter: "all",
|
|
131
|
+
duration_ms: Date.now() - startedAt,
|
|
125
132
|
});
|
|
126
133
|
setRerunStatus({ kind: "failed", reason: kind, failedAt: Date.now() });
|
|
127
134
|
} finally {
|
|
@@ -353,6 +360,7 @@ function MainReport({
|
|
|
353
360
|
<ComeBackBetterSection
|
|
354
361
|
isRunning={isRunning}
|
|
355
362
|
onRerun={() => onRerun("return_section")}
|
|
363
|
+
score={score}
|
|
356
364
|
/>
|
|
357
365
|
</div>
|
|
358
366
|
<ReportFooter cachedAt={cachedAt} />
|
|
@@ -24,18 +24,22 @@
|
|
|
24
24
|
import React, { forwardRef, useMemo, useState } from "react";
|
|
25
25
|
import { pickArchetypeVariant, type ArchetypeKey } from "@/src/audit/archetypes";
|
|
26
26
|
import { type Grade } from "@/src/audit/scoring";
|
|
27
|
-
import { getArchetypeRarityPct
|
|
27
|
+
import { getArchetypeRarityPct } from "@/src/audit/social-proof";
|
|
28
28
|
import { copyOrDownloadCard, downloadCard, shareCardNative, shareCardToastMessage } from "@/lib/share-card";
|
|
29
29
|
import { toast } from "@/app/components/toast";
|
|
30
30
|
import { usePostHog } from "@/contexts/PostHogContext";
|
|
31
31
|
import { Sigil } from "./sigil";
|
|
32
32
|
import { X_TEMPLATES, LI_TEMPLATES, pickTemplate, type ShareCtx } from "./share-templates";
|
|
33
33
|
|
|
34
|
-
const SITE_URL = "https://befailproof.ai";
|
|
35
34
|
const X_INTENT = (text: string) =>
|
|
36
35
|
`https://x.com/intent/tweet?text=${encodeURIComponent(text)}`;
|
|
36
|
+
// LinkedIn deprecated the share-offsite `summary` / `title` params, so they no
|
|
37
|
+
// longer pre-fill the post composer (it only scrapes OG tags from the URL). The
|
|
38
|
+
// feed route with `shareActive=true` + `text=` opens "start a post" with our
|
|
39
|
+
// text pre-filled — and the share templates already embed the befailproof.ai
|
|
40
|
+
// link inside that text.
|
|
37
41
|
const LI_INTENT = (text: string) =>
|
|
38
|
-
`https://www.linkedin.com/
|
|
42
|
+
`https://www.linkedin.com/feed/?shareActive=true&text=${encodeURIComponent(text)}`;
|
|
39
43
|
|
|
40
44
|
interface Props {
|
|
41
45
|
archetypeKey: ArchetypeKey;
|
|
@@ -60,7 +64,6 @@ export const AuditPoster = forwardRef<HTMLDivElement, Props>(function AuditPoste
|
|
|
60
64
|
[archetypeKey, seed],
|
|
61
65
|
);
|
|
62
66
|
const rarityPct = getArchetypeRarityPct(archetypeKey);
|
|
63
|
-
const scoreRank = getScoreRank(score);
|
|
64
67
|
const indexLabel = String(archetype.index).padStart(2, "0");
|
|
65
68
|
const auditedDate = useMemo(() => formatAuditedDate(auditedAt), [auditedAt]);
|
|
66
69
|
|
|
@@ -254,17 +257,18 @@ export const AuditPoster = forwardRef<HTMLDivElement, Props>(function AuditPoste
|
|
|
254
257
|
)}
|
|
255
258
|
</div>
|
|
256
259
|
|
|
257
|
-
{/* Score block — heroic number
|
|
260
|
+
{/* Score block — heroic number, centered in the card */}
|
|
258
261
|
<div className="poster-score">
|
|
259
262
|
<span className="score-n">{score}</span>
|
|
260
263
|
<span className="score-of">/100</span>
|
|
261
|
-
<span className="score-rank">{scoreRank}</span>
|
|
262
264
|
</div>
|
|
263
265
|
</div>
|
|
264
266
|
|
|
265
267
|
<footer className="poster-foot">
|
|
268
|
+
<span className="poster-brand">befailproof.ai</span>
|
|
266
269
|
<span className="poster-cta">
|
|
267
|
-
audit yours <span className="arrow">→</span>
|
|
270
|
+
audit yours <span className="arrow">→</span>{" "}
|
|
271
|
+
<span className="cta-cmd">npx -y failproofai audit</span>
|
|
268
272
|
</span>
|
|
269
273
|
</footer>
|
|
270
274
|
</div>
|
|
@@ -24,8 +24,11 @@ export interface AuthedUser {
|
|
|
24
24
|
|
|
25
25
|
interface Props {
|
|
26
26
|
open: boolean;
|
|
27
|
-
/** Optional title. Defaults to "
|
|
27
|
+
/** Optional title. Defaults to "where to route the reminder?". */
|
|
28
28
|
headline?: string;
|
|
29
|
+
/** Optional subtitle shown under the title on the email step. Defaults to
|
|
30
|
+
* "we'll send a one-time code to confirm." */
|
|
31
|
+
subhead?: string;
|
|
29
32
|
onClose: () => void;
|
|
30
33
|
/** Fired after successful verify. Caller decides what to do next. */
|
|
31
34
|
onAuthed: (user: AuthedUser) => void;
|
|
@@ -51,6 +54,7 @@ function describeFetchError(err: unknown): string {
|
|
|
51
54
|
export function AuthDialog({
|
|
52
55
|
open,
|
|
53
56
|
headline = "where to route the reminder?",
|
|
57
|
+
subhead = "we'll send a one-time code to confirm.",
|
|
54
58
|
onClose,
|
|
55
59
|
onAuthed,
|
|
56
60
|
source = "unknown",
|
|
@@ -270,9 +274,7 @@ export function AuthDialog({
|
|
|
270
274
|
|
|
271
275
|
{step.kind === "email" && (
|
|
272
276
|
<>
|
|
273
|
-
<p className="auth-sub">
|
|
274
|
-
we'll send a one-time code to confirm.
|
|
275
|
-
</p>
|
|
277
|
+
<p className="auth-sub">{subhead}</p>
|
|
276
278
|
<form onSubmit={onEmailSubmit} className="auth-form">
|
|
277
279
|
<input
|
|
278
280
|
ref={emailInputRef}
|
|
@@ -27,13 +27,23 @@ import { InviteDialog } from "./invite-dialog";
|
|
|
27
27
|
interface Props {
|
|
28
28
|
isRunning: boolean;
|
|
29
29
|
onRerun: () => void;
|
|
30
|
+
/** Current audit score (0–100), forwarded into the invite email body. */
|
|
31
|
+
score?: number;
|
|
30
32
|
}
|
|
31
33
|
|
|
32
34
|
const DEFAULT_REMINDER_DAYS = 7;
|
|
33
35
|
const REMINDER_OPTIONS = [3, 7, 14, 30] as const;
|
|
34
36
|
type Cadence = typeof REMINDER_OPTIONS[number];
|
|
35
37
|
|
|
36
|
-
const PERKS_PERK = "
|
|
38
|
+
const PERKS_PERK = "wanna know how your friends' agents score?";
|
|
39
|
+
|
|
40
|
+
// The AuthDialog is shared by the reminder and invite CTAs. The reminder path
|
|
41
|
+
// keeps the dialog's default copy; the invite path swaps in login-required
|
|
42
|
+
// copy. Content only — the auth flow is identical for both.
|
|
43
|
+
const INVITE_AUTH_COPY = {
|
|
44
|
+
headline: "Oops! Login required",
|
|
45
|
+
subhead: "What's your email?",
|
|
46
|
+
} as const;
|
|
37
47
|
|
|
38
48
|
type AuthStatus =
|
|
39
49
|
| { kind: "unknown" }
|
|
@@ -60,7 +70,7 @@ function formatNextAudit(unixSecs: number): string {
|
|
|
60
70
|
});
|
|
61
71
|
}
|
|
62
72
|
|
|
63
|
-
export function ComeBackBetterSection({ isRunning, onRerun }: Props) {
|
|
73
|
+
export function ComeBackBetterSection({ isRunning, onRerun, score }: Props) {
|
|
64
74
|
const { capture } = usePostHog();
|
|
65
75
|
const [authStatus, setAuthStatus] = useState<AuthStatus>({ kind: "unknown" });
|
|
66
76
|
const [reminder, setReminder] = useState<Reminder | null>(null);
|
|
@@ -68,6 +78,10 @@ export function ComeBackBetterSection({ isRunning, onRerun }: Props) {
|
|
|
68
78
|
const [dialogOpen, setDialogOpen] = useState(false);
|
|
69
79
|
const [inviteDialogOpen, setInviteDialogOpen] = useState(false);
|
|
70
80
|
const [reminderBusy, setReminderBusy] = useState(false);
|
|
81
|
+
// Copy for the shared AuthDialog: {} keeps the reminder defaults,
|
|
82
|
+
// INVITE_AUTH_COPY shows the invite variant. Set by whichever CTA opens the
|
|
83
|
+
// dialog — content selection only, no effect on the auth flow.
|
|
84
|
+
const [authCopy, setAuthCopy] = useState<{ headline?: string; subhead?: string }>({});
|
|
71
85
|
const ctaShownRef = useRef(false);
|
|
72
86
|
const lastRefreshAtRef = useRef(0);
|
|
73
87
|
|
|
@@ -196,6 +210,7 @@ export function ComeBackBetterSection({ isRunning, onRerun }: Props) {
|
|
|
196
210
|
return;
|
|
197
211
|
}
|
|
198
212
|
if (authStatus.kind === "anon") {
|
|
213
|
+
setAuthCopy({}); // reminder context → keep the dialog's default copy
|
|
199
214
|
setDialogOpen(true);
|
|
200
215
|
}
|
|
201
216
|
},
|
|
@@ -222,6 +237,7 @@ export function ComeBackBetterSection({ isRunning, onRerun }: Props) {
|
|
|
222
237
|
// Unauthed users go through the AuthDialog first so we have a sender
|
|
223
238
|
// identity to Cc on the invite email.
|
|
224
239
|
if (authStatus.kind !== "authed") {
|
|
240
|
+
setAuthCopy(INVITE_AUTH_COPY); // invite context → "Oops! Login required"
|
|
225
241
|
setDialogOpen(true);
|
|
226
242
|
return;
|
|
227
243
|
}
|
|
@@ -278,7 +294,7 @@ export function ComeBackBetterSection({ isRunning, onRerun }: Props) {
|
|
|
278
294
|
|
|
279
295
|
{/* Perks card */}
|
|
280
296
|
<div className="cbb-card">
|
|
281
|
-
<div className="cbb-card-title">
|
|
297
|
+
<div className="cbb-card-title">Share with friends</div>
|
|
282
298
|
<div className="cbb-card-sub">{PERKS_PERK}</div>
|
|
283
299
|
<button type="button" className="invite-btn" onClick={handleInvite}>
|
|
284
300
|
invite a friend
|
|
@@ -292,12 +308,14 @@ export function ComeBackBetterSection({ isRunning, onRerun }: Props) {
|
|
|
292
308
|
<InviteDialog
|
|
293
309
|
open={inviteDialogOpen}
|
|
294
310
|
source="come_back_better_section"
|
|
311
|
+
score={score}
|
|
295
312
|
onClose={() => setInviteDialogOpen(false)}
|
|
296
313
|
onUnauthorized={() => {
|
|
297
314
|
// Session expired between probe and submit — flip back to anon
|
|
298
315
|
// and bounce through the AuthDialog so the user re-auths.
|
|
299
316
|
setAuthStatus({ kind: "anon" });
|
|
300
317
|
setReminder(null);
|
|
318
|
+
setAuthCopy(INVITE_AUTH_COPY); // still the invite context
|
|
301
319
|
setDialogOpen(true);
|
|
302
320
|
}}
|
|
303
321
|
/>
|
|
@@ -305,6 +323,8 @@ export function ComeBackBetterSection({ isRunning, onRerun }: Props) {
|
|
|
305
323
|
<AuthDialog
|
|
306
324
|
open={dialogOpen}
|
|
307
325
|
source="return_section"
|
|
326
|
+
headline={authCopy.headline}
|
|
327
|
+
subhead={authCopy.subhead}
|
|
308
328
|
onClose={() => setDialogOpen(false)}
|
|
309
329
|
onAuthed={(u) => {
|
|
310
330
|
setDialogOpen(false);
|
|
@@ -24,6 +24,9 @@ interface Props {
|
|
|
24
24
|
* submit). The parent should re-open the AuthDialog so the user can
|
|
25
25
|
* re-authenticate; without this, a 401 dead-ends with an inline error. */
|
|
26
26
|
onUnauthorized?: () => void;
|
|
27
|
+
/** Sender's audit score (0–100), forwarded to the api-server so the invite
|
|
28
|
+
* body can show "mine came out at N/100". Omitted → score-free copy. */
|
|
29
|
+
score?: number;
|
|
27
30
|
}
|
|
28
31
|
|
|
29
32
|
const EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
@@ -46,7 +49,7 @@ function parseEmails(input: string): { valid: string[]; invalid: string[] } {
|
|
|
46
49
|
return { valid, invalid };
|
|
47
50
|
}
|
|
48
51
|
|
|
49
|
-
export function InviteDialog({ open, onClose, source, onUnauthorized }: Props): React.ReactElement | null {
|
|
52
|
+
export function InviteDialog({ open, onClose, source, onUnauthorized, score }: Props): React.ReactElement | null {
|
|
50
53
|
const { capture } = usePostHog();
|
|
51
54
|
const [value, setValue] = useState("");
|
|
52
55
|
const [busy, setBusy] = useState(false);
|
|
@@ -102,7 +105,7 @@ export function InviteDialog({ open, onClose, source, onUnauthorized }: Props):
|
|
|
102
105
|
const res = await fetch("/api/audit/invite", {
|
|
103
106
|
method: "POST",
|
|
104
107
|
headers: { "content-type": "application/json" },
|
|
105
|
-
body: JSON.stringify({ to: valid }),
|
|
108
|
+
body: JSON.stringify({ to: valid, score }),
|
|
106
109
|
});
|
|
107
110
|
const body = (await res.json().catch(() => ({}))) as {
|
|
108
111
|
sent?: string[];
|
|
@@ -141,7 +144,7 @@ export function InviteDialog({ open, onClose, source, onUnauthorized }: Props):
|
|
|
141
144
|
setBusy(false);
|
|
142
145
|
}
|
|
143
146
|
},
|
|
144
|
-
[busy, valid, invalid, capture, source, onClose, onUnauthorized],
|
|
147
|
+
[busy, valid, invalid, capture, source, onClose, onUnauthorized, score],
|
|
145
148
|
);
|
|
146
149
|
|
|
147
150
|
if (!open) return null;
|