PageSourceSearch

https://abtestly.com/signals

html abtestly.com collected 2026-10-02 01:21:06 UTC 90,060 bytes, 1,227 lines download raw bytes

1<!doctype html>
2<html lang="en">
3<head>
4  <meta charset="UTF-8" />
5  <link rel="icon" type="image/svg+xml" href="/assets/favicon.svg" />
6  <link rel="icon" type="image/png" sizes="48x48" href="/favicon-48.png" />
7  <link rel="icon" type="image/png" sizes="32x32" href="/favicon-32.png" />
8  <link rel="icon" type="image/png" sizes="16x16" href="/favicon-16.png" />
9  <link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
10  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
11  <meta name="theme-color" content="#f7f3ee" />
12
13  <title>Signals. An AI CRO audit that ranks a falsifiable backlog.</title>
14  <meta name="description" content="Signals reads your page and your GA4, then returns a ranked, evidence backed A/B test backlog. Every hypothesis is put through an adversarial pass." />
15  <link rel="canonical" href="https://abtestly.com/signals" />
16  <meta property="og:title" content="ABTestly Signals. From your URL to a ranked, falsifiable backlog." />
17  <meta property="og:description" content="An AI CRO audit for teams that test. It reads your page and your GA4, ranks a test backlog, and puts every idea through a pass that argues against it." />
18  <meta property="og:url" content="https://abtestly.com/signals" />
19  <meta property="og:type" content="website" />
20  <meta property="og:logo" content="https://abtestly.com/assets/favicon.svg" />
21  <meta name="twitter:card" content="summary_large_image" />
22  <meta property="og:image" content="https://abtestly.com/assets/og/index.png" />
23  <meta property="og:image:width" content="1200" />
24  <meta property="og:image:height" content="630" />
25  <meta name="twitter:image" content="https://abtestly.com/assets/og/index.png" />
26
27  <!-- Fonts. Same families as the app: Plex Sans + Plex Mono. -->
28  <link rel="preload" href="/assets/fonts/ibm-plex-sans-400.woff2" as="font" type="font/woff2" crossorigin />
29  <link rel="preload" href="/assets/fonts/ibm-plex-sans-500.woff2" as="font" type="font/woff2" crossorigin />
30
31  <!-- Theme with no flash. Runs before first paint. -->
32  
32<script>
33    (function () {
34      try {
35        var stored = localStorage.getItem('abtestly-theme');
36        var prefers = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
37        var theme = stored || 'light';
38        if (theme === 'dark') document.documentElement.setAttribute('data-theme', 'dark');
39        var meta = document.querySelector('meta[name="theme-color"]');
40        if (meta) meta.setAttribute('content', theme === 'dark' ? '#09101b' : '#f7f3ee');
41      } catch (e) {}
42    })();
43  </script>
43
44
45  <link rel="stylesheet" href="/consent.css" />
46  
46<script>
47    window.CONSENT_CONFIG = {
48      version: '1.0.0',
49      policyUrl: 'https://abtestly.com/privacy',
50      expiryDays: 180,
51      cookieDomain: location.hostname === 'localhost' ? undefined : '.abtestly.com',
52      scripts: {
53        analytics: [
54          // ABTestly self-experiment snippet — variant assignment + impression tracking.
55          { src: 'https://cdn.abtestly.com/s/1yi1kvrr1h.js' },
56          // The exposure bridge, which reports our own experiments to GA4.
57          // /ga4-init.js is deliberately NOT in this list any more: the Google
58          // tag loads from <head> on every page under Consent Mode v2 with
59          // denied defaults, so it stores nothing until a category is granted.
60          { src: '/gtm-bridge.js?v=9c1e3a69' },
61        ],
62        // The marketing category loads no script of its own. It drives the
63        // three Consent Mode ad signals in /ga4-init.js instead: the Google
64        // Ads tag is a consent STATE there, not a second snippet here.
65        marketing: [],
66      },
67    };
68  </script>
68
69  
69<script src="/ga4-init.js?v=1d6db3f3" defer></script>
69
70  
70<script src="/consent.js?v=99bdab09" defer></script>
70
71
72  
72<script type="application/ld+json">
73  {
74    "@context": "https://schema.org",
75    "@type": "BreadcrumbList",
76    "itemListElement": [
77      { "@type": "ListItem", "position": 1, "name": "Home", "item": "https://abtestly.com/" },
78      { "@type": "ListItem", "position": 2, "name": "Signals", "item": "https://abtestly.com/signals" }
79    ]
80  }
81  </script>
81
82
83  
83<script type="application/ld+json">
84{
85  "@context": "https://schema.org",
86  "@graph": [
87    {
88      "@type": "Organization",
89      "@id": "https://abtestly.com/#organization",
90      "name": "ABTestly",
91      "url": "https://abtestly.com/",
92      "logo": {
93        "@type": "ImageObject",
94        "url": "https://abtestly.com/assets/logo.svg"
95      }
96    },
97    {
98      "@type": "WebSite",
99      "@id": "https://abtestly.com/#website",
100      "name": "ABTestly",
101      "url": "https://abtestly.com/",
102      "publisher": {
103        "@id": "https://abtestly.com/#organization"
104      }
105    },
106    {
107      "@type": "SoftwareApplication",
108      "@id": "https://abtestly.com/signals#software",
109      "name": "ABTestly Signals",
110      "description": "Signals reads your page and your GA4, then returns a ranked, evidence backed A/B test backlog. Every hypothesis is put through an adversarial pass.",
111      "url": "https://abtestly.com/signals",
112      "applicationCategory": "BusinessApplication",
113      "operatingSystem": "Web",
114      "isPartOf": {
115        "@id": "https://abtestly.com/#website"
116      },
117      "publisher": {
118        "@id": "https://abtestly.com/#organization"
119      }
120    },
121    {
122      "@type": "WebPage",
123      "@id": "https://abtestly.com/signals",
124      "url": "https://abtestly.com/signals",
125      "name": "ABTestly Signals",
126      "isPartOf": {
127        "@id": "https://abtestly.com/#website"
128      },
129      "description": "Signals reads your page and your GA4 and returns a ranked, evidence backed A/B test backlog. Every idea is labeled with the evidence it rests on and goes through an adversarial pass. The argument arrives attached when the pass returns one.",
130      "dateModified": "2026-09-19"
131    }
132  ]
133}
134  </script>
134
135
136  <style>
137  /* ══════════════════════════════════════════════════════════════════
138     Signals page — section chrome.
139     These section styles (hero, differentiator spine, honesty floor,
140     learning-loop flywheel) are written against the site's own tokens
141     from src/style.css, so light and dark follow the page automatically.
142     The interactive pipeline below is token-aliased instead (see the
143     `.audit, .pmodal` block) and kept structurally verbatim.
144     ══════════════════════════════════════════════════════════════════ */
145
146  /* Scroll reveal — pure CSS progressive enhancement. Non-supporting or
147     reduced-motion visitors get the static, fully visible layout. */
148  @supports (animation-timeline: view()) {
149    @media (prefers-reduced-motion: no-preference) {
150      .sig-reveal { animation: sigReveal linear both; animation-timeline: view(); animation-range: entry 0% entry 52%; }
151    }
152  }
153  @keyframes sigReveal { from { opacity: 0; transform: translateY(16px); } to { opacity: 1; transform: none; } }
154
155  /* ── Hero ───────────────────────────────────────────────────────────── */
156  .sig-hero { position: relative; padding: clamp(64px, 9vw, 116px) 0 clamp(48px, 7vw, 88px); overflow: hidden; }
157  .sig-hero::before {
158    content: ''; position: absolute; inset: 0; pointer-events: none;
159    background: radial-gradient(52% 42% at 50% -12%, var(--accent-soft) 0%, transparent 70%); opacity: 0.7;
160  }
161  .sig-hero::after {
162    content: ''; position: absolute; inset: 0; z-index: 0; pointer-events: none;
163    background-image:
164      linear-gradient(to right, var(--hair) 1px, transparent 1px),
165      linear-gradient(to bottom, var(--hair) 1px, transparent 1px);
166    background-size: 56px 56px;
167    -webkit-mask-image: radial-gradient(115% 78% at 50% -6%, #000 26%, transparent 72%);
168    mask-image: radial-gradient(115% 78% at 50% -6%, #000 26%, transparent 72%);
169    opacity: 0.5;
170  }
171  .sig-hero .container { position: relative; z-index: 1; display: flex; flex-direction: column; align-items: center; text-align: center; }
172  .sig-hero .eyebrow { display: inline-flex; }
173  /* Sonar beacon on the hero eyebrow — a filled dot with two concentric
174     rings that expand outward and fade on a loop, signalling Beta live
175     status. The dot itself is static; only the rings animate. */
176  .sig-hero .eyebrow .sonar { position: relative; display: inline-block; width: 6px; height: 6px; margin-left: 2px; border-radius: 50%; background: var(--accent); flex: none; }
177  .sig-hero .eyebrow .sonar::before,
178  .sig-hero .eyebrow .sonar::after {
179    content: ''; position: absolute; inset: 0; border-radius: 50%;
180    border: 1px solid var(--accent); opacity: 0;
181  }
182  @media (prefers-reduced-motion: no-preference) {
183    .sig-hero .eyebrow .sonar::before,
184    .sig-hero .eyebrow .sonar::after { animation: sigSonar 2.6s var(--ease) infinite; }
185    .sig-hero .eyebrow .sonar::after { animation-delay: 1.3s; }
186  }
187  @keyframes sigSonar { 0% { transform: scale(1); opacity: 0.55; } 100% { transform: scale(4.2); opacity: 0; } }
188  .sig-hero h1 {
189    font-size: clamp(38px, 5.6vw, 66px); line-height: 1.03; letter-spacing: -0.03em;
190    color: var(--ink); max-width: 18ch; margin: 22px auto 0; font-weight: 600; text-wrap: balance;
191  }
192  .sig-hero h1 .grad { font-style: normal; }
193  .sig-hero .sig-sub { font-size: clamp(17px, 1.8vw, 20px); line-height: 1.55; color: var(--ink-2); max-width: 60ch; margin: 22px auto 0; }
194  .sig-hero .hero-cta { justify-content: center; margin-top: 32px; }
195  .sig-hero-proof { margin-top: 22px; font-family: var(--font-mono); font-size: 12.5px; color: var(--muted); display: inline-flex; align-items: center; gap: 9px; }
196  .sig-hero-proof .pulse { width: 7px; height: 7px; border-radius: 50%; background: var(--accent); position: relative; flex: none; }
197  .sig-hero-proof .pulse::after { content: ''; position: absolute; inset: -4px; border-radius: 50%; border: 1px solid var(--accent); opacity: 0.4; animation: sigRing 2.4s var(--ease) infinite; }
198  @keyframes sigRing { 0% { transform: scale(0.6); opacity: 0.5; } 100% { transform: scale(1.6); opacity: 0; } }
199  .sig-hero-strip { display: flex; margin-top: 48px; padding-top: 26px; border-top: 1px solid var(--hair); width: 100%; max-width: 760px; align-items: center; justify-content: center; gap: 10px 12px; flex-wrap: wrap; }
200  .sig-hero-strip .pl { font-family: var(--font-mono); font-size: 12px; font-weight: 500; letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-3); }
201  .sig-hero-strip .sep { color: var(--hair-strong); display: inline-flex; }
202  .sig-hero-strip .sep svg { width: 15px; height: 15px; }
203  @media (max-width: 640px) {
204    .sig-hero-strip { margin-top: 36px; gap: 8px; }
205    .sig-hero-strip .pl { font-size: 11px; letter-spacing: 0.05em; }
206    .sig-hero-strip .sep svg { width: 12px; height: 12px; }
207  }
208  @media (prefers-reduced-motion: reduce) {
209    .sig-hero-proof .pulse::after { animation: none; }
210    .sig-hero .eyebrow .sonar::before, .sig-hero .eyebrow .sonar::after { display: none; }
211  }
212
213  /* ── Hero background scene · Converge ─────────────────────────────────
214     Ported from the Hypothesisly marketing hero (HeroScene.tsx +
215     .scene-converge in its marketing.css): ten evidence streams flow
216     inward, dashes animating toward a pulsing core. Recolored to the
217     ABTestly accent and driven entirely by this page's own tokens, so it
218     tracks light/dark automatically. Purely decorative and sits behind
219     .sig-hero .container: that element carries z-index:1, which the CSS
220     stacking rules always paint above this scene's implicit z-index:0,
221     regardless of DOM order, so headline/subhead/CTA stay unaffected. */
222  .sig-hero-scene { position: absolute; inset: 0; overflow: hidden; pointer-events: none; z-index: 0; }
223  .sig-hero-scene svg { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
224  .sig-scene-converge .sig-cv line { stroke: var(--accent); stroke-width: 1.2; opacity: 0.16; stroke-dasharray: 3 11; }
225  .sig-scene-converge .sig-cv-ring { fill: none; stroke: var(--accent); stroke-width: 1.4; opacity: 0.26; transform-box: fill-box; transform-origin: center; }
226  .sig-scene-converge .sig-cv-core { fill: var(--accent); opacity: 0.45; }
227  html[data-theme="dark"] .sig-scene-converge .sig-cv line { opacity: 0.2; }
228  html[data-theme="dark"] .sig-scene-converge .sig-cv-ring { opacity: 0.32; }
229  @media (prefers-reduced-motion: no-preference) {
230    .sig-scene-converge .sig-cv line { animation: sigCvFlow 2.4s linear infinite; }
231    .sig-scene-converge .sig-cv-ring { animation: sigCvRing 3.4s ease-out infinite; }
232    .sig-scene-converge .sig-cv-core { animation: sigCvCore 3.4s ease-in-out infinite; }
233  }
234  /* No prefers-reduced-motion: reduce override needed: the animation
235     property above is scoped inside the no-preference query only, so a
236     reduced-motion visitor simply gets the static rest state (dashed
237     lines, resting ring and core opacity) with zero motion. */
238  @keyframes sigCvFlow { to { stroke-dashoffset: -14; } }
239  @keyframes sigCvRing { 0% { transform: scale(0.4);
239 opacity: 0.44; } 100% { transform: scale(3.2); opacity: 0; } }
240  @keyframes sigCvCore { 0%, 100% { opacity: 0.38; } 50% { opacity: 0.68; } }
241
242  /* ── Wide pipeline wrapper (spans near the viewport, with side padding) ─ */
243  .sig-wide { max-width: min(1600px, 94vw); margin: 40px auto 0; padding: 0 clamp(16px, 4vw, 40px); }
244  .sig-pipe-more { text-align: center; margin-top: 28px; font-size: 15px; color: var(--ink-3); }
245  .sig-pipe-more a { color: var(--accent-ink); font-weight: 500; }
246  .sig-pipe-more a:hover { color: var(--accent); }
247
248  /* ── Differentiators — flowing spine timeline ───────────────────────── */
249  .sig-diff { position: relative; max-width: 880px; margin: 0 auto; }
250  .sig-diff-item { position: relative; display: grid; grid-template-columns: 210px minmax(0, 1fr); gap: clamp(24px, 4vw, 56px); padding: 0 0 clamp(40px, 5vw, 64px) 46px; align-items: start; }
251  .sig-diff-item:last-child { padding-bottom: 0; }
252  .sig-diff-item::before { content: ''; position: absolute; left: 6px; top: 14px; bottom: -2px; width: 2px; background: linear-gradient(180deg, var(--accent) 0%, var(--accent-ring) 70%, transparent 100%); opacity: 0.5; }
253  .sig-diff-item:last-child::before { background: linear-gradient(180deg, var(--accent) 0%, transparent 92%); }
254  .sig-diff-node { position: absolute; left: 0; top: 7px; width: 14px; height: 14px; border-radius: 50%; background: var(--surface); border: 2px solid var(--accent); z-index: 1; }
255  .sig-diff-node::after { content: ''; position: absolute; inset: 2px; border-radius: 50%; background: var(--accent); opacity: 0.85; transform-origin: center; }
256  @media (prefers-reduced-motion: no-preference) {
257    .sig-diff-node::after { animation: sigNode 3.6s ease-in-out infinite; }
258    .sig-diff-item:nth-child(2) .sig-diff-node::after { animation-delay: 1.2s; }
259    .sig-diff-item:nth-child(3) .sig-diff-node::after { animation-delay: 2.4s; }
260  }
261  @keyframes sigNode { 0%, 100% { transform: scale(1); opacity: 0.85; } 50% { transform: scale(1.35); opacity: 0.5; } }
262  .sig-diff-term { display: flex; flex-direction: column; gap: 10px; }
263  .sig-diff-term .k { font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.07em; text-transform: uppercase; color: var(--accent-ink); display: inline-flex; align-items: center; gap: 8px; }
264  .sig-diff-term .tag { font-family: var(--font-mono); font-size: 12px; color: var(--muted); }
265  .sig-diff-body h3 { font-size: clamp(20px, 2vw, 27px); line-height: 1.22; letter-spacing: -0.02em; margin: 0 0 12px; text-wrap: balance; color: var(--ink); font-weight: 600; }
266  .sig-diff-body p { font-size: 16px; line-height: 1.65; color: var(--ink-2); margin: 0; max-width: 56ch; text-wrap: pretty; }
267  .sig-diff-body p b { color: var(--ink); font-weight: 600; }
268  @media (max-width: 760px) {
269    .sig-diff-item { grid-template-columns: 1fr; gap: 14px; padding-left: 38px; }
270    .sig-diff-term { flex-direction: row; align-items: center; justify-content: space-between; gap: 12px; }
271  }
272
273  /* ── Honesty floor — editorial divided manifesto ────────────────────── */
274  .sig-floor { display: grid; grid-template-columns: minmax(0, 0.82fr) minmax(0, 1.7fr); gap: clamp(36px, 6vw, 84px); align-items: start; }
275  .sig-floor-head { position: sticky; top: 96px; }
276  .sig-floor-head .eyebrow { display: inline-flex; margin-bottom: 16px; }
277  .sig-floor-head h2 { margin: 0 0 16px; font-size: clamp(28px, 3.6vw, 40px); letter-spacing: -0.022em; line-height: 1.1; color: var(--ink); }
278  .sig-floor-head p { font-size: 16.5px; line-height: 1.62; color: var(--ink-3); max-width: 32ch; margin: 0; text-wrap: pretty; }
279  .sig-floor-list { display: flex; flex-direction: column; }
280  .sig-floor-item { display: grid; grid-template-columns: auto 1fr; gap: clamp(20px, 3vw, 40px); padding: clamp(24px, 3vw, 34px) 0; border-top: 1px solid var(--hair); align-items: baseline; }
281  .sig-floor-item:first-child { border-top: 0; padding-top: 4px; }
282  .sig-floor-n { font-family: var(--font-mono); font-size: clamp(30px, 3.4vw, 46px); font-weight: 500; line-height: 0.9; color: var(--hair-strong); font-variant-numeric: tabular-nums; letter-spacing: -0.03em; transition: color 0.25s var(--ease); }
283  .sig-floor-item:hover .sig-floor-n { color: var(--accent); }
284  .sig-floor-body h3 { font-size: clamp(19px, 1.6vw, 23px); letter-spacing: -0.015em; margin: 0 0 9px; text-wrap: balance; color: var(--ink); font-weight: 600; }
285  .sig-floor-body p { font-size: 16px; line-height: 1.65; color: var(--ink-2); max-width: 60ch; margin: 0; text-wrap: pretty; }
286  .sig-floor-body p b { color: var(--ink); font-weight: 600; }
287  @media (max-width: 860px) {
288    .sig-floor { grid-template-columns: 1fr; gap: 28px; }
289    .sig-floor-head { position: static; }
290  }
291
292  /* ── Learning-loop flywheel ─────────────────────────────────────────── */
293  .sig-loop { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 10px; max-width: 960px; margin: 0 auto; }
294  .sig-loop-node { font-family: var(--font-mono); font-size: 12.5px; color: var(--ink-2); background: var(--surface); border: 1px solid var(--hair); border-radius: var(--r-pill); padding: 8px 16px; box-shadow: var(--shadow-sm); }
295  .sig-loop-node--accent { color: var(--accent-ink); background: var(--accent-soft); border-color: var(--accent); }
296  .sig-loop-arrow { font-family: var(--font-mono); color: var(--muted); font-size: 14px; }
297  .sig-loop-arrow--back { color: var(--accent); font-size: 17px; }
298  @media (max-width: 620px) { .sig-loop { flex-direction: column; } .sig-loop-arrow { transform: rotate(90deg); } }
299  .sig-note { display: flex; align-items: flex-start; gap: 14px; max-width: 760px; margin: 40px auto 0; padding: 18px 22px; border: 1px solid var(--hair); border-radius: var(--r-4); background: var(--surface-2); }
300  .sig-note-k { font-family: var(--font-mono); font-size: 11px; font-weight: 500; letter-spacing: 0.08em; text-transform: uppercase; color: var(--accent-ink); flex: 0 0 auto; margin-top: 2px; }
301  .sig-note p { font-size: 14.5px; line-height: 1.6; color: var(--ink-2); margin: 0; }
302
303  /* ── Pricing — free in Beta, priced by scans after ──────────────────── */
304  .sig-pricing .plan-grid { grid-template-columns: repeat(3, 1fr); max-width: 900px; margin: var(--s-7) auto 0; }
305  .sig-pricing .plan-desc { min-height: 0; margin-bottom: 0; }
306  .sig-pricing .plan-price { margin-top: var(--s-2); }
307  @media (max-width: 760px) {
308    .sig-pricing .plan-grid { grid-template-columns: 1fr; max-width: 420px; }
309  }
310
311  /* ════════════════════════════════════════════════════════════════════
312     Pipeline token aliases.
313     The interactive pipeline below is ported structurally verbatim; it
314     uses its own internal token names. Here we map those onto the site's
315     tokens so the diagram inherits the page's own light and dark. Tokens
316     whose names already match the site (--ink, --ink-2, --ink-3, --warn,
317     --warn-ink, --warn-soft, --shadow-md, --font-sans, --font-mono,
318     --t-base, --ease) are intentionally NOT re-declared: they inherit
319     straight from :root, and a self-referential alias (e.g. --ink: var(--ink))
320     would be a cyclic, invalid-at-computed-value declaration. The block is
321     scoped to BOTH roots because the modal (.pmodal) is a sibling of the
322     diagram, not a descendant of .audit.
323     ════════════════════════════════════════════════════════════════════ */
324  .audit, .pmodal {
325    --canvas: var(--bg);
326    --paper: var(--surface);
327    --paper-2: var(--surface-2);
328    --well: var(--surface-3);
329    --line: var(--hair);
330    --line-2: var(--hair-soft, var(--hair));
331    --line-strong: var(--hair-strong);
332    --ink-4: var(--muted);
333    --ink-5: var(--hair-strong);
334    --brand: var(--accent);
335    --brand-600: var(--accent-hover);
336    --brand-700: var(--accent-ink);
337    --brand-soft: var(--accent-soft);
338    --brand-soft-2: var(--accent-soft-2);
339    --brand-ring: var(--accent-ring);
340    --scrim: rgba(0, 0, 0, 0.5);
341    --shadow-xs: var(--shadow-sm);
342
343    /* Falsification accent: no site token exists, so define it literally. */
344    --neg: #c2410c;
345    --neg-soft: #f6e4d9;
346
347    /* Structural tokens the pipeline needs that the site does not name. */
348    --r-xs: 5px;
349    --r-sm: 7px;
350    --r-md: 9px;
351    --r-lg: 11px;
352    --r-xl: 14px;
353    --r-2xl: 18px;
354    --r-pill: 999px;
355    --ease-spring: cubic-bezier(0.34, 1.32, 0.46, 1);
356  }
357  [data-theme="dark"] .audit, [data-theme="dark"] .pmodal {
358    --neg: #e79457;
359    --neg-soft: rgba(231, 148, 87, 0.18);
360  }
361
362  /* ════════════════════════════════════════════════════════════════════
363     Pipeline diagram — structure and rule set ported verbatim. Only the
364     palette resolves through the aliases above.
365     ════════════════════════════════════════════════════════════════════ */
366
367  /* ── Audit canvas (the pipeline sits on a bordered card) ─────────────── */
368  .audit {
369    container-type: inline-size;
370    border: 1px solid var(--line);
371    border-radius: var(--r-2xl);
372    background:
373      radial-gradient(130% 90% at 0% 0%, var(--brand-soft-2) 0%, transparent 44%),
374      var(--paper);
375    box-shadow: var(--shadow-md);
376    padding: 30px 30px 32px;
377    overflow: hidden;
378  }
379
380  /* ── Full pipeline diagram (three streams converge → refine) ─────────── */
381  .pipe-cap { display: flex; justify-content: space-between; gap: 16px; margin-bottom: 20px; flex-wrap: wrap; }
382  .pipe-cap span { font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.05em; text-transform: uppercase; color: var(--brand-700); display: inline-flex; align-items: center; gap: 7px; text-wrap: pretty; }
383  .pipe-cap .r { color: var(--ink-4); }
384  .pipe-cap .r::before { content: ''; width: 5px; height: 5px; border-radius: 50%; background: var(--ink-5); }
385
386  .pipe-diagram { display: flex; align-items: stretch; }
387  .pipe-inputs { flex: 0 0 232px; display: flex; flex-direction: column; gap: 10px; }
388  .pipe-inputs .pnode { flex: 1; flex-direction: row; align-items: flex-start; gap: 11px; padding: 13px; }
389  .pipe-inputs .pn-ic { margin-top: 1px; }
390  .pipe-inputs .pn-col { display: flex; flex-direction: column; gap: 7px; min-width: 0; }
391  .pipe-inputs .pn-n { margin-top: 2px; }
392  .pipe-merge { flex: 0 0 50px; align-self: stretch; color: var(--line-strong); }
393  .pipe-merge svg { width: 100%; height: 100%; display: block; }
394  .pipe-merge path { fill: none; stroke: currentColor; stroke-width: 1.5; }
395  .pchain { flex: 1 1 0; min-width: 0; display: flex; align-items: center; }
396  .pipe-arrow { display: flex; align-items: center; justify-content: center; color: var(--ink-5); padding: 0 7px; flex: 0 0 auto; }
397  .pipe-arrow svg { width: 19px; height: 19px; }
398
399  .pnode { background: var(--paper); border: 1px solid var(--line); border-radius: var(--r-lg); padding: 14px; box-shadow: var(--shadow-xs); display: flex; flex-direction: column; gap: 9px; width: 100%; }
400  .pn-head { display: flex; align-items: center; gap: 9px; }
401  .pn-ic { width: 30px; height: 30px; flex: none; border-radius: var(--r-sm); background: var(--brand-soft); color: var(--brand); display: grid; place-items: center; }
402  .pn-ic svg { width: 16px; height: 16px; }
403  .pn-n { font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.06em; text-transform: uppercase; color: var(--ink-4); }
404  .pn-t { font-size: 13.5px; font-weight: 500; color: var(--ink); letter-spacing: -0.01em; line-height: 1.25; }
405  .pn-d { font-size: 11.5px; line-height: 1.45; color: var(--ink-3); }
406  .pnode.is-hub { border-color: var(--brand-ring); background: linear-gradient(180deg, var(--brand-soft-2), var(--paper) 72%); }
407  .pnode.is-fals .pn-ic { background: var(--neg-soft); color: var(--neg); }
408  .pn-tags { display: flex; flex-wrap: wrap; gap: 5px;
408 margin-top: 1px; min-width: 0; }
409  .audit .pchain, .audit .pnode, .audit .pn-col, .audit .pn-head { min-width: 0; }
410  .audit .pn-t, .audit .pn-d { overflow-wrap: anywhere; text-wrap: pretty; }
411  .pn-tag { font-family: var(--font-mono); font-size: 9.5px; line-height: 1.45; letter-spacing: 0.01em; color: var(--ink-3); background: var(--well); border: 1px solid var(--line-2); border-radius: var(--r-xs); padding: 2px 6px; white-space: normal; max-width: 100%; overflow-wrap: anywhere; }
412  .pn-tag.b { color: var(--brand-700); background: var(--brand-soft); border-color: transparent; }
413  .pn-tag.q { color: var(--warn-ink); background: var(--warn-soft); border-color: transparent; }
414
415  .pipe-foot { display: flex; justify-content: space-between; align-items: center; gap: 14px 28px; flex-wrap: wrap; margin-top: 20px; padding-top: 16px; border-top: 1px solid var(--line-2); font-family: var(--font-mono); font-size: 11px; color: var(--ink-4); }
416  .pipe-foot span { display: inline-flex; align-items: center; gap: 7px; }
417  .pipe-foot span::before { content: ''; width: 5px; height: 5px; border-radius: 50%; background: var(--brand); flex: none; }
418  .pipe-foot b { color: var(--ink-3); font-weight: 500; }
419
420  @container (max-width: 980px) {
421    .pipe-diagram { flex-direction: column; gap: 10px; }
422    .pipe-inputs { flex: none; flex-direction: row; }
423    .pipe-inputs .pnode { flex: 1 1 0; }
424    .pipe-merge { flex: none; height: 24px; width: 100%; }
425    .pipe-merge svg { display: none; }
426    .pipe-merge::after { content: ''; display: block; width: 1.5px; height: 100%; margin: 0 auto; background: var(--line-strong); }
427    .pchain { flex: none; }
428    .pipe-arrow { padding: 2px 0; }
429    .pipe-arrow svg { transform: rotate(90deg); }
430  }
431  @container (max-width: 620px) {
432    .pipe-inputs { flex-direction: column; }
433  }
434
435  /* ── Pipeline looping explainer (animations) ─────────────────────────── */
436  @media (prefers-reduced-motion: no-preference) {
437    .audit .pipe-merge path { stroke: var(--brand); stroke-dasharray: 5 9; animation: pipeMergeFlow 1.4s linear infinite; }
438    .audit .pnode { position: relative; }
439    .audit .pnode::after {
440      content: ''; position: absolute; inset: -2px; border-radius: 13px;
441      box-shadow: 0 0 0 1.5px var(--brand-ring), 0 12px 36px -6px var(--brand-ring);
442      opacity: 0; pointer-events: none; transform-origin: center;
443      animation: pipeBeat 8.5s cubic-bezier(0.37, 0, 0.34, 1) infinite;
444    }
445    .audit .pnode.is-fals::after { box-shadow: 0 0 0 1.5px var(--neg), 0 12px 36px -6px var(--neg-soft); }
446    .audit .pipe-inputs .pnode:nth-child(1)::after { animation-delay: 0s; }
447    .audit .pipe-inputs .pnode:nth-child(2)::after { animation-delay: 0.13s; }
448    .audit .pipe-inputs .pnode:nth-child(3)::after { animation-delay: 0.26s; }
449    .audit .pipe-diagram > .pchain:nth-child(3) .pnode::after { animation-delay: 1.05s; }
450    .audit .pipe-diagram > .pchain:nth-child(5) .pnode::after { animation-delay: 1.95s; }
451    .audit .pipe-diagram > .pchain:nth-child(7) .pnode::after { animation-delay: 2.85s; }
452    .audit .pipe-diagram > .pchain:nth-child(9) .pnode::after { animation-delay: 3.75s; }
453    .audit .pipe-arrow svg { animation: pipeArrowGlide 8.5s cubic-bezier(0.37, 0, 0.34, 1) infinite; will-change: transform, opacity; }
454    .audit .pipe-diagram > .pipe-arrow:nth-child(4) svg { animation-delay: 1.5s; }
455    .audit .pipe-diagram > .pipe-arrow:nth-child(6) svg { animation-delay: 2.4s; }
456    .audit .pipe-diagram > .pipe-arrow:nth-child(8) svg { animation-delay: 3.3s; }
457  }
458  @keyframes pipeMergeFlow { to { stroke-dashoffset: -14; } }
459  @keyframes pipeBeat {
460    0%   { opacity: 0;    transform: scale(0.965); }
461    6%   { opacity: 0.9;  transform: scale(1.004); }
462    11%  { opacity: 1;    transform: scale(1.012); }
463    18%  { opacity: 0.55; transform: scale(1.022); }
464    26%  { opacity: 0;    transform: scale(1.032); }
465    100% { opacity: 0;    transform: scale(0.965); }
466  }
467  @keyframes pipeArrowGlide {
468    0%   { opacity: 0.4; transform: translateX(-3px); color: var(--ink-5); }
469    7%   { opacity: 1;   transform: translateX(2px);  color: var(--brand); }
470    16%  { opacity: 0.6; transform: translateX(3px);  color: var(--brand); }
471    26%  { opacity: 0.4; transform: translateX(-3px); color: var(--ink-5); }
472    100% { opacity: 0.4; transform: translateX(-3px); color: var(--ink-5); }
473  }
474
475  /* ── Clickable stage cards + expand badge + tap hint ─────────────────── */
476  .audit .pipe-diagram .pnode { cursor: pointer; padding-right: 30px; transition: transform 0.16s var(--ease), box-shadow 0.16s var(--ease), border-color 0.16s var(--ease); }
477  .audit .pipe-diagram .pnode:hover { transform: translateY(-2px); box-shadow: var(--shadow-md); border-color: var(--brand-ring); }
478  .audit .pipe-diagram .pnode:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
479  .audit .pn-more { position: absolute; top: 8px; right: 8px;
479 width: 20px; height: 20px; border-radius: 6px; display: grid; place-items: center; color: var(--ink-4); background: var(--well); border: 1px solid var(--line-2); transition: color 0.15s var(--ease), background 0.15s var(--ease), border-color 0.15s var(--ease); }
480  .audit .pn-more svg { width: 11px; height: 11px; }
481  .audit .pipe-diagram .pnode:hover .pn-more { color: #fff; background: var(--brand); border-color: transparent; }
482  .audit .pipe-hint { display: flex; width: fit-content; margin: 18px auto 0; align-items: center; gap: 7px; font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.03em; color: var(--brand-700); background: var(--brand-soft); border-radius: var(--r-pill); padding: 6px 13px; }
483  .audit .pipe-hint svg { width: 13px; height: 13px; color: var(--brand); }
484
485  /* ── Feedback loop: 07 Output → logged outcomes → 01 Intake ──────────── */
486  .audit .pipe-loop { position: relative; height: 54px; margin: 16px 8px 2px; }
487  .audit .pl-bracket { position: absolute; left: 10px; right: 10px; top: 13px; bottom: 8px; border: 2px dashed var(--brand); border-top: 0; border-radius: 0 0 18px 18px; opacity: 0.55; }
488  .audit .pl-arrow { position: absolute; left: 4px; top: 1px; width: 0; height: 0; border-left: 7px solid transparent; border-right: 7px solid transparent; border-bottom: 11px solid var(--brand); }
489  .audit .pl-dot { position: absolute; bottom: 4px; left: calc(100% - 18px); width: 9px; height: 9px; border-radius: 50%; background: var(--brand); box-shadow: 0 0 0 4px var(--brand-soft); opacity: 0; z-index: 2; }
490  .audit .pl-from, .audit .pl-to { position: absolute; top: 2px; font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.04em; text-transform: uppercase; color: var(--ink-4); background: var(--paper); padding: 0 6px; }
491  .audit .pl-from { right: 12px; }
492  .audit .pl-to { left: 24px; }
493  .audit .pl-tag { position: absolute; left: 50%; top: 46px; transform: translate(-50%, -50%); display: inline-flex; align-items: center; gap: 8px; cursor: pointer; font-family: var(--font-mono); font-size: 11.5px; color: var(--brand-700); background: var(--paper); border: 1px solid var(--brand-ring); border-radius: var(--r-pill); padding: 6px 14px; box-shadow: var(--shadow-xs); white-space: nowrap; transition: border-color var(--t-base); }
494  .audit .pl-tag:hover { border-color: var(--brand); }
495  .audit .pl-tag:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
496  .audit .pl-tag svg { width: 14px; height: 14px; color: var(--brand); }
497  @container (max-width: 980px) {
498    .audit .pipe-loop { height: auto; margin-top: 16px; text-align: center; }
499    .audit .pl-bracket, .audit .pl-arrow, .audit .pl-dot, .audit .pl-from, .audit .pl-to { display: none; }
500    .audit .pl-tag { position: static; transform: none; }
501  }
502  @media (prefers-reduced-motion: no-preference) {
503    .audit .pl-bracket { animation: plLoopBeat 8.5s ease-in-out infinite; }
504    .audit .pl-dot { animation: plLoopDot 8.5s cubic-bezier(0.45, 0.05, 0.3, 1) infinite; }
505  }
506  @keyframes plLoopBeat { 0%, 50%, 100% { opacity: 0.45; } 60% { opacity: 0.95; } 82% { opacity: 0.95; } 90% { opacity: 0.45; } }
507  @keyframes plLoopDot {
508    0%, 52%   { left: calc(100% - 18px); opacity: 0; }
509    57%       { left: calc(100% - 18px); opacity: 1; }
510    80%       { left: 9px; opacity: 1; }
511    86%, 100% { left: 9px; opacity: 0; }
512  }
513
514  /* ── Stage detail modal ──────────────────────────────────────────────── */
515  .pmodal[hidden] { display: none; }
516  .pmodal { position: fixed; inset: 0; z-index: 120; display: grid; place-items: center; padding: 24px; }
517  .pmodal-scrim { position: absolute; inset: 0; background: var(--scrim); -webkit-backdrop-filter: blur(3px); backdrop-filter: blur(3px); animation: pmFade 0.2s ease; }
518  .pmodal-panel { position: relative; width: min(560px, 100%); max-height: 86vh; overflow: auto; background: var(--paper); border: 1px solid var(--line); border-radius: var(--r-2xl); box-shadow: var(--shadow-md); padding: 26px 26px 24px; animation: pmRise 0.3s var(--ease-spring); }
519  @keyframes pmFade { from { opacity: 0; } }
520  @keyframes pmRise { from { opacity: 0; transform: translateY(14px) scale(0.985); } }
521  .pmodal-x { position: absolute; top: 14px; right: 14px; width: 32px; height: 32px; border-radius: var(--r-sm); border: 1px solid var(--line); background: var(--paper); color: var(--ink-3); display: grid; place-items: center; cursor: pointer; transition: color 0.15s, background 0.15s; }
522  .pmodal-x:hover { background: var(--paper-2); color: var(--ink); }
523  .pmodal-x svg { width: 16px; height: 16px; }
524  .pmodal-head { display: flex; gap: 14px; align-items: flex-start; margin-bottom: 16px; padding-right: 30px; }
525  .pmodal-head > div { display: flex; flex-direction: column; gap: 3px; padding-top: 2px; }
526  .pmodal-ic { width: 44px; height: 44px; flex: none; border-radius: var(--r-md); background: var(--brand-soft); color: var(--brand); display: grid; place-items: center; }
527  .pmodal-ic.neg { background: var(--neg-soft); color: var(--neg); }
528  .pmodal-ic svg { width: 22px; height: 22px; }
529  .pmodal-eyebrow { font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-4); }
530  .pmodal-title { font-size: 21px; letter-spacing: -0.02em; color: var(--ink); line-height: 1.15; margin: 0; font-weight: 500; }
531  .pmodal-lead { font-size: 15px; line-height: 1.6; color: var(--ink-2); margin: 0 0 16px; }
532  .pmodal-list { list-style: none; padding: 0; margin: 0; display: grid; gap: 11px; }
533  .pmodal-list li { display: flex; gap: 10px; }
534  .pmodal-list li::before { content: ''; flex: none; width: 6px; height: 6px; margin-top: 7px; border-radius: 50%; background: var(--brand); }
535  .pmodal-list li span { font-size: 14px; line-height: 1.5; color: var(--ink-2); }
536  .pmodal-list li span b { color: var(--ink); font-weight: 500; }
537  .pmodal-note { margin-top: 18px; padding: 13px 15px; border-radius: var(--r-lg); background: var(--well); border: 1px solid var(--line-2); font-size: 13px; line-height: 1.55; color: var(--ink-3); display: flex; gap: 9px; }
538  .pmodal-note svg { width: 15px; height: 15px; flex: none; margin-top: 2px; color: var(--ink-4); }
539  .pmodal-note.warn { background: var(--warn-soft); border-color: transparent; color: var(--warn-ink); }
540  .pmodal-note.warn svg { color: var(--warn); }
541  </style>
542  
542<script type="module" crossorigin src="/assets/modulepreload-polyfill-B5Qt9EMX.js"></script>
542
543  
543<script type="module" crossorigin src="/assets/main-CRu3pe50.js"></script>
543
544  <link rel="stylesheet" crossorigin href="/assets/main-C0jWISLR.css">
545</head>
546<body>
547
548  <!-- =================== HEADER =================== -->
549  <header class="site-header">
550    <nav class="nav" aria-label="Primary">
551      <a class="brand" href="/" aria-label="ABTestly home">
552        <svg class="brand-mark" viewBox="0 0 220 92" aria-hidden="true" focusable="false"><rect class="brand-mark-top" x="0" y="0" width="132" height="34" rx="17"/><path class="brand-mark-win" d="M17 58 A17 17 0 0 0 17 92 L196 92 L208 58 Z"/></svg><span class="brand-word">ABTestly</span>
553      </a>
554      <ul class="nav-links" role="list">
555        <li><a href="/#how-it-works">How it works</a></li>
556        <li><a href="/signals" aria-current="page">Signals</a></li>
557        <li><a href="/compare">Compare</a></li>
558        <li><a href="/#developers">Developers</a></li>
559        <li><a href="/pricing">Pricing</a></li>
560        <li><a href="https://docs.abtestly.com" target="_blank" rel="noopener noreferrer">Docs</a></li>
561      </ul>
562      <div class="nav-actions">
563        <button class="theme-toggle" type="button" data-theme-toggle aria-label="Toggle dark mode" title="Toggle theme">
564          <svg class="icon-sun" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="4"/><path d="M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M4.93 19.07l1.41-1.41M17.66 6.34l1.41-1.41"/></svg>
565          <svg class="icon-moon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M21 12.79A9 9 0 1 1 11.21 3a7 7 0 0 0 9.79 9.79z"/></svg>
566        </button>
567        <a class="btn btn-ghost" href="https://app.abtestly.com/sign-in">Log in</a>
568        <a class="btn btn-primary" href="https://app.abtestly.com/sign-up">Start free trial</a>
569      </div>
570    </nav>
571  </header>
572
573  <main>
574
575    <!-- =================== 1 · HERO =================== -->
576    <section class="sig-hero">
577      <div class="sig-hero-scene" aria-hidden="true">
578        <svg class="sig-scene-converge" viewBox="0 0 1200 600" preserveAspectRatio="xMidYMid slice">
579          <g class="sig-cv">
580            <line x1="-60" y1="40" x2="600" y2="300"/>
581            <line x1="300" y1="-50" x2="600" y2="300"/>
582            <line x1="700" y1="-60" x2="600" y2="300"/>
583            <line x1="1260" y1="30" x2="600" y2="300"/>
584            <line x1="1290" y1="300" x2="600" y2="300"/>
585            <line x1="1260" y1="560" x2="600" y2="300"/>
586            <line x1="760" y1="660" x2="600" y2="300"/>
587            <line x1="320" y1="650" x2="600" y2="300"/>
588            <line x1="-70" y1="560" x2="600" y2="300"/>
589            <line x1="-90" y1="300" x2="600" y2="300"/>
590          </g>
591          <circle class="sig-cv-ring" cx="600" cy="300" r="14"/>
592          <circle class="sig-cv-core" cx="600" cy="300" r="5"/>
593        </svg>
594      </div>
595      <div class="container">
596        <span class="eyebrow">Signals &middot; Beta<span class="sonar" aria-hidden="true"></span></span>
597        <h1>AI powered hypothesis generation, <span class="grad">ranked and falsifiable.</span></h1>
598        <p class="sig-sub">
599          ABTestly is a code first A/B testing platform. Signals is its optional CRO audit add on: it reads your page and your GA4, then generates a ranked, evidence graded backlog of A/B test hypotheses. Every idea is graded on its evidence and put through a pass that argues against it.
600        </p>
601        <div class="hero-cta">
602          <a class="btn btn-primary btn-lg" href="https://app.abtestly.com/sign-up">Start your free trial <span class="arrow" aria-hidden="true">&rarr;</span></a>
603          <a class="btn btn-secondary btn-lg" href="https://docs.abtestly.com/signals/overview" target="_blank" rel="noopener noreferrer">Read the docs</a>
604        </div>
605        <div class="sig-hero-proof">
606          <span class="pulse" aria-hidden="true"></span>In beta. It runs on the Anthropic commercial API, whose terms do not use your data to train models.
607        </div>
608        <div class="sig-hero-strip" aria-hidden="true">
609          <span class="pl">Evidence</span>
610          <span class="sep"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M13 6l6 6-6 6"/></svg></span>
611          <span class="pl">Payload</span>
612          <span class="sep"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M13 6l6 6-6 6"/></svg></span>
613          <span class="pl">Generation</span>
614          <span class="sep"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M13 6l6 6-6 6"/></svg></span>
615          <span class="pl">Falsification</span>
616          <span class="sep"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M13 6l6 6-6 6"/></svg></span>
617          <span class="pl">Ranked backlog</span>
618        </div>
619      </div>
620    </section>
621
622    <!-- =================== 2 · HOW A SCAN WORKS (pipeline) =================== -->
623    <section class="section" id="how-it-works" style="border-top:1px solid var(--hair); background: var(--surface); padding-top: var(--s-11); padding-bottom: var(--s-11);">
624      <div class="container">
625        <div class="section-head center sig-reveal">
626          <span class="eyebrow" style="display:inline-flex;">how a scan works</span>
627          <h2>Three evidence streams. <em class="grad">One ranked backlog.</em></h2>
628          <p>Seven stages with a shape. Three evidence streams converge into one multimodal payload, then Signals generates hypotheses, argues against its own work, and ranks what it found. Tap any stage to see inside it.</p>
629        </div>
630      </div>
631
632      <div class="sig-wide sig-reveal">
633        <div class="audit">
634          <div class="pipe-cap">
635            <span>Evidence in &middot; three parallel streams</span>
636            <span class="r">Reasoning &middot; narrowed to a ranked backlog</span>
637          </div>
638          <div class="pipe-diagram">
639            <div class="pipe-inputs">
640              <div class="pnode" data-stage="1" role="button" tabindex="0" aria-haspopup="dialog">
641                <span class="pn-ic"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M12 3v18M3 8h6M3 16h6M15 8h6M15 16h6"/></svg></span>
642                <div class="pn-col"><span class="pn-n">01 &middot; Intake</span><div class="pn-t">Site &amp; business context</div><div class="pn-tags"><span class="pn-tag">URL plus context</span><span class="pn-tag">connect GA4</span><span class="pn-tag b">sets what a scan can read</span></div></div>
643                <span class="pn-more" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M15 3h6v6"/><path d="M9 21H3v-6"/><path d="M21 3l-7 7"/><path d="M3 21l7-7"/></svg></span>
644              </div>
645              <div class="pnode" data-stage="2" role="button" tabindex="0" aria-haspopup="dialog">
646                <span class="pn-ic"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="18" height="14" rx="2"/><path d="M3 8h18M8 21h8"/></svg></span>
647                <div class="pn-col"><span class="pn-n">02 &middot; Capture</span><div class="pn-t">DOM, renders, funnel walks</div><div class="pn-tags"><span class="pn-tag b">20 plus DOM signals</span><span class="pn-tag">desktop and mobile</span><span class="pn-tag">throttled view</span></div></div>
648                <span class="pn-more" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M15 3h6v6"/><path d="M9 21H3v-6"/><path d="M21 3l-7 7"/><path d="M3 21l7-7"/></svg></span>
649              </div>
650              <div class="pnode" data-stage="3" role="button" tabindex="0" aria-haspopup="dialog">
651                <span class="pn-ic"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M3 3v18h18"/><rect x="7" y="11" width="3" height="6"/><rect x="13" y="7" width="3" height="10"/></svg></span>
652                <div class="pn-col"><span class="pn-n">03 &middot; Behaviour</span><div class="pn-t">GA4 funnel and drop off</div><div class="pn-tags"><span class="pn-tag">device CVR and channels</span><span class="pn-tag">funnel drop off</span></div></div>
653                <span class="pn-more" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M15 3h6v6"/><path d="M9 21H3v-6"/><path d="M21 3l-7 7"/><path d="M3 21l7-7"/></svg></span>
654              </div>
655            </div>
656            <div class="pipe-merge" aria-hidden="true"><svg viewBox="0 0 50 100" preserveAspectRatio="none"><path d="M2 16 C 28 16 24 50 48 50" vector-effect="non-scaling-stroke"/><path d="M2 50 H 48" vector-effect="non-scaling-stroke"/><path d="M2 84 C 28 84 24 50 48 50" vector-effect="non-scaling-stroke"/></svg></div>
657            <div class="pchain"><div class="pnode is-hub" data-stage="4" role="button" tabindex="0" aria-haspopup="dialog">
658              <div class="pn-head"><span class="pn-ic"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M4 7h6l6 5"/><path d="M4 17h6l6-5"/><circle cx="18" cy="12" r="2" fill="currentColor" stroke="none"/></svg></span><span class="pn-n">04 &middot; Payload</span></div>
659              <div class="pn-t">Multimodal payload assembled</div><div class="pn-d">Three image blocks plus structured evidence, combined into one prompt.</div><div class="pn-tags"><span class="pn-tag">3 images + text</span><span class="pn-tag">vision reconciled</span></div>
660              <span class="pn-more" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M15 3h6v6"/><path d="M9 21H3v-6"/><path d="M21 3l-7 7"/><path d="M3 21l7-7"/></svg></span>
661            </div></div>
662            <div class="pipe-arrow"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M13 6l6 6-6 6"/></svg></div>
663            <div class="pchain"><div class="pnode" data-stage="5" role="button" tabindex="0" aria-haspopup="dialog">
664              <div class="pn-head"><span class="pn-ic"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M12 3l2.4 4.9 5.4.8-3.9 3.8.9 5.4L12 15.6l-4.8 2.5.9-5.4L4.2 8.7l5.4-.8z"/></svg></span><span class="pn-n">05 &middot; Generation</span></div>
665              <div class="pn-t">Grounded hypotheses</div><div class="pn-d">Each tied to a behavioral mechanism and a citation; thin evidence is labeled, not inflated.</div><div class="pn-tags"><span class="pn-tag b">structured fields</span><span class="pn-tag b">8 yes or no answers</span><span class="pn-tag">5 CRO pillars</span><span class="pn-tag">two signal gate</span></div>
666              <span class="pn-more" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M15 3h6v6"/><path d="M9 21H3v-6"/><path d="M21 3l-7 7"/><path d="M3 21l7-7"/></svg></span>
667            </div></div>
668            <div class="pipe-arrow"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M13 6l6 6-6 6"/></svg></div>
669            <div class="pchain"><div class="pnode is-fals" data-stage="6" role="button" tabindex="0" aria-haspopup="dialog">
670              <div class="pn-head"><span class="pn-ic"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M12 9v4M12 17h.01"/><path d="M10.3 3.9 2 18a2 2 0 0 0 1.7 3h16.6a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0z"/></svg></span><span class="pn-n">06 &middot; Falsification</span></div>
671              <div class="pn-t">Argued against itself</div><div class="pn-d">Failure mode, confounder, alternative, and the test that settles it.</div><div class="pn-tags"><span class="pn-tag q">adversarial second pass</span></div>
672              <span class="pn-more" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M15 3h6v6"/><path d="M9 21H3v-6"/><path d="M21 3l-7 7"/><path d="M3 21l7-7"/></svg></span>
673            </div></div>
674            <div class="pipe-arrow"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14M13 6l6 6-6 6"/></svg></div>
675            <div class="pchain"><div class="pnode is-out" data-stage="7" role="button" tabindex="0" aria-haspopup="dialog">
676              <div class="pn-head"><span class="pn-ic"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M5 4h11l3 3v13H5z"/><path d="M9 9h6M9 13h6M9 17h4"/></svg></span><span class="pn-n">07 &middot; Output</span></div>
677              <div class="pn-t">Structured hypotheses, ranked</div><div class="pn-d">Ordered by PXL, each with its evidence tier, effort and a tracking spec.</div><div class="pn-tags"><span class="pn-tag b">PXL ranked</span><span class="pn-tag">4 evidence tiers</span><span class="pn-tag">ready to build</span></div>
678              <span class="pn-more" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M15 3h6v6"/><path d="M9 21H3v-6"/><path d="M21 3l-7 7"/><path d="M3 21l7-7"/></svg></span>
679            </div></div>
680          </div>
681          <div class="pipe-hint"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M9 9l5 12 1.8-5.2L21 14 9 9z"/></svg>Tap any stage to see what happens inside it</div>
682          <div class="pipe-loop" aria-label="Feedback loop: experiment outcomes feed back as priors for the next scan">
683            <span class="pl-to">into 01 &middot; Intake</span>
684            <span class="pl-from">from 07 &middot; Output</span>
685            <div class="pl-bracket"></div>
686            <span class="pl-arrow"></span>
687            <span class="pl-dot"></span>
688            <span class="pl-tag" data-stage="loop" role="button" tabindex="0" aria-haspopup="dialog"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12a9 9 0 0 1 15-6.7L21 8"/><path d="M21 3v5h-5"/><path d="M21 12a9 9 0 0 1-15 6.7L3 16"/><path d="M3 21v-5h5"/></svg>Outcomes feed back as priors for the next scan</span>
689          </div>
690          <div class="pipe-foot"><span><b>A few minutes</b> &middot; end to end</span><span>It produces the backlog &middot; <b>it never runs your test</b></span></div>
691        </div>
692
693        <p class="sig-pipe-more"><a href="https://docs.abtestly.com/signals/overview" target="_blank" rel="noopener noreferrer">Read how each stage works in the docs &rarr;</a></p>
694
695        <div class="hero-cta" style="justify-content:center; margin-top:24px;">
696          <a class="btn btn-secondary btn-lg" href="https://chromewebstore.google.com/detail/abtestly/lneegoiabmnanlpehinpnhndihfigfcl" target="_blank" rel="noopener noreferrer">Add to Chrome</a>
697        </div>
698        <p class="sig-pipe-more" style="margin-top:12px;">The browser extension captures a page from your own logged in session &middot; free during beta, within your monthly scan allowance.</p>
699      </div>
700    </section>
701
702    <!-- =================== 3 · WHY IT IS DIFFERENT =================== -->
703    <section class="section" style="border-top:1px solid var(--hair);">
704      <div class="container">
705        <div class="section-head center sig-reveal">
706          <span class="eyebrow" style="display:inline-flex;">why it is different</span>
707          <h2>Three things a best practice checklist will not do.</h2>
708          <p>Anyone can print a list of ideas. The work is deciding what is worth your traffic, and being honest about how sure it is.</p>
709        </div>
710
711        <div class="sig-diff">
712          <div class="sig-diff-item sig-reveal">
713            <span class="sig-diff-node"></span>
714            <div class="sig-diff-term">
715              <span class="k">Behavioral grading</span>
716              <span class="tag">The two signal rule</span>
717            </div>
718            <div class="sig-diff-body">
719              <h3>A structural finding reaches your backlog, but it is never Test ready on its own.</h3>
720              <p>Signals grades on <b>two signals</b>, a structural finding on the page plus evidence that agrees with it: a behavioral pattern in your GA4, or customer voice you paste into your brand context. A structural finding alone leaves an idea labeled Needs evidence, however good it looks. A second signal puts it in contention, and it reaches <b>Test ready</b> only once its score also clears the threshold for its evidence tier; short of that it reads Needs evidence or Below threshold. A small mobile CTA is a flagged finding on its own, and a confirmed issue once your mobile conversion rate agrees. The <a href="https://docs.abtestly.com/signals/evidence-contract" target="_blank" rel="noopener noreferrer">evidence contract</a> lists every threshold, and the <a href="https://docs.abtestly.com/signals/read-a-scan" target="_blank" rel="noopener noreferrer">idea board guide</a> shows the badges in place.</p>
721            </div>
722          </div>
723          <div class="sig-diff-item sig-reveal">
724            <span class="sig-diff-node"></span>
725            <div class="sig-diff-term">
726              <span class="k">Adversarial falsification</span>
727              <span class="tag">The second pass</span>
728            </div>
729            <div class="sig-diff-body">
730              <h3>Before a test slot is spent, the agent argues against itself.</h3>
731              <p>A second pass names the strongest <b>failure mode</b>
731, the likeliest confounder, the alternative explanation, and the <b>single test that would tell them apart</b>. When it comes back with one, you get the argument against the recommendation, attached to the recommendation.</p>
732            </div>
733          </div>
734          <div class="sig-diff-item sig-reveal">
735            <span class="sig-diff-node"></span>
736            <div class="sig-diff-term">
737              <span class="k">The closed loop</span>
738              <span class="tag">It owns both ends</span>
739            </div>
740            <div class="sig-diff-body">
741              <h3>A standalone audit guesses once. Signals hears back.</h3>
742              <p>Because Signals runs inside ABTestly, the audit and the test engine are one system. Once a linked experiment concludes, its outcome feeds back <b>automatically</b> as a prior for the next scan of that domain. The learning is in context, not model training.</p>
743            </div>
744          </div>
745        </div>
746      </div>
747    </section>
748
749    <!-- =================== 4 · HONESTY FLOOR =================== -->
750    <section class="section" style="border-top:1px solid var(--hair); background: var(--surface);">
751      <div class="container">
752        <div class="sig-floor">
753          <div class="sig-floor-head sig-reveal">
754            <span class="eyebrow">the honesty floor</span>
755            <h2>Test ready is earned, never assumed.</h2>
756            <p>The point of Signals is telling you what it does not know. These behaviors are built in, not bolted on.</p>
757          </div>
758          <div class="sig-floor-list">
759            <div class="sig-floor-item sig-reveal">
760              <span class="sig-floor-n">01</span>
761              <div class="sig-floor-body">
762                <h3>The qualification gate</h3>
763                <p>It tells you when your traffic <b>cannot reach significance</b>, and refuses to fake confidence about it.</p>
764              </div>
765            </div>
766            <div class="sig-floor-item sig-reveal">
767              <span class="sig-floor-n">02</span>
768              <div class="sig-floor-body">
769                <h3>Evidence tier, set per idea</h3>
770                <p>Every hypothesis carries one of <b>four evidence tiers</b>: Verified, Full evidence, Structural plus qualitative, or Structural. The tier is derived from which evidence questions were credited on that idea, so two ideas from the same scan land in different tiers when your GA4 speaks to one and not the other.</p>
771              </div>
772            </div>
773            <div class="sig-floor-item sig-reveal">
774              <span class="sig-floor-n">03</span>
775              <div class="sig-floor-body">
776                <h3>It never invents a number</h3>
777                <p>Thin evidence is <b>labeled, not inflated</b>. When a claim rests on page structure alone, Signals says so and names the cheapest action that would confirm it.</p>
778              </div>
779            </div>
780          </div>
781        </div>
782        <div class="vs-table-wrap sig-reveal">
783          <table class="vs-table">
784          <caption class="sr-only">What earns each evidence tier, the PXL score it needs for Test ready, and the highest score that tier can reach</caption>
785          <thead>
786            <tr><th>Evidence tier</th><th>What earns it</th><th>Score it needs</th><th>Highest it can reach</th></tr>
787          </thead>
788          <tbody>
789            <tr><th scope="row">Verified</th><td>Your GA4 and a first party heatmap both credited</td><td>9 or more</td><td>10, or 12 with customer voice</td></tr>
790            <tr><th scope="row">Full evidence</th><td>Your GA4 credited</td><td>7 or more</td><td>8, or 10 with customer voice</td></tr>
791            <tr><th scope="row">Structural + qualitative</th><td>Customer voice credited, no analytics</td><td>6 or more</td><td>8</td></tr>
792            <tr><th scope="row">Structural</th><td>Page structure alone</td><td>No score reaches Test ready</td><td>6</td></tr>
793          </tbody>
794          </table>
795        </div>
796
797        <div class="sig-note sig-reveal">
798          <span class="sig-note-k">Both, not either</span>
799          <p>Clearing the score is necessary and not sufficient. An idea reads Test ready only when a second independent signal agrees with the structural finding <b>and</b> the score clears its tier. Miss either one and it reads Needs evidence, with the board naming the specific thing that would move it, down to "Connect GA4 so the scan can check this idea against funnel data."</p>
800        </div>
801      </div>
802    </section>
803
804    <!-- =================== 4b · WHAT COMES BACK =================== -->
805    <section class="section" style="border-top:1px solid var(--hair);">
806      <div class="container">
807        <div class="section-head center sig-reveal">
808          <span class="eyebrow" style="display:inline-flex;">the output</span>
809          <h2>What one idea looks like <em class="grad">when it comes back.</em></h2>
810          <p>Not a paragraph of advice. Every hypothesis in the backlog carries the same structured fields, so two ideas from different scans can be compared without rereading them.</p>
811          <p>To see these fields filled in, read <a href="/signals-sample-scan">an illustrated scan of a product page</a>.</p>
812        </div>
813
814        <div class="vs-table-wrap sig-reveal">
815          <table class="vs-table">
816            <caption class="sr-only">The fields carried by every hypothesis Signals returns</caption>
817            <thead>
818              <tr><th>On every idea</th><th>What it holds</th></tr>
819            </thead>
820            <tbody>
821              <tr><th scope="row">Observation and proposed change</th><td>What it found on the page, and the specific change to make. One of five CRO pillars: Trust and Credibility, Offer Clarity, Friction, Urgency and Motivation, or Page Flow and Hierarchy</td></tr>
822              <tr><th scope="row">Mechanism</th><td>Why the change should work, tagged with up to four named frameworks rather than left as intuition</td></tr>
823              <tr><th scope="row">Research citation</th><td>Every idea carries one. None ship uncited</td></tr>
824              <tr><th scope="row">Expected lift and effort</th><td>Effort is Low, Medium or High, and it feeds the rank, so a cheap idea is not buried under an expensive one</td></tr>
825              <tr><th scope="row">Statistical note</th><td>What the numbers behind the idea do and do not support</td></tr>
826              <tr><th scope="row">Tracking spec</th><td>The events to record so the test can actually be measured</td></tr>
827              <tr><th scope="row">Interaction spec</th><td>How the variant should behave once it is built</td></tr>
828              <tr><th scope="row">Data source</th><td>Where the evidence came from, which is what sets the evidence tier</td></tr>
829            </tbody>
830          </table>
831        </div>
832
833        <div class="sig-note sig-reveal">
834          <span class="sig-note-k">Conditional</span>
835          <p>A recommended run time in weeks arrives when your traffic supports computing one, capped at eight. Customer voice appears on an idea only where your brand context spoke to it. And when the falsification pass returns, four more fields come with it: the strongest failure mode, the likeliest confou
835nder, the alternative explanation, and the single test that would tell them apart.</p>
836        </div>
837      </div>
838    </section>
839
840    <!-- =================== 5 · THE CLOSED LOOP =================== -->
841    <section class="section" style="border-top:1px solid var(--hair);">
842      <div class="container">
843        <div class="section-head center sig-reveal">
844          <span class="eyebrow" style="display:inline-flex;">the learning loop</span>
845          <h2>Every linked experiment that concludes <em class="grad">sharpens the next scan.</em></h2>
846          <p>Signals does not hand off a backlog and forget it. Ship a hypothesis in ABTestly, and when the experiment concludes its result returns as a prior for the next scan. Nothing to log by hand.</p>
847        </div>
848
849        <div class="sig-loop sig-reveal">
850          <span class="sig-loop-node">Scan the page</span>
851          <span class="sig-loop-arrow">&rarr;</span>
852          <span class="sig-loop-node">Ranked backlog</span>
853          <span class="sig-loop-arrow">&rarr;</span>
854          <span class="sig-loop-node">Ship the test in ABTestly</span>
855          <span class="sig-loop-arrow">&rarr;</span>
856          <span class="sig-loop-node">Exact ledger verdict</span>
857          <span class="sig-loop-arrow">&rarr;</span>
858          <span class="sig-loop-node sig-loop-node--accent">Outcome returns as a prior</span>
859          <span class="sig-loop-arrow sig-loop-arrow--back">&#8631;</span>
860        </div>
861
862        <div class="sig-note sig-reveal">
863          <span class="sig-note-k">Note</span>
864          <p>Signals runs on the Anthropic commercial API, whose terms do not use your data to train models. So this is a data feedback loop, not model fine tuning. Signals produces the backlog and the test plan; you stay in control of what ships.</p>
865        </div>
866      </div>
867    </section>
868
869    <!-- =================== 5b · WHAT IT NEEDS, WHAT IT CANNOT SEE =================== -->
870    <section class="section" style="border-top:1px solid var(--hair); background: var(--surface);">
871      <div class="container">
872        <div class="sig-floor">
873          <div class="sig-floor-head sig-reveal">
874            <span class="eyebrow">before you point it at a page</span>
875            <h2>What it needs from you, and what it cannot see.</h2>
876            <p>None of this is a caveat buried in the docs. It changes what a scan can return, so it belongs next to the promise.</p>
877          </div>
878          <div class="sig-floor-list">
879            <div class="sig-floor-item sig-reveal">
880              <span class="sig-floor-n">01</span>
881              <div class="sig-floor-body">
882                <h3>GA4, or a lower ceiling</h3>
883                <p>Without analytics connected, <b>no idea can reach Verified or Full evidence</b>. The best available is Structural plus qualitative, and only when you paste customer voice into your brand context. Page structure on its own has no threshold to clear, so it never reaches Test ready however good the finding looks.</p>
884              </div>
885            </div>
886            <div class="sig-floor-item sig-reveal">
887              <span class="sig-floor-n">02</span>
888              <div class="sig-floor-body">
889                <h3>The GA4 it reads is the last 90 days</h3>
890                <p>A scan pulls a <b>90 day window</b>. If you redesigned the page inside that window, some of the behaviour being weighed belongs to the design you replaced. Signals cannot detect that for you, and it is worth knowing before you act on a funnel number.</p>
891              </div>
892            </div>
893            <div class="sig-floor-item sig-reveal">
894              <span class="sig-floor-n">03</span>
895              <div class="sig-floor-body">
896                <h3>The counter argument can be absent</h3>
897                <p>Every idea goes through the falsification pass, and <b>the argument arrives attached when the pass returns one</b>. When the pass cannot complete, the idea still reaches you without it rather than being held back. So read a missing argument as missing, not as an idea that survived one.</p>
898              </div>
899            </div>
900          </div>
901        </div>
902      </div>
903    </section>
904
905    <!-- =================== 6 · PRICING (free in Beta, priced after) =================== -->
906    <section class="section sig-pricing" style="border-top:1px solid var(--hair); background: var(--surface);">
907      <div class="container">
908        <div class="section-head center sig-reveal">
909          <span class="eyebrow" style="display:inline-flex;">pricing</span>
910          <h2>Signals is free for every paid plan, <em class="grad">while it is in Beta.</em></h2>
911          <p>No extra charge and nothing to switch on. If your <a href="/pricing">ABTestly plan</a> is paid, Signals runs today at no cost, within a monthly scan allowance.</p>
912        </div>
913
914        <div class="sig-note sig-reveal" style="margin-top: var(--s-6);">
915          <span class="sig-note-k">During Beta</span>
916          <p>Each account gets a monthly scan allowance: 5 scans on Starter, 25 on Pro, 100 on Business and 100 on Enterprise. Every site in the account draws on it, and it resets on the 1st of each month (UTC). Unused scans do not carry over. A scan that fails does not count. When the allowance runs out, new scans are refused until it resets or you move to a plan with a larger one.</p>
917        </div>
918
919        <div class="sig-note sig-reveal" style="margin-top: var(--s-4);">
920          <span class="sig-note-k">After Beta</span>
921          <p>Signals will be priced by scans per month. One scan is one full audit run. These prices are not live yet, Signals stays free until Beta ends.</p>
922        </div>
923
924        <div class="plan-grid sig-reveal">
925          <article class="plan">
926            <div class="plan-name">Lite</div>
927            <div class="plan-price"><b>$49</b><span class="per">/mo</span></div>
928            <p class="plan-desc">5 scans per month &middot; page heatmaps included.</p>
929          </article>
930          <article class="plan">
931            <div class="plan-name">Growth</div>
932            <div class="plan-price"><b>$149</b><span class="per">/mo</span></div>
933            <p class="plan-desc">25 scans per month &middot; page heatmaps included.</p>
934          </article>
935          <article class="plan">
936            <div class="plan-name">Scale</div>
937            <div class="plan-price"><b>$399</b><span class="per">/mo</span></div>
938            <p class="plan-desc">100 scans per month &middot; page heatmaps included.</p>
939          </article>
940        </div>
941
942        <div class="sig-note sig-reveal" style="margin-top: var(--s-6);">
943          <span class="sig-note-k">Heatmaps</span>
944          <p>Experiment heatmaps are live and included with Pro and Business at no extra cost, covering the pages your tests run on. Signals reads that behaviour as evidence when it writes hypotheses, including on pages where the test has already finished. On Starter, where experiment heatmaps are not included, Signals brings heatmaps with it. The heatmap corroborates GA4 funnel data rather than replacing it, so it counts toward an idea's evidence tier only on a scan where GA4 also contributed.</p>
945        </div>
946      </div>
947    </section>
948
949    <!-- =================== 7 · CLOSING CTA (dark band) =================== -->
950    <div class="container">
951      <section class="cta-band">
952        <span class="eyebrow" style="margin-bottom:var(--s-4); display:inline-flex">see it on your site</span>
953        <h2 style="max-width:22ch; margin-left:auto; margin-right:auto;">See what Signals finds on your own site.</h2>
954        <p style="max-width:52ch; margin:var(--s-4) auto 0; color:rgba(255,255,255,0.72);">Point it at a page, connect GA4, and read the backlog it returns. Signals is free while it is in Beta, on any paid plan, within a monthly scan allowance.</p>
955        <div class="hero-cta" style="justify-content:center; margin:var(--s-7) auto 0;">
956          <a class="btn btn-primary btn-lg" href="https://app.abtestly.com/sign-up">Start your free trial <span class="arrow" aria-hidden="true">&rarr;</span></a>
957          <a class="btn btn-secondary btn-lg" href="https://docs.abtestly.com/signals/overview" target="_blank" rel="noopener noreferrer">Read the docs</a>
958          <a class="btn btn-secondary btn-lg" href="/switch-one-experiment">Switch one experiment</a>
959        </div>
960      </section>
961    </div>
962
963  </main>
964
965  <!-- Stage detail modal (opened by the pipeline stage cards) -->
966  <div class="pmodal" hidden>
967    <div class="pmodal-scrim" data-close></div>
968    <div class="pmodal-panel" role="dialog" aria-modal="true" aria-labelledby="pmodal-title" tabindex="-1">
969      <button class="pmodal-x" data-close aria-label="Close"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M18 6L6 18M6 6l12 12"/></svg></button>
970      <div class="pmodal-head">
971        <span class="pmodal-ic"></span>
972        <div><span class="pmodal-eyebrow"></span><h3 class="pmodal-title" id="pmodal-title"></h3></div>
973      </div>
974      <p class="pmodal-lead"></p>
975      <ul class="pmodal-list"></ul>
976    </div>
977  </div>
978
979  <!-- =================== FOOTER =================== -->
980    <footer class="footer">
981    <div class="container">
982      <div class="footer-inner">
983        <div>
984          <a class="brand" href="/" aria-label="ABTestly home">
985            <svg class="brand-mark" viewBox="0 0 220 92" aria-hidden="true" focusable="false"><rect class="brand-mark-top" x="0" y="0" width="132" height="34" rx="17"/><path class="brand-mark-win" d="M17 58 A17 17 0 0 0 17 92 L196 92 L208 58 Z"/></svg><span class="brand-word">ABTestly</span>
986          </a>
987          <p class="footer-tag">A/B testing for teams who ship experiments in code.</p>
988        </div>
989        <div>
990          <h2>Product</h2>
991          <ul role="list">
992            <li><a href="/#product">Overview</a></li>
993            <li><a href="/code-first-ab-testing">Code first testing</a></li>
994            <li><a href="/revenue-ab-testing">Revenue testing</a></li>
995            <li><a href="/signals">Signals</a></li>
996            <li><a href="/pricing">Pricing</a></li>
997            <li><a href="https://app.abtestly.com/sign-up">Start free trial</a></li>
998          </ul>
999        </div>
1000        <div>
1001          <h2>Developers</h2>
1002          <ul role="list">
1003            <li><a href="/browser-ab-testing-runtime">Browser runtime</a></li>
1004            <li><a href="/#code-check">Code check</a></li>
1005            <li><a href="https://docs.abtestly.com/developer/window-abtestly-api" target="_blank" rel="noopener noreferrer">Browser API</a></li>
1006            <li><a href="https://docs.abtestly.com/preview/dev-debugger" target="_blank" rel="noopener noreferrer">Dev debugger</a></li>
1007            <li><a href="/ab-test-calculator">A/B test calculator</a></li>
1008          </ul>
1009        </div>
1010        <div>
1011          <h2>Methodology</h2>
1012          <ul role="list">
1013            <li><a href="/#how-it-works">How it works</a></li>
1014            <li><a href="https://docs.abtestly.com/results/exact-ledger" target="_blank" rel="noopener noreferrer">Exact ledger</a></li>
1015            <li><a href="https://docs.abtestly.com/methodology/overview" target="_blank" rel="noopener noreferrer">Guides</a></li>
1016            <li><a href="/#faq">FAQ</a></li>
1017            <li><a href="/experiment-walkthrough">One experiment, built</a></li>
1018            <li><a href="/evaluate-one-experiment">Evaluate one experiment</a></li>
1019          </ul>
1020        </div>
1021        <div>
1022          <h2>Company</h2>
1023          <ul role="list">
1024            <li><a href="/terms">Terms</a></li>
1025            <li><a href="/privacy">Privacy</a></li>
1026            <li><button class="footer-link" type="button" data-consent-settings aria-haspopup="dialog">Cookie settings</button></li>
1027            <li><a href="/refund">Refunds</a></li>
1028            <li><a href="/cdn-cgi/l/email-protection#82eae7eeeeedc2e3e0f6e7f1f6eefbace1edef">Contact</a></li>
1029          </ul>
1030        </div>
1031      </div>
1032
1033      <!-- The comparison pages sit in a wrapped strip rather than a column.
1034           As a column they were 14 long against neighbours of 4 to 7, which
1035           made the whole footer as tall as that one list and left everything
1036           beside it empty. A row uses the width instead, and the next
1037           comparison page joins it rather than making the footer taller. -->
1038      <div class="footer-strip">
1039        <h2>Compare and switch</h2>
1040        <ul role="list">
1041          <li><a href="/compare" class="footer-strip-lead">All comparisons</a></li>
1042          <li><a href="/optimizely-alternative">Optimizely alternative</a></li>
1043          <li><a href="/vwo-alternative">VWO alternative</a></li>
1044          <li><a href="/abtasty-alternative">AB Tasty alternative</a></li>
1045          <li><a href="/convert-alternative">Convert alternative</a></li>
1046          <li><a href="/posthog-vs-abtestly">PostHog vs ABTestly</a></li>
1047          <li><a href="/optimizely-pricing">Optimizely pricing</a></li>
1048          <li><a href="/vwo-pricing">VWO pricing</a></li>
1049          <li><a href="/abtasty-pricing">AB Tasty pricing</a></li>
1050          <li><a href="/convert-pricing">Convert pricing</a></li>
1051          <li><a href="/vwo-vs-optimizely">VWO vs Optimizely</a></li>
1052          <li><a href="/abtestly-vs-optimizely-vwo-convert">Four tools compared</a></li>
1053          <li><a href="/switch-one-experiment">Switch one experiment</a></li>
1054        </ul>
1055      </div>
1056      <div class="container footer-bottom">
1057        <span>CODE FIRST / EDGE SERVED / EXACT RESULTS</span>
1058        <span>Built for CRO developers and technical teams.</span>
1059      </div>
1060    </div>
1061  </footer>
vendor: 112 bytes, lines 1061-1063
1061
1062
1063  <script data-cfasync="false" src="/cdn-cgi/scripts/5c5dd728/cloudflare-static/email-decode.min.js"></script>
1063<script>
1064  (function () {
1065    var IC = {
1066      intake: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M12 3v18M3 8h6M3 16h6M15 8h6M15 16h6"/></svg>',
1067      capture: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="4" width="18" height="14" rx="2"/><path d="M3 8h18M8 21h8"/></svg>',
1068      behaviour: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M3 3v18h18"/><rect x="7" y="11" width="3" height="6"/><rect x="13" y="7" width="3" height="10"/></svg>',
1069      payload: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M4 7h6l6 5"/><path d="M4 17h6l6-5"/><circle cx="18" cy="12" r="2" fill="currentColor" stroke="none"/></svg>',
1070      generation: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M12 3l2.4 4.9 5.4.8-3.9 3.8.9 5.4L12 15.6l-4.8 2.5.9-5.4L4.2 8.7l5.4-.8z"/></svg>',
1071      falsification: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M12 9v4M12 17h.01"/><path d="M10.3 3.9 2 18a2 2 0 0 0 1.7 3h16.6a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0z"/></svg>',
1072      output: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M5 4h11l3 3v13H5z"/><path d="M9 9h6M9 13h6M9 17h4"/></svg>',
1073      loop: '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.9" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12a9 9 0 0 1 15-6.7L21 8"/><path d="M21 3v5h-5"/><path d="M21 12a9 9 0 0 1-15 6.7L3 16"/><path d="M3 21v-5h5"/></svg>'
1074    };
1075    var NOTE_IC = '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><path d="M12 16v-4M12 8h.01"/></svg>';
1076
1077    var STAGES = {
1078      "1": {
1079        eyebrow: "01 · Intake", title: "Site & business context", icon: IC.intake,
1080        lead: "You give ABTestly a page URL plus optional business context, and what you connect decides how far the audit can go. Connect neither GA4 nor customer voice and every idea stays in the Structural tier; each source you add raises the tier an idea it speaks to can reach.",
1081        points: [
1082          "<b>The page and context:</b> the URL you want audited, plus optional context like niche, average order value, primary goal and device split.",
1083          "<b>The browser extension</b> captures the page from your own logged in session, so the scan reads what a real visitor actually sees.",
1084          "<b>Connect GA4</b> for the behavioral signal, or paste customer voice into your brand context for the qualitative one. With neither, ideas stay in the Structural tier and never reach Test ready; with either, an idea that source speaks to can promote.",
1085          "<b>It sets what a scan can read</b>, and checks the page is on your own site before it runs. The evidence tier is then set idea by idea, from which evidence questions were credited on each one."
1086        ]
1087      },
1088      "2": {
1089        eyebrow: "02 · Capture", title: "DOM, renders, funnel walks", icon: IC.capture,
1090        lead: "The ABTestly browser extension captures the page from your own logged in session, so the model reads the real thing a shopper sees, never a bare URL.",
1091        points: [
1092          "<b>20 plus DOM signals:</b> page type, framework, heading hierarchy, form fields, CTA inventory, schema markup, review counts, trust badges, image alt coverage and HTTPS.",
1093          "<b>Three screenshots</b> on desktop, mobile and a throttled mobile view, read by a vision pass and reconciled against the DOM.",
1094          "<b>Funnel walks</b> let you capture several steps of a journey, so the scan sees more than a single page."
1095        ],
1096        note: { text: "It captures pages from your own logged in session. It never submits payment and never tries to evade a site's bot protection." }
1097      },
1098      "3": {
1099        eyebrow: "03 · Behaviour", title: "GA4 funnel and drop off", icon: IC.behaviour,
1100        lead: "If you connected GA4, the agent can read where real visitors drop off, the behavioral half of the two signal rule.",
1101        points: [
1102          "From GA4: funnel drop off, conversion by device, and revenue by channel, plus new versus returning and your top pages.",
1103          "This is what lets a structural finding become actionable. A DOM observation promotes once a second signal agrees with it: behavior here, or customer voice you paste into your brand context."
1104        ]
1105      },
1106      "4": {
1107        eyebrow: "04 · Payload", title: "Multimodal payload assembled", icon: IC.payload,
1108        lead: "Everything captured so far is assembled into one multimodal prompt, so the model reasons over real evidence, never a bare URL.",
1109        points: [
1110          "<b>Three image blocks:</b> the desktop, mobile and throttled mobile renders.",
1111          "<b>One structured text block:</b> business context, DOM signals, the live GA4 snapshot, and prior tested outcomes on this domain fed back automatically.",
1112          "It is framed as evidence of substance, not a list of claims, so the model weighs what is actually there."
1113        ]
1114      },
1115      "5": {
1116        eyebrow: "05 · Generation", title: "Grounded hypotheses", icon: IC.generation,
1117        lead: "The model proposes test ideas that address your stated problem, each grounded in a mechanism and gated on evidence. AI evaluates the evidence. ABTestly computes the score.",
1118        points: [
1119          "<b>Structured fields</b> on every hypothesis: observation, the change, the behavioral mechanism, expected lift, a <b>PXL score</b> with the answer behind every point, effort, a research citation, data source, statistical note, tracking spec and interaction spec, plus an opportunity size range and a recommended run time when the scan can support them.",
1120          "<b>The model answers eight yes or no questions</b> about the idea, each with a short rationale. ABTestly turns those answers into the score, the evidence tier and the readiness badge, and overrides any answer the evidence on that scan cannot support.",
1121          "Tagged to one of <b>five CRO pillars:</b> Trust and Credibility, Offer Clarity, Friction, Urgency and Motivation, Page Flow and Hierarchy.",
1122          "Framed through a named model: Fogg, Cialdini, prospect theory, cognitive load, Hick's Law or Jobs to be Done.",
1123          "<b>The two signal gate:</b> thin evidence ideas are not dropped. They are surfaced and labeled with the single cheapest action that would validate them."
1124        ]
1125      },
1126      "6": {
1127        eyebrow: "06 · Falsification", title: "Argued against itself", icon: IC.falsification, neg: true,
1128        lead: "Before a recommendation reaches you, a second pass tries to break it, and the argument it makes arrives attached to the idea. If that pass cannot complete, the idea still reaches you without one.",
1129        points: [
1130          "It names the strongest <b>failure mode</b>, the most likely <b>confounder</b>, an <b>alternative explanation</b> for the same evidence, and the <b>discriminating test</b> that would tell them apart.",
1131          "When the pass comes back with one, you get the argument against the recommendation, attached to the recommendation itself."
1132        ],
1133        note: { text: "It runs as an adversarial second pass over the scan's generated ideas, before they reach your backlog." }
1134      },
1135      "7": {
1136        eyebrow: "07 · Output", title: "Structured hypotheses, ranked", icon: IC.output,
1137        lead: "The result is a prioritized backlog you can act on, each item carrying everything needed to run it well.",
1138        points: [
1139          "Ranked by <b>PXL score</b>, then by how much evidence backs the idea; ties break on effort, cheapest first. Each card reads its score against <b>that scan's own maximum</b>, so a point the scan could never have awarded is never in the denominator.",
1140          "Every hypothesis carries its <b>Evidence tier</b>, effort and a tracking spec for what to instrument, plus an opportunity size range and a recommended run time when the scan can support them.",
1141          "<b>Four evidence tiers:</b> Verified, Full evidence, Structural plus qualitative, and Structural. They tell you how much weight each recommendation can bear."
1142        ],
1143        note: { text: "It produces the backlog and the test plan. It never runs your experiment. You stay in control of what ships." }
1144      },
1145      loop: {
1146        eyebrow: "The learning loop", title: "How it gets context over time", icon: IC.loop,
1147        lead: "Once a linked experiment concludes, its outcome feeds back automatically into the next scan of that domain. The Anthropic commercial API does not use your data to train models; the learning is in context, so past results become priors in the next scan's payload.",
1148        points: [
1149          "<b>Automatic outcomes:</b> when a linked experiment concludes, its result, won, lost, or inconclusive with the actual lift, feeds back as a prior for the next scan on that domain.",
1150          "<b>Prior scan memory:</b> it confirms what looks resolved, evolves what did not land, and avoids proposing the same thing again."
1151        ],
1152        note: { text: "Submitted data is processed via the Anthropic commercial API and is not used to train models, so this is a data feedback loop, not model fine tuning." }
1153      }
1154    };
1155
1156    var modal = document.querySelector('.pmodal');
1157    var panel = modal.querySelector('.pmodal-panel');
1158    var icEl = modal.querySelector('.pmodal-ic');
1159    var eyebrowEl = modal.querySelector('.pmodal-eyebrow');
1160    var titleEl = modal.querySelector('.pmodal-title');
1161    var leadEl = modal.querySelector('.pmodal-lead');
1162    var listEl = modal.querySelector('.pmodal-list');
1163    var lastFocus = null;
1164
1165    function open(key) {
1166      var s = STAGES[key];
1167      if (!s) return;
1168      lastFocus = document.activeElement;
1169
1170      icEl.className = 'pmodal-ic' + (s.neg ? ' neg' : '');
1171      icEl.innerHTML = s.icon;
1172      eyebrowEl.textContent = s.eyebrow;
1173      titleEl.textContent = s.title;
1174      leadEl.textContent = s.lead;
1175      listEl.innerHTML = s.points.map(function (p) {
1176        return '<li><span>' + p + '</span></li>';
1177      }).join('');
1178
1179      var existing = panel.querySelector('.pmodal-note');
1180      if (existing) existing.remove();
1181      if (s.note) {
1182        var note = document.createElement('div');
1183        note.className = 'pmodal-note' + (s.note.warn ? ' warn' : '');
1184        note.innerHTML = NOTE_IC + '<span></span>';
1185        note.querySelector('span').textContent = s.note.text;
1186        panel.appendChild(note);
1187      }
1188
1189      modal.hidden = false;
1190      document.body.style.overflow = 'hidden';
1191      panel.focus();
1192    }
1193
1194    function close() {
1195      modal.hidden = true;
1196      document.body.style.overflow = '';
1197      if (lastFocus && typeof lastFocus.focus === 'function') lastFocus.focus();
1198    }
1199
1200    var triggers = document.querySelectorAll('[data-stage]');
1201    for (var i = 0; i < triggers.length; i++) {
1202      (function (el) {
1203        el.addEventListener('click', function () { open(el.getAttribute('data-stage')); });
1204        el.addEventListener('keydown', function (e) {
1205          if (e.key === 'Enter' || e.key === ' ' || e.key === 'Spacebar') {
1206            e.preventDefault();
1207            open(el.getAttribute('data-stage'));
1208          }
1209        });
1210      })(triggers[i]);
1211    }
1212
1213    var closers = modal.querySelectorAll('[data-close]');
1214    for (var j = 0; j < closers.length; j++) {
1215      closers[j].addEventListener('click', close);
1216    }
1217
1218    document.addEventListener('keydown', function (e) {
1219      if (!modal.hidden && e.key === 'Escape') close();
1220    });
1221  })();
1222  </script>
1222
1223
1224  
1224<script src="/chat-widget.js" defer></script>
vendor: 1 bytes, line 1224
1224
1225<script type="module" src="https://static.cloudflareinsights.com/beacon.min.js/v31edd6df95cf4e85bb4c19e7a9bdbcba1788362987495" integrity="sha512-iIg7k2xntmwu6/uSb5tpc/hySgZc4eoL31yB29W6tJFo2akwjPWcEqnCEdJvGexCL0KEQwVYv5BlowfhVz26hg==" data-cf-beacon='{"version":"2024.11.0","token":"570edb9dca1c47c9a1c87507836899b9","r":1,"spa":2}' crossorigin="anonymous"></script>
1225
1226</body>
1227</html>

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