PageSourceSearch

https://talkify.nz/blog

html talkify.nz collected 2026-10-02 00:38:49 UTC 260,842 bytes, 6,876 lines download raw bytes

1<!doctype html>
2<html lang="en">
3<head>
4    <meta charset="utf-8">
5    <meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover">
6    
6<script>
7        /*
8         * No-flash theme: a visitor's own choice wins, otherwise light.
9         *
10         * We deliberately do NOT follow prefers-color-scheme here. Most people
11         * run their OS in dark mode, so honouring it would mean the light site
12         * is the one almost nobody sees. The toggle in the nav still works and
13         * still persists, so anyone who prefers dark is one click away.
14         */
15        (function () {
16            try {
17                var stored = localStorage.getItem('talkify-theme');
18                document.documentElement.setAttribute('data-theme', stored === 'dark' ? 'dark' : 'light');
19            } catch (e) {
20                document.documentElement.setAttribute('data-theme', 'light');
21            }
22            /* Scripting is on, so .r may hide its block until the observer
23               reveals it. Without this class nothing is ever hidden, which is
24               what a visitor with no JS (or a crawler) sees. */
25            document.documentElement.classList.add('js');
26        })();
27    </script>
27
28    <title>The Talkify Journal | AI Phone Agent Insights for NZ Businesses</title>
29    <meta name="description"
30          content="Field notes, real numbers, and plain-English playbooks on AI phone agents, missed-call recovery, after-hours reception, and call automation for New Zealand small business.">
31
32    
33        <link rel="canonical" href="https://talkify.nz/blog">
34                    <link rel="icon" type="image/x-icon" href="/favicon.ico">
35    <link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
36    <link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
37    <link rel="apple-touch-icon" sizes="180x180" href="/media/branding/brand/app-icon-180.png">
38    <link rel="manifest" href="/site.webmanifest">
39    
40    <meta name="theme-color" content="#318abe">
41
42    <meta property="og:type" content="website">
43    <meta property="og:url" content="https://talkify.nz/blog">
44    <meta property="og:site_name" content="Talkify">
45    <meta property="og:title" content="The Talkify Journal | AI Phone Agent Insights for NZ Businesses">
46    <meta property="og:description"
47          content="Field notes, real numbers, and plain-English playbooks on AI phone agents, missed-call recovery, after-hours reception, and call automation for New Zealand small business.">
48        <meta property="og:image" content="https://talkify.nz/media/share/blog.jpg">
49    
50    <meta property="og:image:width" content="1200">
51    <meta property="og:image:height" content="630">
52    <meta property="og:image:type" content="image/jpeg">
53    <meta property="og:image:alt"
54          content="Talkify, AI Phone Agent for New Zealand businesses.">
55    
56    <meta property="og:locale" content="en_NZ">
57
58    <meta name="twitter:card" content="summary_large_image">
59    <meta name="twitter:title" content="The Talkify Journal | AI Phone Agent Insights for NZ Businesses">
60    <meta name="twitter:description"
61          content="Field notes, real numbers, and plain-English playbooks on AI phone agents, missed-call recovery, after-hours reception, and call automation for New Zealand small business.">
62    <meta name="twitter:image" content="https://talkify.nz/media/share/blog.jpg">
63    <meta name="facebook-domain-verification" content="ic2puw1bkz233rscxrhcl0qol7suu1"/>
64    
65        
65<script
66        type="application/ld+json">{"@context":"https://schema.org","@graph":[{"@type":["Organization","LocalBusiness"],"@id":"https://talkify.nz#organization","name":"Talkify","url":"https://talkify.nz","logo":"https://talkify.nz/media/branding/talkify-face-gradient-512.png","image":"https://talkify.nz/media/meta-image.jpg","description":"AI Phone Agent for New Zealand and Australian businesses. 24/7 AI receptionist, smart booking, lead qualification, and intelligent call handling. Business agents from $129 per month, Personal Assistant from $89.","telephone":"+64-800-002-967","email":"[email protected]","priceRange":"$$","areaServed":[{"@type":"Country","name":"New Zealand"},{"@type":"Country","name":"Australia"}],"address":{"@type":"PostalAddress","addressCountry":"NZ","addressRegion":"Canterbury","addressLocality":"Christchurch"},"contactPoint":[{"@type":"ContactPoint","telephone":"+64-800-002-967","contactType":"sales","areaServed":"NZ","availableLanguage":["English","te reo Māori"]},{"@type":"ContactPoint","telephone":"+64-3-242-1262","contactType":"demo","areaServed":["NZ","AU"]},{"@type":"ContactPoint","telephone":"+611300852142","contactType":"sales","areaServed":"AU","availableLanguage":["English"]}],"foundingDate":"2024","foundingLocation":{"@type":"Place","address":{"@type":"PostalAddress","addressCountry":"NZ","addressLocality":"Christchurch"}},"parentOrganization":{"@type":"Organization","name":"D3V Services Limited","address":{"@type":"PostalAddress","addressCountry":"NZ","addressRegion":"Canterbury","addressLocality":"Christchurch"}},"knowsAbout":["AI receptionist","Virtual receptionist","Phone answering service","After-hours call answering","AI phone agent","Appointment booking","Outbound calling campaigns","Business phone numbers"],"sameAs":["https://www.facebook.com/profile.php?id=61572226258048","https://www.instagram.com/talkifynz/","https://www.linkedin.com/company/talkify-nz/"]},{"@type":"WebSite","@id":"https://talkify.nz#website","name":"Talkify","url":"https://talkify.nz","publisher":{"@id":"https://talkify.nz#organization"},"inLanguage":"en-NZ"},{"@type":"Service","@id":"https://talkify.nz#service","name":"Talkify AI Phone Agent","description":"AI-powered phone agent providing 24/7 AI reception, smart booking, lead qualification and intelligent call handling for New Zealand and Australian businesses.","provider":{"@id":"https://talkify.nz#organization"},"areaServed":[{"@type":"Country","name":"New Zealand"},{"@type":"Country","name":"Australia"}],"serviceType":"AI Phone Agent","category":"Business Phone System","audience":{"@type":"BusinessAudience","audienceType":"Small and medium businesses"},"hasOfferCatalog":{"@type":"OfferCatalog","name":"Talkify Plans","itemListElement":[{"@type":"Offer","name":"Shortwave (Personal Assistant, for one person)","price":"89","priceCurrency":"NZD"},{"@type":"Offer","name":"Broadcast (Business agents)","price":"129","priceCurrency":"NZD"},{"@type":"Offer","name":"Website Chat","price":"49","priceCurrency":"NZD"},{"@type":"Offer","name":"Custom Setup","price":"499","priceCurrency":"NZD","description":"From price. Includes custom API integration; 12-month contract."},{"@type":"Offer","name":"Fleet","priceCurrency":"NZD","description":"Custom pricing for multi-location operators"}]}}]}</script>
66
67
68    
69    
70            <!-- Google Analytics -->
vendor: 68 bytes, lines 70-71
70
71    <script async src="https://www.googletagmanager.com/gtag/js?id=
71G-YS6V82V8W9
vendor: 16 bytes, lines 71-72
71"></script>
72    
72<script>
73        
vendor: 176 bytes, lines 73-80
73window.dataLayer = window.dataLayer || [];
74
75        function gtag() {
76            dataLayer.push(arguments);
77        }
78
79        gtag('js', new Date());
80        gtag('config', "
80G-YS6V82V8W9
vendor: 12 bytes, lines 80-81
80");
81        
81gtag('config', "AW-18227321636");
82    </script>
82
83    
84    
85    
85<script>
86    // Safe before gtag has loaded: dataLayer is already an array by here and
87    // gtag() only pushes onto it, so an event queued early still gets sent.
88    window.talkifyTrack = function (name, params) {
89        if (typeof gtag !== 'function') { return; }
90        gtag('event', name, params || {});
91    };
92    </script>
92
93
94        <!-- Google Tag Manager -->
95    
95<script>
vendor: 534 bytes, lines 95-107
95(function (w, d, s, l, i) {
96            w[l] = w[l] || [];
97            w[l].push({
98                'gtm.start':
99                    new Date().getTime(), event: 'gtm.js'
100            });
101            var f = d.getElementsByTagName(s)[0],
102                j = d.createElement(s), dl = l != 'dataLayer' ? '&l=' + l : '';
103            j.async = true;
104            j.src =
105                'https://www.googletagmanager.com/gtm.js?id=' + i + dl;
106            f.parentNode.insertBefore(j, f);
107        })(window, document, 'script', 'dataLayer', "
107GTM-TTGHDLQ4
vendor: 3 bytes, line 107
107");
107</script>
107
108    <!-- End Google Tag Manager -->
109    <link rel="preconnect" href="https://fonts.googleapis.com">
110    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
111    <!-- Meta Pixel Code -->
112    
112<script>
vendor: 679 bytes, lines 112-131
112
113        !function (f, b, e, v, n, t, s) {
114            if (f.fbq) return;
115            n = f.fbq = function () {
116                n.callMethod ?
117                    n.callMethod.apply(n, arguments) : n.queue.push(arguments)
118            };
119            if (!f._fbq) f._fbq = n;
120            n.push = n;
121            n.loaded = !0;
122            n.version = '2.0';
123            n.queue = [];
124            t = b.createElement(e);
125            t.async = !0;
126            t.src = v;
127            s = b.getElementsByTagName(e)[0];
128            s.parentNode.insertBefore(t, s)
129        }(window, document, 'script',
130            'https://connect.facebook.net/en_US/fbevents.js');
131        fbq('init', '
1311560743332225994
vendor: 42 bytes, lines 131-133
131');
132        fbq('track', 'PageView');
133    
133</script>
133
134    <noscript><img height="1" width="1" style="display:none"
135                   src="https://www.facebook.com/tr?id=1560743332225994&ev=PageView&noscript=1"
136        /></noscript>
137    <!-- End Meta Pixel Code -->
138        
139    <link
140        href="https://fonts.googleapis.com/css2?family=Outfit:[email protected]&family=JetBrains+Mono:wght@400;500&display=swap"
141        rel="stylesheet">
142
143    <style>
144        /* ====== TOKENS ======
145           The 2026 brand guide, in one place.
146
147           Roles, not decoration:
148             blue   #318ABE  PRIMARY. Links, primary buttons, focus rings, the
149                             mark, the start of the gradient.
150             green  #A3D654  ACCENT. Live dots, success, the end of the
151                             gradient, small highlights on dark ground.
152             ink    #101820  Body copy on light, the dark surface on dark.
153
154           Green is never small text on a light ground: #A3D654 on white is
155           1.6:1. Where a word genuinely has to be green and small, use
156           --green-ink.
157
158           Naming note: this sheet grew up with --ink as the page GROUND and
159           --paper as the text on it, and ~65 pages are written against that,
160           so the pair keeps its meaning. :root is the dark treatment;
161           html[data-theme="light"] is what almost every visitor sees, because
162           the no-flash script picks light unless somebody has chosen dark. */
163        :root {
164            /* -- brand constants, identical in both themes -- */
165            --blue: #318ABE;
166            --blue-dark: #256D97;
167            --green: #A3D654;
168            --green-ink: #4F6B18; /* the rare small-green-text case, on light */
169            --brand-blue: #318ABE; /* legacy aliases, still referenced by pages */
170            --brand-blue-bright: #5BC7E8;
171            --brand-green: #A3D654;
172            --brand-green-bright: #B9DD80;
173
174            /* -- dark treatment -- */
175            --ink: #101820;
176            --ink-2: #16202A;
177            --ink-3: #1D2831;
178            --line: rgba(255, 255, 255, .10);
179            --line-2: rgba(255, 255, 255, .18);
180            --paper: #FFFFFF;
181            --paper-warm: #F2F4F5;
182            --bone: #C6CCD1;
183            --mute: #9AA2A8;
184            --mute-2: #79828A;
185
186            /* Primary. Blue carries links and fills here. --plasma is the same
187               family: the .blue / .eb-blue / .plasma-text idiom stays blue, the
188               brand simply has one primary rather than the two accents this
189               sheet used to run. Green is --accent, and only --accent. */
190            --signal: #4FA6D8;
191            --signal-warm: #7BC4E9;
192            --plasma: #4FA6D8;
193            --plasma-bright: #7BC4E9;
194            --accent: #A3D654; /* live, success, gradient end */
195            --coral: #FF5E3A;
196            --violet: #7C5BFF;
197            /* 45deg blue to green, hero surfaces only, never twice on a page */
198            --grad: linear-gradient(45deg, var(--blue) 0%, var(--green) 100%);
199            --grad-soft: linear-gradient(45deg, color-mix(in srgb, var(--blue) 18%, transparent) 0%, color-mix(in srgb, var(--green) 18%, transparent) 100%);
200
201            /* -- type --
202               Outfit does the display, heading and body work; JetBrains Mono
203               does labels. --serif and --serif-italic are kept as names because
204               ~65 pages reference them, but both now resolve to Outfit: there
205               is no second face on the site. */
206            --sans: 'Outfit', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', sans-serif;
207            --serif: 'Outfit', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', sans-serif;
208            --serif-italic: 'Outfit', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', sans-serif;
209            --mono: 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
210
211            /* One scale, so a page cannot invent a size. The old sheet ran
212               138px headlines over 13.5px body copy; nothing here is below
213               14px and nothing above 96px. */
214            --t-display: clamp(44px, 6.4vw, 96px);
215            --t-h2: clamp(34px, 4.4vw, 60px);
216            --t-h3: clamp(22px, 2.2vw, 30px);
217            --t-sub: clamp(20px, 2vw, 26px);
218            --t-lede: 17px;
219            --t-body: 16px;
220            --t-small: 14px;
221            --t-label: 11.5px;
222            --lh-display: 1.04;
223            --lh-head: 1.12;
224            --lh-body: 1.6;
225            --ls-head: -.02em; /* the guide's -2% on headings */
226            --ls-label: .13em; /* the guide's +13% on mono labels */
227
228            --ease: cubic-bezier(.2, .7, .2, 1);
229            --ease-out: cubic-bezier(.16, 1, .3, 1);
230
231            --shell-pad: clamp(20px, 3.5vw, 56px);
232            /* Section rhythm, so a new page stops reaching for
233               style="padding-top:0". See section.shell and .shell.flush. */
234            --space-section: clamp(72px, 8vw, 120px);
235            --space-section-tight: clamp(52px, 5.5vw, 80px);
236
237            /* -- semantic tokens (recurring patterns that must flip per theme) -- */
238            --on-accent: #0B1116; /* text sitting on a brand fill */
239            --panel: #16202A;
240            --panel-2: #1A242E;
241            --panel-grad: linear-gradient(140deg, #18232D, #101820);
242            --panel-grad-160: linear-gradient(160deg, #16202A, #101820);
243            --deck-grad: linear-gradient(180deg, #18232D, #101820);
244            --surface: rgba(255, 255, 255, .02);
245            --surface-2: rgba(255, 255, 255, .04);
246            --surface-3: rgba(255, 255, 255, .06);
247            --scrim-strong: rgba(16, 24, 32, .85);
248            --scrim-mid: rgba(16, 24, 32, .6);
249            --scrim-soft: rgba(16, 24, 32, .4);
250            --scrim-solid: #101820;
251            --shadow-deep: rgba(0, 0, 0, .8);
252            --shadow-soft: rgba(0, 0, 0, .5);
253            --logo-light: none; /* logo image swap: see .logo img rules */
254        }
255
256        /* ====== LIGHT THEME ====== */
257        html[data-theme="light"] {
258            --ink: #FFFFFF;
259            --ink-2: #F7F8F8; /* the guide's surface */
260            --ink-3: #EDEFEF;
261            --line: #E9EAEA; /* the guide's line */
262            --line-2: #D5D8D9;
263            --paper: #101820; /* the guide's ink, as body copy */
264            --paper-warm: #1B242C;
265            --bone: #3F4A52; /* long-form body copy, 9.6:1 on white */
266            --mute: #5A6268; /* the guide's grey, 6.2:1 on white */
267            --mute-2: #79828A;
268
269            /* On white, #318ABE is 3.8:1, which is short of AA for a 14px
270               label or a link in running text. The guide's own blue dark is
271               5.7:1, so that is what carries text and button fills here;
272               #318ABE stays the brand blue for the mark, the gradient and
273               anything large. */
274            --signal: #256D97;
275            --signal-warm: #1F5D80;
276            --plasma: #256D97;
277            --plasma-bright: #1F5D80;
278            --accent: #A3D654;
279
280            --on-accent: #FFFFFF; /* white on the blue fill: 5.7:1 */
281            --panel: #F7F8F8;
282            --panel-2: #EFF1F1;
283            --panel-grad: linear-gradient(140deg, #FFFFFF, #F2F4F4);
284            --panel-grad-160: linear-gradient(160deg, #FFFFFF, #F2F4F4);
285            --deck-grad: linear-gradient(180deg, #FFFFFF, #F7F8F8);
286            --surface: rgba(16, 24, 32, .03);
287            --surface-2: rgba(16, 24, 32, .05);
288            --surface-3: rgba(16, 24, 32, .07);
289            --scrim-strong: rgba(255, 255, 255, .88);
290            --scrim-mid: rgba(255, 255, 255, .58);
291            --scrim-soft: rgba(255, 255, 255, .36);
292            --scrim-solid: #FFFFFF;
293            --shadow-deep: rgba(16, 24, 32, .20);
294            --shadow-soft: rgba(16, 24, 32, .12);
295        }
296
297        html {
298            transition: background-color .35s var(--ease), color .35s var(--ease);
299        }
300
301        @media (prefers-reduced-motion: reduce) {
302            html {
303                transition: none
304            }
305        }
306
307        /* Light-theme atmosphere, the dark grain/scanline/vignette overlays don't suit a light ground */
308        html[data-theme="light"] .grain {
309            opacity: .12;
310            mix-blend-mode: multiply
311        }
312
313        html[data-theme="light"] .scanlines {
314            display: none
315        }
316
317        html[data-theme="light"] .vignette {
318            background: radial-gradient(120% 80% at 50% 0%, transparent 45%, rgba(20, 22, 15, .06) 100%)
319        }
320
321        /* Theme-swappable photos: elements pass --shot-dark / --shot-light as inline custom props */
322        html[data-theme="light"] .hero-bg .photo {
323            background-image: var(--shot-light, var(--shot-dark))
324        }
325
326        html[data-theme="light"] .hero-photo {
327            background-image: var(--shot-light, var(--shot-dark))
328        }
329
330        html[data-theme="light"] .endcta .endcta-photo {
331            background-image: url('/media/frontend/nz-skyline-day.jpg');
332            opacity: .5;
333            filter: saturate(1) contrast(1)
334        }
335
336        /* ── The 2026 mark (x-brand.logo) ──────────────────────────────────
337           The lockup is drawn inline so the spark eye can wink and so the
338           word can take the theme's colour rather than needing a file per
339           combination. Base here is the dark treatment, matching :root; the
340           light theme, which is what the no-flash script picks unless somebody
341           has chosen dark, inverts the pair. The gradient circle is the same
342           blue-to-green in both, per the brand guide. */
343        .tk-logo {
344            --tk-word: #ffffff;
345            --tk-ground: #101820;
346            display: block;
347        }
348
349        html[data-theme="light"] .tk-logo {
350            --tk-word: #101820;
351            --tk-ground: #ffffff;
352        }
353
354        /* The guide's one permitted movement: 300ms close on a 4 second
355           cycle, on an inner group so the star keeps its translate and scale. */
356        @keyframes tk-blink {
357            0%, 92%, 100% { transform: scaleY(1) }
358            95% { transform: scaleY(.08) }
359        }
360
361        .tk-logo .tk-eye {
362            animation: tk-blink 4s ease-in-out infinite;
363            transform-origin: 50px 50px
364        }
365
366        @media (prefers-reduced-motion: reduce) {
367            .tk-logo .tk-eye {
368                animation: none
369            }
370        }
371
372        /* Theme toggle button */
373        .theme-toggle {
374            width: 40px;
375            height: 40px;
376            border-radius: 10px;
377            border: 1px solid var(--line);
378            display: grid;
379            place-items: center;
380            color: var(--bone);
381            transition: .25s var(--ease);
382            flex: 0 0 auto
383        }
384
385        .theme-toggle:hover {
386            border-color: var(--signal);
387            color: var(--paper)
388        }
389
390        .theme-toggle .icon-moon {
391            display: none
392        }
393
394        html[data-theme="light"] .theme-toggle .icon-sun {
395            display: none
396        }
397
398        html[data-theme="light"] .theme-toggle .icon-moon {
399            display: block
400        }
401
402        * {
403            box-sizing: border-box;
404            margin: 0;
405            padding: 0
406        }
407
408        html, body {
409            background: var(--ink);
410            color: var(--paper);
411            font-family: var(--sans);
412            font-weight: 400;
413            -webkit-font-smoothing: antialiased;
414            text-rendering: optimizeLegibility;
415            overflow-x: hidden
416        }
417
418        body {
419            font-size: var(--t-body);
420            line-height: var(--lh-body);
421            letter-spacing: 0
422        }
423
424        a {
425            color: inherit;
426            text-decoration: none
427        }
428
429        img, svg {
430            display: block;
431            max-width: 100%
432        }
433
434        button {
435            font: inherit;
436            color: inherit;
437            background: none;
438            border: 0;
439            cursor: pointer
440        }
441
442        input, textarea, select {
443            font: inherit;
444            color: inherit
445        }
446
447        ::selection {
448            background: var(--signal);
449            color: var(--on-accent)
450        }
451
452        /* Labels: JetBrains Mono 500, uppercase, +13% tracking. */
453        .mono {
454            font-family: var(--mono);
455            font-weight: 500;
456            letter-spacing: var(--ls-label)
457        }
458
459        .serif {
460            font-family: var(--serif)
461        }
462
463        /* The accent idiom.
464           It was a Fraunces italic in green. Outfit ships no italic, and a
465           browser-synthesised slant on a geometric sans at 96px looks broken,
466           so the accent is now weight and colour: Outfit 600 in the primary
467           blue. The !important is deliberate and is the only one in this
468           sheet: several pages set font-style on their own .it descendants
469           and would otherwise reintroduce the fake slant. */
470        .italic, .it, .blue {
471            font-family: var(--serif);
472            font-style: normal !important;
473            font-weight: 600
474        }
475
476        .signal-text {
477            color: var(--signal)
478        }
479
480        .plasma-text {
481            color: var(--plasma-bright)
482        }
483
484        /* ====== ATMOSPHERE ====== */
485        .grain {
486            position: fixed;
487            inset: 0;
488            pointer-events: none;
489            z-index: 200;
490            mix-blend-mode: overlay;
491            opacity: .32;
492            background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='160' height='160'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='1.4' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .55 0'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>");
493            background-size: 160px
494        }
495
496        .scanlines {
497            position: fixed;
498            inset: 0;
499            pointer-events: none;
500            z-index: 201;
501            opacity: .04;
502            background-image: linear-gradient(to bottom, transparent 0, transparent 2px, rgba(255, 255, 255, .6) 2px, rgba(255, 255, 255, .6) 3px);
503            background-size: 100% 3px
504        }
505
506        .vignette {
507            position: fixed;
508            inset: 0;
509            pointer-events: none;
510            z-index: 199;
511            background: radial-gradient(120% 80% at 50% 0%, transparent 40%, rgba(0, 0, 0, .5) 100%)
512        }
513
514        @keyframes pulse {
515            0%, 100% {
516                transform: scale(1);
517                opacity: 1
518            }
519            50% {
520                transform: scale(1.4);
521                opacity: .6
522            }
523        }
524
525        @keyframes slide {
526            from {
527                transform: translateX(0)
528            }
529            to {
530                transform: translateX(-50%)
531            }
532        }
533
534        /* ====== NAV ====== */
535        .nav {
536            position: fixed;
537            top: 0;
538            left: 0;
539            right: 0;
540            z-index: 80;
541            display: grid;
542            grid-template-columns:1fr auto 1fr;
543            align-items: center;
544            gap: 24px;
545            padding: 18px var(--shell-pad);
546            background: linear-gradient(180deg, var(--scrim-strong), var(--scrim-soft) 80%, transparent);
547            backdrop-filter: blur(10px) saturate(140%);
548            -webkit-backdrop-filter: blur(10px) saturate(140%)
549        }
550
551        .nav .logo {
552            display: flex;
553            align-items: center;
554            gap: 14px
555        }
556
557        .nav .logo .mark {
558            width: 34px;
559            height: 34px;
560            border-radius: 10px;
561            background: var(--grad);
562            display: grid;
563            place-items: center;
564            position: relative;
565            overflow: hidden;
566            box-shadow: 0 0 30px rgba(49, 138, 190, .4)
567        }
568
569        .nav .logo .mark::after {
570            content: "";
571            position: absolute;
572            inset: 0;
573            background: radial-gradient(circle at 30% 20%, rgba(255, 255, 255, .55), transparent 50%)
574        }
575
576        .nav .logo .mark svg {
577            width: 18px;
578            height: 18px;
579            color: var(--ink);
580            position: relative;
581            z-index: 1
582        }
583
584        .nav .logo b {
585            font-family: var(--serif);
586            font-weight: 500;
587            font-size: 22px;
588            letter-spacing: -.02em
589        }
590
591        .nav .logo .tag {
592            font-family: var(--mono);
593            font-size: var(--t-label);
594            color: var(--mute);
595            text-transform: uppercase;
596            letter-spacing: .18em;
597            margin-left: 6px;
598            padding: 3px 6px;
599            border: 1px solid var(--line);
600            border-radius: 4px
601        }
602
603        .nav ul {
604            display: flex;
605            gap: 6px;
606            list-style: none
607        }
608
609        .nav ul a {
610            display: inline-flex;
611            align-items: center;
612            gap: 6px;
613            padding: 8px 14px;
614            border-radius: 999px;
615            font-size: 13px;
616            color: var(--bone);
617            transition: .25s var(--ease)
618        }
619
620        .nav ul a:hover {
621            background: var(--ink-3);
622            color: var(--paper)
623        }
624
625        .nav ul a.is-active {
626            background: var(--ink-3);
627            color: var(--paper)
628        }
629
630        .nav ul a.is-active .dot {
631            background: var(--signal);
632            box-shadow: 0 0 8px var(--signal)
633        }
634
635        .nav ul a .dot {
636            width: 5px;
637            height: 5px;
638            border-radius: 50%;
639            background: var(--mute)
640        }
641
642        /* ── Agents mega-menu ─────────────────────────────────────────────
643           Desktop: opens on hover, on focus, or on click (the click state is
644           what mobile uses, where the whole nav is a stacked panel and the
645           menu becomes an inline accordion). */
646        .nav-drop {
647            position: relative
648        }
649
650        .nav-drop-btn {
651            display: inline-flex;
652            align-items: center;
653            gap: 6px;
654            padding: 8px 14px;
655            border-radius: 999px;
656            font-family: var(--sans);
657            font-size: 13px;
658            color: var(--bone);
659            background: none;
660            border: 0;
661            cursor: pointer;
662            transition: .25s var(--ease)
663        }
664
665        .nav-drop-btn:hover,
666        .nav-drop-btn.is-active {
667            background: var(--ink-3);
668            color: var(--paper)
669        }
670
671        .nav-drop-btn.is-active .dot {
672            background: var(--signal);
673            box-shadow: 0 0 8px var(--signal)
674        }
675
676        .nav-drop-btn .dot {
677            width: 5px;
678            height: 5px;
679            border-radius: 50%;
680            background: var(--mute)
681        }
682
683        .nav-drop-chev {
684            transition: transform .25s var(--ease);
685            opacity: .7
686        }
687
688        .nav-drop.is-open .nav-drop-chev {
689            transform: rotate(180deg)
690        }
691
692        .nav-drop-panel {
693            position: absolute;
694            top: calc(100% + 10px);
695            left: 0;
696            z-index: 90;
697            display: none;
698            grid-template-columns: minmax(240px, 1fr) minmax(300px, 1fr);
699            gap: 26px;
700            min-width: 620px;
701            padding: 22px;
702            background: var(--ink-2);
703            border: 1px solid var(--line);
704            border-radius: 16px;
705            box-shadow: 0 24px 60px rgba(0, 0, 0, .35)
706        }
707
708        /* Invisible bridge across the 10px gap between the button and the panel.
709           Without it the pointer leaves .nav-drop on the way down and the menu
710           shuts before you get there, unless you move quickly. It spans the full
711           width of the panel, so a diagonal approach is covered too. */
712        .nav-drop-panel::before {
713            content: "";
714            position: absolute;
715            left: 0;
716            right: 0;
717            top: -12px;
718            height: 12px
719        }
720
721        /* One-column variant, for a menu that holds a single short list. The
722           base two-column grid is what Agents uses. */
723        .nav-drop-panel--single {
724            grid-template-columns: 1fr;
725            min-width: 340px
726        }
727
728        /* Industries runs to twenty-three entries in four sectors, so it takes
729           a third column rather than a taller one. Sector headings do the
730           finding; the A-Z inside each does the rest. */
731        .nav-drop-panel--industries {
732            grid-template-columns: repeat(3, minmax(190px, 1fr));
733            min-width: 660px
734        }
735
736        .nav-drop:hover .nav-drop-panel,
737        .nav-drop:focus-within .nav-drop-panel,
738        .nav-drop.is-open .nav-drop-panel {
739            display: grid
740        }
741
742        .nav-drop-hd {
743            display: block;
744            font-family: var(--mono);
745            font-size: var(--t-label);
746            letter-spacing: .18em;
747            text-transform: uppercase;
748            color: var(--mute);
749            margin-bottom: 10px
750        }
751
752        /* These selectors carry `.nav ul` on purpose: the generic `.nav ul a`
753           rule above makes every nav link an inline-flex pill, which would put
754           each label and its description side by side instead of stacked. */
755        .nav ul .nav-drop-panel a {
756            display: block;
757            padding: 9px 10px;
758            border-radius: 10px;
759            font-size: var(--t-small);
760            line-height: 1.35;
761            color: var(--paper);
762            transition: .2s var(--ease)
763        }
764
765        .nav ul .nav-drop-panel a > span {
766            display: block;
767            font-weight: 500
768        }
769
770        .nav ul .nav-drop-panel a em {
771            display: block;
772            font-style: normal;
773            font-size: 11.5px;
774            line-height: 1.4;
775            color: var(--mute);
776            margin-top: 3px
777        }
778
779        .nav ul .nav-drop-panel a:hover {
780            background: var(--ink-3)
781        }
782
783        .nav-drop-col {
784            display: flex;
785            flex-direction: column;
786            align-items: stretch
787        }
788
789        /* A sector column's links sit tighter than the described Agents rows:
790           they are one word each and there is no <em> under them. */
791        .nav ul .nav-drop-panel--industries a:not(.nav-drop-all) {
792            padding-top: 6px;
793            padding-bottom: 6px
794        }
795
796        /* margin-top:auto pins it to the foot of its column, so both "See all"
797           links line up even though the two columns are different lengths. */
798        .nav ul .nav-drop-all {
799            margin-top: auto;
800            padding-top: 12px;
801            border-top: 1px solid var(--line);
802            border-radius: 0;
803            color: var(--signal);
804            font-weight: 500;
805            /* The arrow belongs on the same line as the words. In a sector
806               column ~190px wide it wrapped onto a line of its own. */
807            white-space: nowrap
808        }
809
810        .nav ul .nav-drop-all:hover {
811            background: none;
812            opacity: .8
813        }
814
815        /* `a` is in the selector to out-specify `.nav ul .nav-drop-panel a >
816           span`, which is display:block for the stacked label-and-description
817           rows. Without it the arrow was a block of its own and dropped onto a
818           second line under the words. */
819        .nav ul a.nav-drop-all > span {
820            display: inline;
821            font-weight: 500
822        }
823
824        .nav .actions {
825            justify-self: end;
826            display: flex;
827            align-items: center;
828            gap: 10px
829        }
830
831        .nav .num {
832            font-family: var(--mono);
833            font-size: 13px;
834            color: var(--bone);
835            padding: 8px 12px;
836            border: 1px solid var(--line);
837            border-radius: 8px;
838            transition: .25s;
839            white-space: nowrap
840        }
841
842        .nav .num:hover {
843            border-color: var(--signal);
844            color: var(--paper)
845        }
846
847        .nav .num b {
848            color: var(--signal);
849            font-weight: 500
850        }
851
852        /* The signup pill's two faces: the wide desktop one links to /signup
853           (a tel: link on a desktop rings nothing), the mobile one is a phone
854           glyph that actually dials. Only ever one on screen. */
855        .nav .num-call {
856            display: none;
857            align-items: center;
858            justify-content: center;
859            padding: 8px 10px;
860            line-height: 0
861        }
862
863        .menu-btn {
864            display: none
865        }
866
867        .btn {
868            display: inline-flex;
869            align-items: center;
870            gap: 10px;
871            padding: 12px 20px;
872            border-radius: 999px;
873            font-size: var(--t-small);
874            font-weight: 500;
875            letter-spacing: 0;
876            transition: .25s var(--ease);
877            border: 1px solid transparent;
878            white-space: nowrap
879        }
880
881        /* Primary is Talkify Blue, per the guide. Green is the accent and
882           never the button. */
883        .btn-primary {
884            background: var(--signal);
885            color: var(--on-accent)
886        }
887
888        .btn-primary:hover {
889            background: var(--signal-warm);
890            transform: translateY(-1px);
891            box-shadow: 0 8px 26px -8px color-mix(in srgb, var(--signal) 55%, transparent)
892        }
893
894        .btn-blue {
895            background: var(--plasma);
896            color: var(--on-accent)
897        }
898
899        .btn-blue:hover {
900            background: var(--plasma-bright);
901            transform: translateY(-1px)
902        }
903
904        .btn-ghost {
905            border-color: var(--paper);
906            color: var(--paper)
907        }
908
909        .btn-ghost:hover {
910            background: var(--paper);
911            color: var(--ink);
912            border-color: var(--paper)
913        }
914
915        /* One focus ring for every interactive thing on the site. */
916        .btn:focus-visible, a:focus-visible, button:focus-visible,
917        input:focus-visible, select:focus-visible, textarea:focus-visible,
918        summary:focus-visible, [tabindex]:focus-visible {
919            outline: 2px solid var(--blue);
920            outline-offset: 2px
921        }
922
923        .btn .arr {
924            transition: transform .25s var(--ease)
925        }
926
927        .btn:hover .arr {
928            transform: translateX(3px)
929        }
930
931        .btn-lg {
932            padding: 16px 28px;
933            font-size: 16px
934        }
935
936        /* ====== EYEBROW ====== */
937        .eyebrow {
938            display: inline-flex;
939            align-items: center;
940            gap: 10px;
941            font-family: var(--mono);
942            font-weight: 500;
943            font-size: var(--t-label);
944            text-transform: uppercase;
945            letter-spacing: var(--ls-label);
946            color: var(--mute);
947            padding: 6px 10px;
948            border: 1px solid var(--line);
949            border-radius: 999px;
950            background: var(--surface)
951        }
952
953        /* Green is the live state, which is exactly what this dot is. */
954        .eyebrow .pin {
955            width: 6px;
956            height: 6px;
957            border-radius: 50%;
958            background: var(--accent);
959            box-shadow: 0 0 10px color-mix(in srgb, var(--accent) 70%, transparent)
960        }
961
962        .eyebrow.eb-blue .pin {
963            background: var(--plasma);
964            box-shadow: 0 0 10px var(--plasma)
965        }
966
967        .eyebrow.eb-coral .pin {
968            background: var(--coral);
969            box-shadow: 0 0 10px var(--coral)
970        }
971
972        /* ====== HERO ====== */
973        /* The nav is 84px and fixed, so 160px of padding was 76px of nothing
974           above the headline. On a laptop that pushed the whole hero, and the
975           dialler beside it, most of the way down the fold before a word was
976           read. 120 keeps a comfortable 36px under the bar. */
977        .hero {
978            position: relative;
979            padding: 120px var(--shell-pad) 80px;
980            overflow: hidden
981        }
982
983        .hero-bg {
984            position: absolute;
985            inset: 0;
986            pointer-events: none;
987            z-index: 0;
988            overflow: hidden
989        }
990
991        .hero-bg .photo {
992            position: absolute;
993            inset: 0;
994            background-image: var(--shot-dark);
995            background-position: center right;
996            background-size: cover;
997            background-repeat: no-repeat;
998            opacity: .78;
999            filter: saturate(.85) contrast(1.05)
1000        }
1001
1002        .hero-bg .photo::after {
1003            content: "";
1004            position: absolute;
1005            inset: 0;
1006            background: linear-gradient(90deg, var(--scrim-solid) 0%, var(--scrim-strong) 28%, var(--scrim-mid) 50%, var(--scrim-soft) 72%, var(--scrim-mid) 100%),
1007            linear-gradient(180deg, var(--scrim-soft) 0%, transparent 30%, transparent 70%, var(--scrim-mid) 100%)
1008        }
1009
1010        .hero-bg .glow1 {
1011            position: absolute;
1012            top: -20%;
1013            left: -10%;
1014            width: 80%;
1015            height: 120%;
1016            background: radial-gradient(closest-side, rgba(49, 138, 190, .20), transparent 70%);
1017            filter: blur(20px);
1018            mix-blend-mode: screen
1019        }
1020
1021        .hero-bg .glow2 {
1022            position: absolute;
1023            bottom: -30%;
1024            right: -10%;
1025            width: 70%;
1026            height: 120%;
1027            background: radial-gradient(closest-side, color-mix(in srgb, var(--accent) 12%, transparent), transparent 70%);
1028            filter: blur(20px);
1029            mix-blend-mode: screen
1030        }
1031
1032        .hero-bg .grid-lines {
1033            position: absolute;
1034            inset: 0;
1035            background-image: linear-gradient(to right, var(--line) 1px, transparent 1px), linear-gradient(to bottom, var(--line) 1px, transparent 1px);
1036            background-size: 80px 80px;
1037            mask-image: radial-gradient(ellipse at center, #000, transparent 70%);
1038            opacity: .5
1039        }
1040
1041        /* The two hero columns are rarely the same height: the copy runs long
1042           on some pages, the photo is very tall on others, and the transcript
1043           deck is short everywhere. Bottom-aligning them dropped whichever was
1044           shorter to the floor and left a hole above it, which is what the
1045           debt-collection, outbound-calls, call-centre and pricing heroes were
1046           all showing. Centred, the difference is split top and bottom instead
1047           of piling up in one corner. */
1048        .hero-shell {
1049            position: relative;
1050            z-index: 1;
1051            display: grid;
1052            grid-template-columns:1.4fr 1fr;
1053            gap: 64px;
1054            align-items: center
1055        }
1056
1057        /* A hero photo is the exception: it is a full-bleed panel, so it fills
1058           the row rather than floating in the middle of it. */
1059        .hero-shell > .hero-photo {
1060            align-self: stretch
1061        }
1062
1063        .hero-shell.single {
1064            grid-template-columns:1fr;
1065            max-width: 1200px
1066        }
1067
1068        /* Heroes whose right column is a tall form. Bottom-aligning them drops a
1069           dead band above the headline and top-aligning just moves it below, so
1070           the left column instead stretches to the form's height and spreads its
1071           groups over it. Needs the left column's content in group wrappers. */
1072        .hero-shell.top {
1073            align-items: stretch
1074        }
1075
1076        .hero-shell.top > .hero-side {
1077            display: flex;
1078            flex-direction: column;
1079            justify-content: space-between
1080        }
1081
1082        h1.display {
1083            margin-top: 28px;
1084            font-family: var(--serif);
1085            font-weight: 600;
1086            font-size: var(--t-display);
1087            line-height: var(--lh-display);
1088            letter-spacing: var(--ls-head);
1089            padding-bottom: .06em
1090        }
1091
1092        /* The resting state IS the default. It used to be
1093           translateY(110%) inside overflow:hidden with a 1s animation, so the
1094           largest element on the page -- the LCP element -- was off screen
1095           until the animation ran, and never arrived at all if animations
1096           were suppressed. */
1097        h1.display .ln {
1098            display: block;
1099            padding-bottom: .06em;
1100            padding-right: .06em
1101        }
1102
1103        h1.display .ln span {
1104            display: inline-block;
1105            padding-bottom: .04em
1106        }
1107
1108        h1.display .it,
1109        h1.display .blue {
1110            font-family: var(--serif);
1111            font-style: normal;
1112            font-weight: 600;
1113            color: var(--signal)
1114        }
1115
1116        h1.display .out {
1117            color: var(--bone)
1118        }
1119
1120        @keyframes rise {
1121            from {
1122                opacity: 0;
1123                transform: translateY(16px)
1124            }
1125            to {
1126                opacity: 1;
1127                transform: none
1128            }
1129        }
1130
1131        @media (prefers-reduced-motion: no-preference) {
1132            h1.display .ln {
1133                overflow: hidden
1134            }
1135
1136            h1.display .ln span {
1137                animation: rise .4s var(--ease-out) both
1138            }
1139
1140            .hero h1.display .ln:nth-child(1) span { animation-delay: 0s }
1141
1142            .hero h1.display .ln:nth-child(2) span { animation-delay: .06s }
1143
1144            .hero h1.display .ln:nth-child(3) span { animation-delay: .12s }
1145
1146            .hero h1.display .ln:nth-child(4) span { animation-delay: .18s }
1147        }
1148
1149        .hero-sub {
1150            margin-top: 32px;
1151            max-width: 580px;
1152            color: var(--bone);
1153            font-size: var(--t-sub);
1154            line-height: 1.45
1155        }
1156
1157        /* rise2 is the site's general "arrive" animation. It is written from
1158           the resting state outwards, so an element that never animates is
1159           already where it belongs. */
1160        @keyframes rise2 {
1161            from {
1162                opacity: 0;
1163                transform: translateY(16px)
1164            }
1165            to {
1166                opacity: 1;
1167                transform: none
1168            }
1169        }
1170
1171        @media (prefers-reduced-motion: no-preference) {
1172            .hero-sub {
1173                animation: rise2 .4s .1s var(--ease-out) both
1174            }
1175        }
1176
1177        .hero-sub b {
1178            color: var(--paper);
1179            font-weight: 500
1180        }
1181
1182        .hero-cta {
1183            margin-top: 36px;
1184            display: flex;
1185            flex-wrap: wrap;
1186            align-items: center;
1187            gap: 14px
1188        }
1189
1190        .hero-meta {
1191            display: flex;
1192            flex-wrap: wrap;
1193            gap: 36px 56px;
1194            margin-top: 48px;
1195            padding-top: 28px;
1196            border-top: 1px dashed var(--line-2)
1197        }
1198
1199        @media (prefers-reduced-motion: no-preference) {
1200            .hero-cta {
1201                animation: rise2 .4s .16s var(--ease-out) both
1202            }
1203
1204            .hero-meta {
1205                animation: rise2 .4s .22s var(--ease-out) both
1206            }
1207        }
1208
1209        .hero-meta dt {
1210            font-family: var(--mono);
1211            font-size: var(--t-label);
1212            letter-spacing: .18em;
1213            text-transform: uppercase;
1214            color: var(--mute)
1215        }
1216
1217        .hero-meta dd {
1218            font-family: var(--serif);
1219            font-weight: 600;
1220            font-size: 30px;
1221            letter-spacing: var(--ls-head);
1222            margin-top: 4px
1223        }
1224
1225        .hero-meta dd b {
1226            color: var(--signal);
1227            font-weight: 600
1228        }
1229
1230        .hero-meta dd small {
1231            font-family: var(--mono);
1232            font-size: var(--t-small);
1233            color: var(--mute);
1234            margin-left: 4px
1235        }
1236
1237        /* Short reassurance list that sits under the hero meta, used to carry the
1238           left column down beside a tall form. */
1239        .hero-points {
1240            margin-top: 34px;
1241            padding-top: 26px;
1242            border-top: 1px dashed var(--line-2);
1243            display: grid;
1244            gap: 14px;
1245            max-width: 560px;
1246            opacity: 0;
1247            animation: rise2 .9s 1s var(--ease-out) forwards
1248        }
1249
1250        .hero-points .pt {
1251            display: flex;
1252    
1252        align-items: flex-start;
1253            gap: 12px;
1254            font-size: 14px;
1255            line-height: 1.5;
1256            color: var(--bone)
1257        }
1258
1259        .hero-points .pt svg {
1260            flex: 0 0 16px;
1261            margin-top: 3px;
1262            color: var(--signal)
1263        }
1264
1265        .hero-points .pt b {
1266            color: var(--paper);
1267            font-weight: 500
1268        }
1269
1270        /* HERO PHOTO PANEL, used on industry pages to showcase a story image as the hero visual */
1271        .hero-photo {
1272            position: relative;
1273            border-radius: 18px;
1274            overflow: hidden;
1275            box-shadow: 0 50px 80px -40px var(--shadow-deep), 0 0 0 1px var(--surface-2) inset;
1276            aspect-ratio: 4/5;
1277            background-image: var(--shot-dark);
1278            background-size: cover;
1279            background-position: center;
1280            opacity: 0;
1281            transform: translateY(30px);
1282            animation: rise2 1s 1s var(--ease-out) forwards
1283        }
1284
1285        .hero-photo::before {
1286            content: "";
1287            position: absolute;
1288            inset: 0;
1289            background: linear-gradient(180deg, transparent 50%, var(--scrim-mid) 100%);
1290            pointer-events: none
1291        }
1292
1293        .hero-photo::after {
1294            content: "";
1295            position: absolute;
1296            top: 0;
1297            left: 0;
1298            right: 0;
1299            height: 1px;
1300            background: linear-gradient(90deg, transparent, var(--signal), transparent);
1301            opacity: .6
1302        }
1303
1304        .hero-photo .corner {
1305            position: absolute;
1306            top: 18px;
1307            left: 18px;
1308            display: flex;
1309            align-items: center;
1310            gap: 8px;
1311            font-family: var(--mono);
1312            font-size: var(--t-label);
1313            letter-spacing: .18em;
1314            text-transform: uppercase;
1315            color: var(--paper);
1316            padding: 6px 12px;
1317            background: var(--scrim-strong);
1318            backdrop-filter: blur(6px);
1319            border: 1px solid var(--line-2);
1320            border-radius: 999px
1321        }
1322
1323        .hero-photo .corner::before {
1324            content: "";
1325            width: 6px;
1326            height: 6px;
1327            border-radius: 50%;
1328            background: var(--coral);
1329            box-shadow: 0 0 8px var(--coral);
1330            animation: pulse 1.6s var(--ease) infinite
1331        }
1332
1333        .hero-photo .caption {
1334            position: absolute;
1335            bottom: 24px;
1336            left: 24px;
1337            right: 24px;
1338            display: flex;
1339            justify-content: space-between;
1340            align-items: flex-end;
1341            gap: 16px;
1342            color: var(--paper);
1343            z-index: 1
1344        }
1345
1346        .hero-photo .caption .title {
1347            font-family: var(--serif);
1348            font-weight: 600;
1349            font-size: 22px;
1350            letter-spacing: -.01em;
1351            line-height: 1.1;
1352            max-width: 18ch
1353        }
1354
1355        .hero-photo .caption .title .it {
1356            font-family: var(--serif);
1357            font-weight: 600;
1358            color: var(--signal)
1359        }
1360
1361        .hero-photo .caption .stat {
1362            font-family: var(--mono);
1363            font-size: 11px;
1364            letter-spacing: .1em;
1365            text-align: right;
1366            flex: 0 0 auto
1367        }
1368
1369        .hero-photo .caption .stat b {
1370            display: block;
1371            font-family: var(--serif);
1372            font-size: 24px;
1373            font-weight: 300;
1374            color: var(--signal);
1375            letter-spacing: -.02em
1376        }
1377
1378        /* CALL DECK */
1379        /* The live call transcript. V2 renders the same thing as a left-ruled
1380           column rather than a floating rounded panel, so the conversation
1381           reads as part of the section instead of a card dropped onto it. */
1382        /* The live call transcript.
1383           This is a CARD, not a ruled column, and that is what /v2 does too:
1384           its hero carries .v2-livecard, which has a fill, a 10px radius and a
1385           drop shadow. Only the deck sitting inside a section (.v2-mini-deck)
1386           is left-ruled.
1387
1388           It was briefly converted to the ruled treatment everywhere, which
1389           left the transcript floating unanchored in the middle of five
1390           different heroes. The rule is: in a hero it is a card, in a section
1391           it is a ruled column (.deck.in-section below). */
1392        .deck {
1393            position: relative;
1394            background: var(--deck-grad);
1395            border-radius: 10px;
1396            padding: 18px 18px 14px;
1397            box-shadow: 0 30px 60px -20px var(--shadow-deep);
1398            backdrop-filter: blur(6px);
1399            font-family: var(--mono);
1400            font-size: 12.5px;
1401            line-height: 1.5;
1402            color: var(--bone);
1403            overflow: hidden;
1404            opacity: 0;
1405            transform: translateY(30px);
1406            animation: rise2 1s 1s var(--ease-out) forwards
1407        }
1408
1409        /* the in-section variant, matching .v2-mini-deck */
1410        .deck.in-section {
1411            background: none;
1412            border-radius: 0;
1413            box-shadow: none;
1414            backdrop-filter: none;
1415            border-left: 1px solid var(--line-2);
1416            padding: 6px 0 6px 28px
1417        }
1418
1419        /* This drew a green hairline across the top of the panel. The deck is
1420           ruled down its left edge now, so a top rule as well met it in a
1421           corner and read as half a box. The left rule is the deck's mark. */
1422        .deck::before {
1423            content: none
1424        }
1425
1426        .deck-hd {
1427            display: flex;
1428            justify-content: space-between;
1429            align-items: center;
1430            padding-bottom: 12px;
1431            border-bottom: 1px solid var(--line);
1432            margin-bottom: 14px;
1433            gap: 12px
1434        }
1435
1436        .deck-hd .dots {
1437            display: flex;
1438            gap: 6px
1439        }
1440
1441        .deck-hd .dots i {
1442            width: 9px;
1443            height: 9px;
1444            border-radius: 50%;
1445            background: var(--ink-3);
1446            display: block
1447        }
1448
1449        .deck-hd .dots i:first-child {
1450            background: var(--coral)
1451        }
1452
1453        .deck-hd .dots i:nth-child(2) {
1454            background: #f5b942
1455        }
1456
1457        .deck-hd .dots i:nth-child(3) {
1458            background: var(--signal)
1459        }
1460
1461        .deck-hd .ttl {
1462            font-size: 10px;
1463            letter-spacing: .16em;
1464            text-transform: uppercase;
1465            color: var(--mute);
1466            overflow: hidden;
1467            text-overflow: ellipsis;
1468            white-space: nowrap
1469        }
1470
1471        .deck-hd .rec {
1472            display: inline-flex;
1473            gap: 6px;
1474            align-items: center;
1475            color: var(--coral);
1476            font-size: 10px;
1477            text-transform: uppercase;
1478            letter-spacing: .16em;
1479            flex: 0 0 auto
1480        }
1481
1482        .deck-hd .rec::before {
1483            content: "";
1484            width: 6px;
1485            height: 6px;
1486            border-radius: 50%;
1487            background: var(--coral);
1488            animation: pulse 1.6s infinite
1489        }
1490
1491        .deck-row {
1492            display: flex;
1493            gap: 10px;
1494            padding: 6px 0;
1495            align-items: flex-start;
1496            opacity: 0;
1497            transform: translateY(6px);
1498            transition: opacity .55s var(--ease-out), transform .55s var(--ease-out)
1499        }
1500
1501        .deck-row.in {
1502            opacity: 1;
1503            transform: translateY(0)
1504        }
1505
1506        .deck-row .ts {
1507            color: var(--mute);
1508            min-width: 48px;
1509            flex: 0 0 48px;
1510            font-size: 11px
1511        }
1512
1513        /* Typing indicator, three dots that pulse */
1514        .deck-typing {
1515            display: flex;
1516            gap: 10px;
1517            padding: 6px 0;
1518            align-items: center;
1519            font-family: var(--mono);
1520            opacity: 0;
1521            transition: opacity .25s ease;
1522            height: 0;
1523            overflow: hidden
1524        }
1525
1526        .deck-typing.on {
1527            opacity: 1;
1528            height: auto;
1529            overflow: visible
1530        }
1531
1532        .deck-typing .ts {
1533            color: var(--mute);
1534            min-width: 48px;
1535            flex: 0 0 48px;
1536            font-size: 11px
1537        }
1538
1539        .deck-typing .who {
1540            min-width: 64px;
1541            flex: 0 0 64px;
1542            text-transform: uppercase;
1543            font-size: 10px;
1544            letter-spacing: .12em;
1545            color: var(--signal)
1546        }
1547
1548        .deck-typing .dotset {
1549            display: inline-flex;
1550            gap: 4px;
1551            align-items: center
1552        }
1553
1554        .deck-typing .dotset i {
1555            width: 6px;
1556            height: 6px;
1557            border-radius: 50%;
1558            background: var(--signal);
1559            opacity: .4;
1560            animation: typingDot 1.2s ease-in-out infinite
1561        }
1562
1563        .deck-typing .dotset i:nth-child(2) {
1564            animation-delay: .2s
1565        }
1566
1567        .deck-typing .dotset i:nth-child(3) {
1568            animation-delay: .4s
1569        }
1570
1571        @keyframes typingDot {
1572            0%, 60%, 100% {
1573                opacity: .3;
1574                transform: scale(.8)
1575            }
1576            30% {
1577                opacity: 1;
1578                transform: scale(1.1)
1579            }
1580        }
1581
1582        /* PA floater notifications, arrive with a green flash and slide */
1583        .pa-floater .row {
1584            opacity: 0;
1585            transform: translateY(-8px);
1586            transition: opacity .55s var(--ease-out), transform .55s var(--ease-out)
1587        }
1588
1589        .pa-floater .row.in {
1590            opacity: 1;
1591            transform: translateY(0)
1592        }
1593
1594        .pa-floater .row.ping {
1595            animation: ping 1.4s var(--ease-out)
1596        }
1597
1598        @keyframes ping {
1599            0% {
1600                box-shadow: 0 0 0 0 transparent
1601            }
1602            20% {
1603                box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent) 60%, transparent), 0 0 22px color-mix(in srgb, var(--accent) 45%, transparent);
1604                background: color-mix(in srgb, var(--accent) 8%, transparent)
1605            }
1606            100% {
1607                box-shadow: 0 0 0 0 transparent;
1608                background: transparent
1609            }
1610        }
1611
1612        .pa-floater .row.fresh::before {
1613            content: "NEW";
1614            position: absolute;
1615            right: 0;
1616            top: -4px;
1617            font-family: var(--mono);
1618            font-size: 8px;
1619            letter-spacing: .18em;
1620            color: var(--ink);
1621            background: var(--signal);
1622            padding: 2px 5px;
1623            border-radius: 3px;
1624            animation: freshFade 4s ease-out forwards
1625        }
1626
1627        .pa-floater .row {
1628            position: relative
1629        }
1630
1631        @keyframes freshFade {
1632            0%, 60% {
1633                opacity: 1
1634            }
1635            100% {
1636                opacity: 0
1637            }
1638        }
1639
1640        .deck-row .who {
1641            min-width: 64px;
1642            flex: 0 0 64px;
1643            text-transform: uppercase;
1644            font-size: 10px;
1645            letter-spacing: .12em
1646        }
1647
1648        .deck-row.caller .who {
1649            color: var(--plasma-bright)
1650        }
1651
1652        .deck-row.agent .who {
1653            color: var(--signal)
1654        }
1655
1656        .deck-row .msg {
1657            color: var(--paper);
1658            flex: 1;
1659            font-size: 12px
1660        }
1661
1662        .deck-foot {
1663            margin-top: 12px;
1664            padding-top: 12px;
1665            border-top: 1px solid var(--line);
1666            display: grid;
1667            grid-template-columns:repeat(3, 1fr);
1668            gap: 8px
1669        }
1670
1671        .deck-foot .stat {
1672            padding: 8px 10px;
1673            background: var(--surface);
1674            border: 1px solid var(--line);
1675            border-radius: 8px
1676        }
1677
1678        .deck-foot .stat span {
1679            display: block;
1680            color: var(--mute-2);
1681            font-size: 9px;
1682            text-transform: uppercase;
1683            letter-spacing: .16em;
1684            margin-bottom: 4px
1685        }
1686
1687        .deck-foot .stat b {
1688            color: var(--paper);
1689            font-weight: 500;
1690            font-size: 13px
1691        }
1692
1693        .wave {
1694            display: flex;
1695            align-items: center;
1696            gap: 2px;
1697            height: 28px;
1698            margin-top: 14px
1699        }
1700
1701        .wave i {
1702            flex: 1;
1703            background: var(--signal);
1704            border-radius: 1px;
1705            animation: wv 1.2s ease-in-out infinite;
1706            height: 30%;
1707            box-shadow: 0 0 6px var(--signal)
1708        }
1709
1710        .wave i:nth-child(2) {
1711            animation-delay: .1s
1712        }
1713
1714        .wave i:nth-child(3) {
1715            animation-delay: .2s
1716        }
1717
1718        .wave i:nth-child(4) {
1719            animation-delay: .3s
1720        }
1721
1722        .wave i:nth-child(5) {
1723            animation-delay: .4s
1724        }
1725
1726        .wave i:nth-child(6) {
1727            animation-delay: .5s
1728        }
1729
1730        .wave i:nth-child(7) {
1731            animation-delay: .6s
1732        }
1733
1734        .wave i:nth-child(8) {
1735            animation-delay: .7s
1736        }
1737
1738        .wave i:nth-child(9) {
1739            animation-delay: .8s
1740        }
1741
1742        .wave i:nth-child(10) {
1743            animation-delay: .9s
1744        }
1745
1746        .wave i:nth-child(11) {
1747            animation-delay: 1s
1748        }
1749
1750        .wave i:nth-child(12) {
1751            animation-delay: 1.1s
1752        }
1753
1754        .wave i:nth-child(13) {
1755            animation-delay: .05s
1756        }
1757
1758        .wave i:nth-child(14) {
1759            animation-delay: .15s
1760        }
1761
1762        .wave i:nth-child(15) {
1763            animation-delay: .25s
1764        }
1765
1766        .wave i:nth-child(16) {
1767            animation-delay: .35s
1768        }
1769
1770        .wave i:nth-child(17) {
1771            animation-delay: .45s
1772        }
1773
1774        .wave i:nth-child(18) {
1775            animation-delay: .55s
1776        }
1777
1778        .wave i:nth-child(19) {
1779            animation-delay: .65s
1780        }
1781
1782        .wave i:nth-child(20) {
1783            animation-delay: .75s
1784        }
1785
1786        @keyframes wv {
1787            0%, 100% {
1788                height: 20%;
1789                opacity: .4
1790            }
1791            50% {
1792                height: 95%;
1793                opacity: 1
1794            }
1795        }
1796
1797        /* ====== STRIP ====== */
1798        /* same treatment as the V2 ticker: a faint raised surface between two
1799           hairlines, rather than a solid slab of ink */
1800        .strip {
1801            border-top: 1px solid var(--line);
1802            border-bottom: 1px solid var(--line);
1803            background: var(--surface);
1804            overflow: hidden;
1805            padding: 18px 0;
1806            font-family: var(--serif);
1807            font-size: 36px;
1808            letter-spacing: -.02em
1809        }
1810
1811        .strip-track {
1812            display: flex;
1813            gap: 64px;
1814            white-space: nowrap;
1815            animation: slide 60s linear infinite;
1816            will-change: transform
1817        }
1818
1819        .strip-track:hover {
1820            animation-play-state: paused
1821        }
1822
1823        @media (prefers-reduced-motion: reduce) {
1824            .strip-track {
1825                animation: none
1826            }
1827        }
1828
1829        .strip-track .pip {
1830            color: var(--signal)
1831        }
1832
1833        .strip-track .it {
1834            font-family: var(--serif);
1835            font-weight: 600;
1836            color: var(--bone)
1837        }
1838
1839        .strip-track .blue {
1840            color: var(--plasma)
1841        }
1842
1843        .strip-link {
1844            color: var(--paper);
1845            text-decoration: none;
1846            display: inline-flex;
1847            align-items: center;
1848            gap: 14px;
1849            padding: 0 4px;
1850            border-radius: 6px;
1851            transition: color .25s, background .25s
1852        }
1853
1854        .strip-link.it {
1855            font-family: var(--serif);
1856            font-weight: 600;
1857            color: var(--bone)
1858        }
1859
1860        .strip-link:hover {
1861            color: var(--signal);
1862            background: color-mix(in srgb, var(--signal) 6%, transparent)
1863        }
1864
1865        /* An item with no page behind it states rather than links, so it takes
1866           no pointer and no hover. */
1867        .strip-link.is-static {
1868            color: var(--mute);
1869            cursor: default
1870        }
1871
1872        .strip-l
1872ink.is-static:hover {
1873            color: var(--mute);
1874            background: none
1875        }
1876
1877        .strip-link:hover .pip {
1878            color: var(--paper)
1879        }
1880
1881        /* ====== SECTION SHELL ====== */
1882        section.shell {
1883            padding: var(--space-section) var(--shell-pad);
1884            position: relative
1885        }
1886
1887        section.shell.tight {
1888            padding: var(--space-section-tight) var(--shell-pad)
1889        }
1890
1891        /* A section that butts straight onto the one above it. Pages were
1892           writing style="padding-top:0" for this, ~1,400 inline styles' worth
1893           of ad-hoc rhythm across the site; new work uses the modifier. */
1894        section.shell.flush {
1895            padding-top: 0
1896        }
1897
1898        section.shell.flush-bottom {
1899            padding-bottom: 0
1900        }
1901
1902        .section-hd {
1903            display: flex;
1904            justify-content: space-between;
1905            align-items: flex-end;
1906            gap: 32px;
1907            margin-bottom: 64px;
1908            flex-wrap: wrap
1909        }
1910
1911        .section-hd h2 {
1912            font-family: var(--serif);
1913            font-weight: 600;
1914            font-size: var(--t-h2);
1915            line-height: var(--lh-head);
1916            letter-spacing: var(--ls-head);
1917            max-width: 18ch
1918        }
1919
1920        .section-hd h2 .it,
1921        .section-hd h2 .blue {
1922            font-family: var(--serif);
1923            font-style: normal;
1924            font-weight: 600;
1925            color: var(--signal)
1926        }
1927
1928        .section-hd .lede {
1929            max-width: 46ch;
1930            color: var(--bone);
1931            line-height: var(--lh-body);
1932            font-size: var(--t-lede)
1933        }
1934
1935        /* ====== SLAB ====== */
1936        /* V2 design language: a ruled band rather than a filled, rounded slab */
1937        .slab {
1938            display: grid;
1939            grid-template-columns:1.1fr 1fr;
1940            gap: 0;
1941            border-top: 1px solid var(--line-2);
1942            overflow: hidden
1943        }
1944
1945        .slab-l {
1946            padding: clamp(40px, 5vw, 64px) clamp(28px, 4vw, 56px) clamp(40px, 5vw, 64px) 0;
1947            display: flex;
1948            flex-direction: column;
1949            justify-content: center;
1950            gap: 40px
1951        }
1952
1953        .slab-l h3 {
1954            font-family: var(--serif);
1955            font-weight: 600;
1956            font-size: clamp(36px, 4.4vw, 60px);
1957            line-height: .98;
1958            letter-spacing: -.02em
1959        }
1960
1961        .slab-l h3 .it {
1962            font-family: var(--serif);
1963            font-weight: 600;
1964            color: var(--signal)
1965        }
1966
1967        .slab-l h3 .blue {
1968            font-family: var(--serif);
1969            font-weight: 600;
1970            color: var(--plasma-bright)
1971        }
1972
1973        .slab-l p {
1974            color: var(--bone);
1975            font-size: 15px;
1976            line-height: 1.6;
1977            max-width: 42ch
1978        }
1979
1980        .slab-l ul {
1981            list-style: none;
1982            display: flex;
1983            flex-direction: column;
1984            gap: 14px;
1985            font-size: 14px;
1986            color: var(--bone)
1987        }
1988
1989        .slab-l ul li {
1990            display: flex;
1991            gap: 12px;
1992            align-items: flex-start;
1993            padding-bottom: 14px;
1994            border-bottom: 1px dashed var(--line)
1995        }
1996
1997        .slab-l ul li:last-child {
1998            border-bottom: 0;
1999            padding-bottom: 0
2000        }
2001
2002        .slab-l ul li::before {
2003            content: "";
2004            flex: 0 0 8px;
2005            width: 8px;
2006            height: 8px;
2007            border-radius: 50%;
2008            margin-top: 7px;
2009            background: var(--signal);
2010            box-shadow: 0 0 12px var(--signal)
2011        }
2012
2013        .slab-l ul li b {
2014            color: var(--paper);
2015            font-weight: 500
2016        }
2017
2018        .slab-r {
2019            position: relative;
2020            padding: 46px 0;
2021            background: radial-gradient(closest-side at 50% 30%, rgba(49, 138, 190, .18), transparent 70%);
2022            display: flex;
2023            align-items: center;
2024            justify-content: center;
2025            overflow: hidden;
2026            min-height: 520px
2027        }
2028
2029        .slab-r::before {
2030            content: "";
2031            position: absolute;
2032            inset: 0;
2033            background-image: linear-gradient(to right, var(--line) 1px, transparent 1px), linear-gradient(to bottom, var(--line) 1px, transparent 1px);
2034            background-size: 48px 48px;
2035            mask: radial-gradient(closest-side, #000, transparent 70%)
2036        }
2037
2038        .slab-r::after {
2039            content: "";
2040            position: absolute;
2041            inset: 0;
2042            pointer-events: none;
2043            background: linear-gradient(to bottom, var(--ink) 0, transparent 13%, transparent 87%, var(--ink) 100%)
2044        }
2045
2046        /* ====== PHONE FRAME ====== */
2047        .phone-frame {
2048            position: relative;
2049            width: 280px;
2050            aspect-ratio: 9/19;
2051            border-radius: 38px;
2052            background: linear-gradient(180deg, #1a1d22, #0a0d10);
2053            padding: 8px;
2054            box-shadow: 0 60px 120px -30px rgba(0, 0, 0, .9), 0 0 0 1px rgba(255, 255, 255, .06) inset
2055        }
2056
2057        .phone-frame::before {
2058            content: "";
2059            position: absolute;
2060            top: 14px;
2061            left: 50%;
2062            transform: translateX(-50%);
2063            width: 90px;
2064            height: 24px;
2065            background: #000;
2066            border-radius: 14px;
2067            z-index: 2
2068        }
2069
2070        .phone-screen {
2071            width: 100%;
2072            height: 100%;
2073            border-radius: 32px;
2074            background: linear-gradient(180deg, #0a0d12, #13171f);
2075            overflow: hidden;
2076            position: relative;
2077            display: flex;
2078            flex-direction: column;
2079            padding: 42px 14px 14px;
2080            font-family: var(--mono);
2081            font-size: var(--t-label)
2082        }
2083
2084        /* Light mode: silver handset + light app screen (text inside uses tokens, so it flips to dark) */
2085        html[data-theme="light"] .phone-frame {
2086            background: linear-gradient(180deg, #dde0e6, #b7bcc6);
2087            box-shadow: 0 50px 90px -30px var(--shadow-deep), 0 0 0 1px rgba(0, 0, 0, .12) inset
2088        }
2089
2090        html[data-theme="light"] .phone-screen {
2091            background: linear-gradient(180deg, #ffffff, #f4f1e8)
2092        }
2093
2094        .phone-screen .stat-row {
2095            display: flex;
2096            justify-content: space-between;
2097            color: var(--bone);
2098            font-size: 9px;
2099            letter-spacing: .06em;
2100            padding: 0 6px 14px
2101        }
2102
2103        .phone-screen .ph-h {
2104            font-family: var(--serif);
2105            font-weight: 600;
2106            font-size: 24px;
2107            color: var(--paper);
2108            padding: 0 6px;
2109            letter-spacing: -.02em;
2110            line-height: 1
2111        }
2112
2113        .phone-screen .ph-h .it {
2114            font-family: var(--serif);
2115            font-weight: 600;
2116            color: var(--signal)
2117        }
2118
2119        .phone-screen .ph-h .blue {
2120            font-family: var(--serif);
2121            font-weight: 600;
2122            color: var(--plasma-bright)
2123        }
2124
2125        .phone-screen .ph-card {
2126            margin-top: 14px;
2127            background: var(--surface-2);
2128            border: 1px solid var(--line);
2129            border-radius: 14px;
2130            padding: 12px;
2131            display: flex;
2132            flex-direction: column;
2133            gap: 8px
2134        }
2135
2136        .phone-screen .ph-card .lbl {
2137            color: var(--mute);
2138            font-size: 9px;
2139            text-transform: uppercase;
2140            letter-spacing: .16em
2141        }
2142
2143        .phone-screen .ph-card .name {
2144            color: var(--paper);
2145            font-size: 12px
2146        }
2147
2148        .phone-screen .ph-card .meta {
2149            color: var(--bone);
2150            font-size: 9px;
2151            display: flex;
2152            gap: 8px
2153        }
2154
2155        .phone-screen .ph-card .meta i {
2156            font-style: normal;
2157            color: var(--signal)
2158        }
2159
2160        .phone-screen .ph-bar {
2161            margin-top: 4px;
2162            display: flex;
2163            align-items: center;
2164            gap: 6px
2165        }
2166
2167        .phone-screen .ph-bar .b {
2168            flex: 1;
2169            height: 3px;
2170            border-radius: 2px;
2171            background: var(--line)
2172        }
2173
2174        .phone-screen .ph-bar .b.on {
2175            background: var(--signal);
2176            box-shadow: 0 0 8px var(--signal)
2177        }
2178
2179        .phone-screen .ph-cta {
2180            margin-top: auto;
2181            background: var(--signal);
2182            color: var(--ink);
2183            padding: 10px;
2184            border-radius: 999px;
2185            text-align: center;
2186            font-size: 11px;
2187            font-weight: 600;
2188            font-family: var(--sans);
2189            letter-spacing: .02em
2190        }
2191
2192        /* ====== METRICS ====== */
2193        .metrics {
2194            display: grid;
2195            grid-template-columns:repeat(12, 1fr);
2196            gap: 0 clamp(24px, 3vw, 40px)
2197        }
2198
2199        /* ruled stats, the way the V2 proof block does them */
2200        .metric {
2201            grid-column: span 3;
2202            border-top: 1px solid var(--line-2);
2203            padding: 24px 0 0;
2204            position: relative;
2205            overflow: hidden;
2206            min-height: 170px;
2207            display: flex;
2208            flex-direction: column;
2209            justify-content: space-between;
2210            transition: border-color .3s var(--ease)
2211        }
2212
2213        .metric:hover {
2214            border-top-color: var(--signal)
2215        }
2216
2217        .metric .lbl {
2218            font-family: var(--mono);
2219            font-size: var(--t-label);
2220            letter-spacing: .16em;
2221            text-transform: uppercase;
2222            color: var(--mute)
2223        }
2224
2225        .metric .val {
2226            font-family: var(--serif);
2227            font-weight: 600;
2228            font-size: 60px;
2229            line-height: 1;
2230            letter-spacing: -.04em;
2231        }
2232
2233        .metric .val small {
2234            font-size: 18px;
2235            color: var(--mute);
2236            font-family: var(--mono);
2237            margin-left: 4px
2238        }
2239
2240        .metric .delta {
2241            font-family: var(--mono);
2242            font-size: 11px;
2243            color: var(--signal)
2244        }
2245
2246        .metric .delta.dn {
2247            color: var(--coral)
2248        }
2249
2250        .metric.wide {
2251            grid-column: span 6
2252        }
2253
2254        /* ====== TIERS ====== */
2255        .tiers {
2256            display: grid;
2257            grid-template-columns:repeat(3, 1fr);
2258            gap: 18px
2259        }
2260
2261        /* Pricing tiers in the V2 language: a rule, a label, a number. They were
2262           rounded, filled cards, and the featured one was picked out with a
2263           masked gradient border. A plan is now marked out by the weight and
2264           colour of its rule instead, which is how the V2 price blocks do it. */
2265        .tier {
2266            position: relative;
2267            border-top: 2px solid var(--line-2);
2268            padding: clamp(26px, 3vw, 40px) 0 0;
2269            display: flex;
2270            flex-direction: column;
2271            gap: 24px;
2272            transition: border-color .3s var(--ease)
2273        }
2274
2275        .tier:hover {
2276            border-top-color: var(--mute-2)
2277        }
2278
2279        .tier.featured {
2280            border-top-color: var(--signal)
2281        }
2282
2283        .tier.featured:hover {
2284            border-top-color: var(--signal)
2285        }
2286
2287        .tier .row1 {
2288            display: flex;
2289            justify-content: space-between;
2290            align-items: center
2291        }
2292
2293        .tier .name {
2294            font-family: var(--mono);
2295            font-size: 11px;
2296            text-transform: uppercase;
2297            letter-spacing: .18em;
2298            color: var(--bone)
2299        }
2300
2301        /* was a filled badge; the rule above already says which plan this is */
2302        .tier .badge {
2303            font-family: var(--mono);
2304            font-size: var(--t-label);
2305            color: var(--signal);
2306            letter-spacing: .14em;
2307            text-transform: uppercase
2308        }
2309
2310        .tier .price {
2311            font-family: var(--serif);
2312            font-weight: 600;
2313            font-size: 64px;
2314            line-height: .95;
2315            letter-spacing: -.035em
2316        }
2317
2318        .tier .price small {
2319            font-family: var(--mono);
2320            font-size: 13px;
2321            color: var(--mute);
2322            margin-left: 6px
2323        }
2324
2325        .tier .desc {
2326            font-size: 14px;
2327            color: var(--bone);
2328            line-height: 1.5;
2329            border-top: 1px dashed var(--line);
2330            padding-top: 20px
2331        }
2332
2333        .tier ul {
2334            list-style: none;
2335            display: flex;
2336            flex-direction: column;
2337            gap: 10px;
2338            font-size: 14px;
2339            color: var(--bone)
2340        }
2341
2342        .tier ul li {
2343            display: flex;
2344            gap: 10px;
2345            align-items: flex-start
2346        }
2347
2348        .tier ul li svg {
2349            flex: 0 0 16px;
2350            color: var(--signal);
2351            margin-top: 3px
2352        }
2353
2354        .tier .cta {
2355            margin-top: auto
2356        }
2357
2358        /* ====== EDITORIAL QUOTE ====== */
2359        .editorial {
2360            display: grid;
2361            grid-template-columns:1fr 1.4fr;
2362            gap: 64px;
2363            align-items: center
2364        }
2365
2366        .ed-num {
2367            font-family: var(--mono);
2368            font-size: 11px;
2369            color: var(--mute);
2370            letter-spacing: .18em;
2371            text-transform: uppercase;
2372            margin-bottom: 24px
2373        }
2374
2375        .ed-quote {
2376            font-family: var(--serif);
2377            font-weight: 600;
2378            font-size: clamp(28px, 3.4vw, 46px);
2379            line-height: 1.1;
2380            letter-spacing: -.02em;
2381        }
2382
2383        .ed-quote .it {
2384            font-family: var(--serif);
2385            font-weight: 600
2386        }
2387
2388        .ed-quote .hl {
2389            background: linear-gradient(180deg, transparent 62%, color-mix(in srgb, var(--accent) 55%, transparent) 62%);
2390            color: inherit;
2391            padding: 0 2px;
2392            -webkit-box-decoration-break: clone;
2393            box-decoration-break: clone
2394        }
2395
2396        .ed-attr {
2397            margin-top: 32px;
2398            display: flex;
2399            align-items: center;
2400            gap: 16px;
2401            color: var(--mute);
2402            font-family: var(--mono);
2403            font-size: 12px;
2404            letter-spacing: .04em
2405        }
2406
2407        .ed-attr .av {
2408            width: 46px;
2409            height: 46px;
2410            border-radius: 50%;
2411            background: var(--grad);
2412            display: grid;
2413            place-items: center;
2414            color: var(--ink);
2415            font-family: var(--serif);
2416            font-weight: 500;
2417            font-size: 18px
2418        }
2419
2420        .ed-attr b {
2421            color: var(--paper);
2422            font-weight: 500;
2423            font-family: var(--sans);
2424            text-transform: none;
2425            letter-spacing: 0
2426        }
2427
2428        /* ====== APP STRIP ====== */
2429        /* V2 lays the app section out as a ruled band with the phone beside the
2430           copy, not as a filled panel with the whole thing inside it. */
2431        .app {
2432            display: grid;
2433            grid-template-columns:1.2fr 1fr;
2434            gap: clamp(32px, 5vw, 80px);
2435            align-items: center;
2436            padding: clamp(48px, 6vw, 80px) 0 0;
2437            border-top: 1px solid var(--line-2);
2438            position: relative
2439        }
2440
2441        /* the glow behind the phone belonged to the filled panel this section
2442           used to sit in; a ruled band carries no lighting of its own */
2443        .app::before {
2444            content: none
2445        }
2446
2447        .app-l {
2448            position: relative;
2449            z-index: 1
2450        }
2451
2452        /* Was a violet pill. The V2 language has no pills: a kicker is a rule,
2453           then mono caps. The leading dot in the markup is redundant against
2454           the rule, so it is not rendered. */
2455        .app-tag {
2456            display: flex;
2457            align-items: center;
2458            gap: 12px;
2459            font-family: var(--mono);
2460            font-size: 11px;
2461            color: var(--mute-2);
2462            text-transform: uppercase;
2463            letter-spacing: .22em
2464        }
2465
2466        .app-tag::before {
2467            content: "";
2468            flex: 0 0 28px;
2469            height: 1px;
2470            background: var(--signal)
2471        }
2472
2473        .app h2 {
2474            font-family: var(--serif);
2475            font-weight: 600;
2476            font-size: clamp(36px, 4.6vw, 68px);
2477            line-height: .98;
2478            letter-spacing: -.025em;
2479            margin-top: 24px;
2480        }
2481
2482        .app h2 .it {
2483            font-family: var(--serif);
2484            font-weight: 600;
2485            color: var(--signal)
2486        }
2487
2488        .app p {
2489            color: var(--bone);
2490            max-width: 48ch;
2491            margin-top: 20px;
2492            font-size: 15px;
2493            line-height: 1.6
2494        }
2495
2496        /* ── Store badges (x-app-badges) ───────────────────────────────────
2497           Apple's and Google's own artwork, which neither will let anybody
2498           redraw. What used to sit here was our own box with a hand-drawn
2499           glyph and the store name set in the site's serif, which is exactly
2500           what both sets of guidelines forbid.
2501
2502           Both files are the black badge with white type. On the light theme
2503           that is the standard treatment. On the dark theme the pill sinks
2504           into the page, so a hairline gives it its edge back; the white
2505           lettering carries either way. */
2506        .app-stores {
2507            margin-top: 32px;
2508            display: flex;
2509            align-items: center;
2510            gap: 14px;
2511            flex-wrap: wrap
2512        }
2513
2514        .app-badge {
2515            display: inline-block;
2516            border-radius: 8px;
2517            box-shadow: 0 0 0 1px var(--line);
2518            transition: opacity .25s var(--ease), box-shadow .25s var(--ease)
2519        }
2520
2521        html[data-theme="light"] .app-badge {
2522            box-shadow: none
2523        }
2524
2525        .app-badge:hover {
2526            opacity: .82;
2527            box-shadow: 0 0 0 1px var(--line-2)
2528        }
2529
2530        .app-badge img {
2531            display: block;
2532            height: var(--app-badge-h, 56px);
2533            width: auto
2534        }
2535
2536        /* Two badges side by side stop fitting a phone at about 340px, and a
2537           badge that has to shrink stops being the store's badge. Let them
2538           stack instead. */
2539        @media (max-width: 420px) {
2540            .app-badge img {
2541                height: calc(var(--app-badge-h, 56px) * .82)
2542            }
2543        }
2544
2545
2546        .app-r {
2547            position: relative;
2548            z-index: 1;
2549            display: flex;
2550            justify-content: center;
2551            align-items: center
2552        }
2553
2554        .app-phone {
2555            transform: rotate(-6deg)
2556        }
2557
2558        .app-phone .phone-screen {
2559            padding: 42px 12px 12px
2560        }
2561
2562        .app-phone .ph-h {
2563            font-size: 18px
2564        }
2565
2566        /* ====== FORMS ====== */
2567        /* The demo deck and other steppers hide panels with the hidden
2568           attribute; any display rule on the element would otherwise win. */
2569        [hidden] {
2570            display: none !important
2571        }
2572
2573        .form {
2574            display: grid;
2575            gap: 18px
2576        }
2577
2578        .form .row {
2579            display: grid;
2580            gap: 18px;
2581            grid-template-columns:1fr 1fr
2582        }
2583
2584        .form .field {
2585            display: flex;
2586            flex-direction: column;
2587            gap: 6px;
2588            position: relative
2589        }
2590
2591        .form .field label {
2592            font-family: var(--mono);
2593            font-size: var(--t-label);
2594            color: var(--mute);
2595            text-transform: uppercase;
2596            letter-spacing: .18em
2597        }
2598
2599        /* squared off; the ruled language has no rounded fields in it */
2600        .form .field input, .form .field select, .form .field textarea {
2601            background: var(--surface);
2602            border: 1px solid var(--line);
2603            border-radius: 2px;
2604            padding: 14px 16px;
2605            color: var(--paper);
2606            font-size: 15px;
2607            font-family: var(--sans);
2608            transition: .25s var(--ease);
2609        }
2610
2611        .form .field input:focus, .form .field select:focus, .form .field textarea:focus {
2612            outline: none;
2613            border-color: var(--signal);
2614            background: var(--ink-3);
2615            box-shadow: 0 0 0 3px color-mix(in srgb, var(--signal) 22%, transparent)
2616        }
2617
2618        .form .field input::placeholder, .form .field textarea::placeholder {
2619            color: var(--mute-2)
2620        }
2621
2622        .form .field textarea {
2623            min-height: 120px;
2624            resize: vertical;
2625            line-height: 1.5
2626        }
2627
2628        .form .radios {
2629            display: grid;
2630            grid-template-columns:repeat(2, 1fr);
2631            gap: 10px
2632        }
2633
2634        /* Options in the V2 language: a hairline and square corners rather than
2635           a filled, rounded card each. They keep a full border rather than only
2636           a top rule because they sit in a two-column grid and have to read as
2637           separately selectable, which a top rule alone does not convey. The
2638           control marks themselves stay round: a radio dot is an affordance
2639           people know by its shape, not decoration. */
2640        .form .radio,
2641        .form .check {
2642            position: relative;
2643            display: flex;
2644            align-items: flex-start;
2645            gap: 12px;
2646            padding: 16px;
2647            border: 1px solid var(--line);
2648            border-radius: 2px;
2649            cursor: pointer;
2650            transition: .25s var(--ease);
2651            background: none
2652        }
2653
2654        .form .radio:hover,
2655        .form .check:hover {
2656            border-color: var(--line-2);
2657            background: var(--surface-2)
2658        }
2659
2660        .form .radio input,
2661        .form .check input {
2662            position: absolute;
2663            opacity: 0;
2664            pointer-events: none
2665        }
2666
2667        .form .radio .dot {
2668            width: 18px;
2669            height: 18px;
2670            border-radius: 50%;
2671            border: 1px solid var(--line-2);
2672            flex: 0 0 18px;
2673            display: grid;
2674            place-items: center;
2675            margin-top: 2px;
2676            transition: .25s
2677        }
2678
2679        .form .radio .dot::after {
2680            content: "";
2681            width: 8px;
2682            height: 8px;
2683            border-radius: 50%;
2684            background: var(--signal);
2685            transform: scale(0);
2686            transition: .25s;
2687            box-shadow: 0 0 8px var(--signal)
2688        }
2689
2690        .form .radio input:checked ~ .dot {
2691            border-color: var(--signal)
2692        }
2693
2694        .form .radio input:checked ~ .dot::after {
2695            transform: scale(1)
2696        }
2697
2698        .form .radio:has(input:checked),
2699        .form .check:has(input:checked) {
2700            border-color: var(--signal);
2701            background: color-mix(in srgb, var(--signal) 6%, transparent)
2702        }
2703
2704        /* Same card as a radio, squared off with a tick so it reads as a
2705           multi-select rather than one of a set. */
2706        .form .check .box {
2707            width: 18px;
2708            height: 18px;
2709            border-radius: 5px;
2710            border: 1px solid var(--line-2);
2711            flex: 0 0 18px;
2712            display: grid;
2713            place-items: center;
2714            margin-top: 2px;
2715            transition: .25s
2716        }
2717
2718        .form .check .box::after {
2719            content: "";
2720            width: 10px;
2721            height: 5px;
2722            margin-top: -2px;
2723            border-left: 2px solid var(--signal);
2724            border-bottom: 2px solid var(--signal);
2725            transform: rotate(-45deg) scale(0);
2726            transition: .25s
2727        }
2728
2729        .form .check input:checked ~ .box {
2730            border-color: var(--signal)
2731        }
2732
2733        .form .check input:checked ~ .box::after {
2734            transform: rotate(-45deg) scale(1)
2735        }
2736
2737        .form .radio .ttl,
2738        .form .check .ttl {
2739            font-family: var(--serif);
2740            font-weight: 400;
2741            font-size: 18px;
2742            letter-spacing: -.01em;
2743            color: var(--paper);
2744            line-height: 1
2745        }
2746
2747        .form .radio .sub,
2748        .form .check .sub {
2749            font-size: 12px;
2750            color: var(--bone);
2751            margin-top: 4px;
2752            line-height: 1.4
2753        }
2754
2755        .form .actions {
2756            display: flex;
2757            justify-content: space-between;
2758            align-items: center;
2759            gap: 16px;
2760            flex-wrap: wrap;
2761            margin-top: 8px
2762        }
2763
2764        .form .actions .note {
2765            font-size: 12px;
2766            color: var(--mute);
2767            font-family: var(--mono);
2768            letter-spacing: .04em
2769        }
2770
2771        /* ====== PLAN DISPLAY (live price panel under agent_type radios) ====== */
2772        /* The running total of what has been picked. Was a rounded card filled
2773           with a blue-to-green wash; in the V2 language a price is a rule and a
2774           number, so it is ruled top and bottom and carries no fill. */
2775        .plan-display {
2776            display: grid;
2777            grid-template-columns:1fr auto;
2778            gap: 18px;
2779            align-items: center;
2780            padding: 22px 0;
2781            margin-top: 24px;
2782            border-top: 1px solid var(--line-2);
2783            border-bottom: 1px solid var(--line);
2784            position: relative;
2785        }
2786
2787        .plan-display::before {
2788            content: "";
2789            position: absolute;
2790            top: 0;
2791            left: 0;
2792            right: 0;
2793            height: 1px;
2794            background: linear-gradient(90deg, transparent, var(--signal), transparent);
2795            opacity: .6
2796        }
2797
2798        .plan-display-label {
2799            font-family: var(--serif);
2800            font-weight: 400;
2801            font-size: 18px;
2802            letter-spacing: -.01em;
2803            color: var(--paper);
2804            line-height: 1.1
2805        }
2806
2807        .plan-display-sub {
2808            font-family: var(--sans);
2809            font-size: 12px;
2810            color: var(--bone);
2811            line-height: 1.5;
2812            margin-top: 4px;
2813            max-width: 38ch
2814        }
2815
2816        .plan-display-right {
2817            text-align: right;
2818            flex: 0 0 auto
2819        }
2820
2821        .plan-display-price {
2822            font-family: var(--serif);
2823            font-weight: 600;
2824            font-size: 34px;
2825            line-height: 1;
2826            letter-spacing: -.025em;
2827            color: var(--signal);
2828            white-space: nowrap
2829        }
2830
2831        .plan-display-price small {
2832            font-family: var(--mono);
2833            font-size: 11px;
2834            color: var(--mute);
2835            margin-left: 4px;
2836            font-weight: 400
2837        }
2838
2839        .plan-display-tier {
2840            font-family: var(--mono);
2841            font-size: 9.5px;
2842            text-transform: uppercase;
2843            letter-spacing: .16em;
2844            color: var(--mute);
2845            margin-top: 6px
2846        }
2847
2848        /* Spells out how long the quoted founding rate lasts and what it becomes. */
2849        .plan-display-note {
2850            font-family: var(--sans);
2851            font-size: 11.5px;
2852            line-height: 1.5;
2853            color: var(--mute);
2854            margin-top: 6px;
2855            max-width: 34ch;
2856            margin-left: auto
2857        }
2858
2859        .plan-asterisk {
2860            font-family: var(--sans);
2861            font-size: 11.5px;
2862            line-height: 1.5;
2863            color: var(--mute);
2864            margin-top: 10px;
2865            padding: 0 4px
2866        }
2867
2868        .plan-asterisk span {
2869            color: var(--signal);
2870            font-weight: 600;
2871            margin-right: 2px
2872        }
2873
2874        /* Shown under "Pick your agent" only for plans that pair with another
2875           one (currently the Outgoing Agent, which wants an incoming agent to
2876           catch the return calls). Toggled by the plan-display script. */
2877        .plan-recommend {
2878            font-family: var(--sans);
2879            font-size: 12.5px;
2880            line-height: 1.55;
2881            color: var(--bone);
2882            margin-top: 12px;
2883            padding: 10px 12px;
2884            border-left: 2px solid var(--signal);
2885            background: rgba(49, 138, 190, .07)
2886        }
2887
2888        @media (max-width: 480px) {
2889            .plan-display {
2890                grid-template-columns:1fr;
2891                gap: 10px
2892            }
2893
2894            .plan-display-right {
2895                text-align: left
2896            }
2897
2898            .plan-display-price {
2899                font-size: 30px
2900            }
2901        }
2902
2903        /* ====== END CTA ====== */
2904        .endcta {
2905            padding: 140px var(--shell-pad);
2906            position: relative;
2907            overflow: hidden;
2908            text-align: center
2909        }
2910
2911        .endcta .endcta-photo {
2912            position: absolute;
2913            inset: 0;
2914            background-image: url('/media/frontend/nz-skyline-dusk.jpg');
2915            background-size: cover;
2916            background-position: center bottom;
2917            opacity: .32;
2918            filter: saturate(.9) contrast(1.1);
2919            z-index: 0
2920        }
2921
2922        .endcta .endcta-photo::after {
2923            content: "";
2924            position: absolute;
2925            inset: 0;
2926            background: linear-gradient(180deg, var(--scrim-strong) 0%, var(--scrim-mid) 30%, var(--scrim-soft) 70%, var(--scrim-strong) 100%),
2927            radial-gradient(ellipse at center, rgba(49, 138, 190, .22) 0%, transparent 60%)
2928        }
2929
2930        .endcta > * {
2931            position: relative;
2932            z-index: 1
2933        }
2934
2935        .endcta::before {
2936            content: "";
2937            position: absolute;
2938            inset: 0;
2939            z-index: 0
2940        }
2941
2942        .endcta .stamp {
2943            font-family: var(--mono);
2944            font-size: 11px;
2945            color: var(--mute);
2946            text-transform: uppercase;
2947            letter-spacing: .2em;
2948            margin-bottom: 24px;
2949            display: flex;
2950            justify-content: center;
2951            align-items: center;
2952            gap: 14px
2953        }
2954
2955        .endcta .stamp::before, .endcta .stamp::after {
2956            content: "";
2957            flex: 0 0 80px;
2958            height: 1px;
2959            background: var(--line)
2960        }
2961
2962        .endcta h2 {
2963            font-family: var(--serif);
2964            font-weight: 600;
2965            font-size: var(--t-display);
2966            line-height: var(--lh-display);
2967            letter-spacing: var(--ls-head)
2968        }
2969
2970        .endcta h2 .it {
2971            font-family: var(--serif);
2972            font-weight: 600;
2973            color: var(--signal)
2974        }
2975
2976        .endcta h2 .blue {
2977            font-family: var(--serif);
2978            font-weight: 600;
2979            color: var(--plasma-bright)
2980        }
2981
2982        /* The two numbers were pills with a circular icon badge each. In the V2
2983           language a number is a rule, a mono label and the figure itself: the
2984           same shape the price blocks use, so the closing line of every page
2985           rhymes with the pricing. The rule fills with the brand gradient on
2986           hover, which is the only affordance it needs. */
2987        .endcta .num-big {
2988            margin-top: 0;
2989            position: relative;
2990            display: block;
2991            text-align: left;
2992            padding: 26px 0 0;
2993            font-family: var(--serif);
2994            font-size: clamp(30px, 3.2vw, 44px);
2995            font-weight: 600;
2996            line-height: 1.1;
2997            letter-spacing: var(--ls-head);
2998            color: var(--paper);
2999            transition: color .3s var(--ease)
3000        }
3001
3002        .endcta .num-big::before, .endcta .num-big::after {
3003            content: "";
3004            position: absolute;
3005            top: 0;
3006            left: 0;
3007            right: 0;
3008            height: 1px
3009        }
3010
3011        .endcta .num-big::before {
3012            background: var(--line-2)
3013        }
3014
3015        .endcta .num-big::after {
3016            background: var(--grad);
3017            transform: scaleX(0);
3018            transform-origin: left;
3019            transition: transform .5s var(--ease-out)
3020        }
3021
3022        .endcta .num-big:hover::after {
3023            transform: scaleX(1)
3024        }
3025
3026        .endcta .num-big:hover {
3027            color: var(--signal)
3028        }
3029
3030        .endcta .num-big.num-blue:hover {
3031            color: var(--plasma-bright)
3032        }
3033
3034        /* the icon badges go with the pills */
3035        .endcta .num-big .ic {
3036            display: none
3037        }
3038
3039        .endcta .num-big small {
3040            display: block;
3041            margin-bottom: 14px;
3042            font-family: var(--mono);
3043            font-size: var(--t-label);
3044            color: var(--mute);
3045            letter-spacing: .18em;
3046            text-transform: uppercase;
3047            line-height: 1.5
3048        }
3049
3050        .endcta .endcta-meta {
3051            margin-top: 32px;
3052            display: flex;
3053            justify-content: center;
3054            gap: 32px;
3055            font-family: var(--mono);
3056            font-size: 11px;
3057            color: var(--mute);
3058            text-transform: uppercase;
3059            letter-spacing: .14em;
3060            flex-wrap: wrap
3061        }
3062
3063        /* ====== FOOTER ====== */
3064        .foot {
3065            padding: 80px var(--shell-pad) 32px;
3066            border-top: 1px solid var(--line);
3067            background: var(--ink-2)
3068        }
3069
3070        /* Brand block plus five link columns. Six tracks only pay off on a wide
3071           screen; between 1100 and 1400 the brand column gives ground and the
3072           gap tightens rather than the links wrapping to a second row. */
3073        .foot-grid {
3074            display: grid;
3075            grid-template-columns:2fr repeat(5, 1fr);
3076            gap: 48px;
3077            margin-bottom: 64px
3078        }
3079
3080        @media (max-width: 1400px) {
3081            .foot-grid {
3082                grid-template-columns:1.4fr repeat(5, 1fr);
3083                gap: 28px
3084            }
3085        }
3086
3087        .foot h4 {
3088            font-family: var(--mono);
3089            font-size: 11px;
3090            color: var(--mute);
3091            text-transform: uppercase;
3092            letter-spacing: .16em;
3093            margin-bottom: 16px
3094        }
3095
3096        .foot ul {
3097            list-style: none;
3098            display: flex;
3099            flex-direction: column;
3100            gap: 8px;
3101            font-size: 13px;
3102            color: var(--bone)
3103        }
3104
3105        .foot ul a {
3106            transition: .25s
3107        }
3108
3109        .foot ul a:hover {
3110            color: var(--signal)
3111        }
3112
3113        .foot-brand p {
3114            margin-top: 16px;
3115            color: var(--bone);
3116            font-size: 13px;
3117            line-height: 1.55;
3118            max-width: 36ch
3119        }
3120
3121        .foot-bot {
3122            display: flex;
3123            justify-content: space-between;
3124            align-items: center;
3125            padding-top: 32px;
3126            border-top: 1px solid var(--line);
3127            font-family: var(--mono);
3128            font-size: 11px;
3129            color: var(--mute);
3130            letter-spacing: .06em;
3131            flex-wrap: wrap;
3132            gap: 16px
3133        }
3134
3135        /* ====== V2 RULED VOCABULARY ======
3136           The shared shapes of the V2 design language, so a new section does
3137           not have to hand-roll the hairline pair again. The language is:
3138
3139             · no boxed cards. A block is a rule and the copy under it.
3140             · no icon marks, no tag pills, no lift-on-hover.
3141             · the rule fills with the brand gradient as the block scrolls in,
3142               which is the only motion a block gets.
3143             · a price, a phone number and a stat all take the same shape:
3144               a rule, a mono label, and a big serif figure.
3145
3146           Reach for these on anything new. The older components (.cap-plate,
3147           .step, .tier, .metric, .trade) carry their own copies of the same
3148           shapes because their markup predates this block; they are not worth
3149           rewriting just to share four declarations, but they must not drift.
3150
3151             <div class="ruled-set r">
3152               <div class="ruled-col">...</div>
3153             </div>
3154
3155           .r on the container is what starts the fill: the site-wide reveal
3156           observer adds .in, and .ruled-set.in is the trigger. */
3157        .ruled-set {
3158            display: grid;
3159            gap: clamp(20px, 2.6vw, 40px)
3160        }
3161
3162        .ruled-set.cols-2 { grid-template-columns:repeat(2, 1fr) }
3163        .ruled-set.cols-3 { grid-template-columns:repeat(3, 1fr) }
3164        .ruled-set.cols-4 { grid-template-columns:repeat(4, 1fr) }
3165
3166        .ruled-col {
3167            position: relative;
3168            padding: 30px 0 0
3169        }
3170
3171        .ruled-col::before, .ruled-col::after {
3172            content: "";
3173            position: absolute;
3174            top: 0;
3175            left: 0;
3176            right: 0;
3177            height: 1px
3178        }
3179
3180        .ruled-col::before { background: var(--line-2) }
3181
3182        .ruled-col::after {
3183            background: var(--grad);
3184            transform: scaleX(0);
3185            transform-origin: left;
3186            transition: transform .9s var(--ease-out)
3187        }
3188
3189        /* the reveal class lands on the container in most sections and on the
3190           column itself in a few, so both spellings start the fill */
3191        .ruled-set.in .ruled-col::after, .ruled-col.in::after {
3192            transform: scaleX(1)
3193        }
3194
3195        .ruled-set.in .ruled-col:nth-child(2)::after { transition-delay: .12s }
3196        .ruled-set.in .ruled-col:nth-child(3)::after { transition-delay: .24s }
3197        .ruled-set.in .ruled-col:nth-child(4)::after { transition-delay: .36s }
3198
3199        .ruled-col h3 {
3200            font-family: var(--serif);
3201            font-weight: 600;
3202            font-size: var(--t-h3);
3203            line-height: var(--lh-head);
3204            letter-spacing: var(--ls-head);
3205            color: var(--paper)
3206        }
3207
3208        .ruled-col h3 .it {
3209            font-family: var(--serif);
3210            font-style: normal;
3211            font-weight: 600;
3212            color: var(--signal)
3213        }
3214
3215        .ruled-col p {
3216            margin-top: 12px;
3217            color: var(--bone);
3218            font-size: var(--t-body);
3219            line-height: var(--lh-body)
3220        }
3221
3222        .ruled-col p b { color: var(--paper); font-weight: 500 }
3223
3224        .ruled-col .tag {
3225            margin-top: 18px;
3226            display: inline-block;
3227            font-family: var(--mono);
3228            font-weight: 500;
3229            font-size: var(--t-label);
3230            letter-spacing: var(--ls-label);
3231            text-transform: uppercase;
3232            color: var(--signal)
3233        }
3234
3235        /* A ruled index: numbered rows under one another, each a hairline, a
3236           name, a description and a tag. This is the /v2 service index and the
3237           shape the FAQ and the wellness escalation ladder both take. Rows may
3238           be links or plain divs; only the links get the sliding arrow.
3239
3240             <div class="rul
3240ed-index r">
3241               <a class="ruled-row" href="...">
3242                 <span class="num">01</span>
3243                 <span class="name">Fergus</span>
3244                 <span class="desc">...</span>
3245                 <span class="go"><span>Books visits</span><span class="arr">→</span></span>
3246               </a>
3247             </div> */
3248        .ruled-index {
3249            margin-top: 44px;
3250            border-bottom: 1px solid var(--line-2)
3251        }
3252
3253        .ruled-row {
3254            display: grid;
3255            grid-template-columns:64px minmax(160px, 240px) 1fr auto;
3256            gap: clamp(14px, 2vw, 28px);
3257            align-items: center;
3258            padding: 22px clamp(4px, 1vw, 12px);
3259            border-top: 1px solid var(--line-2);
3260            text-decoration: none;
3261            transition: background .3s var(--ease)
3262        }
3263
3264        .ruled-row .num {
3265            font-family: var(--mono);
3266            font-size: 11px;
3267            letter-spacing: .14em;
3268            color: var(--mute-2)
3269        }
3270
3271        .ruled-row .name {
3272            font-family: var(--serif);
3273            font-weight: 600;
3274            font-size: clamp(19px, 1.8vw, 24px);
3275            letter-spacing: -.01em;
3276            color: var(--paper);
3277            transition: color .3s var(--ease)
3278        }
3279
3280        .ruled-row .desc {
3281            color: var(--bone);
3282            font-size: var(--t-small);
3283            line-height: var(--lh-body)
3284        }
3285
3286        .ruled-row .go {
3287            display: inline-flex;
3288            align-items: center;
3289            gap: 14px;
3290            font-family: var(--mono);
3291            font-size: var(--t-label);
3292            letter-spacing: .14em;
3293            text-transform: uppercase;
3294            color: var(--mute);
3295            white-space: nowrap
3296        }
3297
3298        .ruled-row .go .arr {
3299            color: var(--signal);
3300            font-size: 15px;
3301            transition: transform .3s var(--ease-out)
3302        }
3303
3304        a.ruled-row:hover {
3305            background: var(--surface-2)
3306        }
3307
3308        a.ruled-row:hover .name {
3309            color: var(--signal)
3310        }
3311
3312        a.ruled-row:hover .go .arr {
3313            transform: translateX(6px)
3314        }
3315
3316        @media (max-width: 900px) {
3317            .ruled-row {
3318                grid-template-columns:40px 1fr auto
3319            }
3320
3321            .ruled-row .desc {
3322                grid-column:2 / 3;
3323                grid-row: 2;
3324                margin-top: 2px
3325            }
3326
3327            .ruled-row .go span:not(.arr) {
3328                display: none
3329            }
3330        }
3331
3332        /* ====== INTEGRATION WALL ======
3333           "Plugged into the software you already run", shared by the industry
3334           pages and the booking page. Replaces a bare grid of words whose cells
3335           were divided by a 1px gap, so "Microsoft" and "Outlook" ran together
3336           with nothing between one system and the next. Each system now gets
3337           its logo and room to breathe, which is the treatment /integrations
3338           already uses. Markup lives in frontend.partials.integration-wall. */
3339        .ig-wall {
3340            margin-top: 40px;
3341            display: grid;
3342            grid-template-columns:repeat(auto-fit, minmax(210px, 1fr));
3343            gap: clamp(20px, 2.4vw, 34px)
3344        }
3345
3346        .ig-item {
3347            display: flex;
3348            align-items: center;
3349            gap: 14px;
3350            padding: 20px 0 0;
3351            border-top: 1px solid var(--line-2);
3352            min-width: 0
3353        }
3354
3355        .ig-tile {
3356            flex: 0 0 44px;
3357            width: 44px;
3358            height: 44px;
3359            border-radius: 3px;
3360            border: 1px solid var(--line-2);
3361            display: grid;
3362            place-items: center;
3363            overflow: hidden
3364        }
3365
3366        .ig-tile.is-light {
3367            background: #fff
3368        }
3369
3370        .ig-tile img {
3371            width: 100%;
3372            height: 100%;
3373            object-fit: contain;
3374            padding: 7px
3375        }
3376
3377        .ig-tile b {
3378            font-family: var(--serif);
3379            font-size: 20px;
3380            font-weight: 400;
3381            line-height: 1
3382        }
3383
3384        .ig-name {
3385            font-family: var(--serif);
3386            font-weight: 400;
3387            font-size: 17px;
3388            line-height: 1.15;
3389            letter-spacing: -.01em;
3390            color: var(--paper);
3391            min-width: 0
3392        }
3393
3394        .ig-name small {
3395            display: block;
3396            margin-top: 4px;
3397            font-family: var(--mono);
3398            font-size: var(--t-label);
3399            letter-spacing: .14em;
3400            text-transform: uppercase;
3401            color: var(--mute)
3402        }
3403
3404        /* A price, a phone number, a headline figure: a heavier rule, a mono
3405           label and a big serif number. .is-pick marks the one being pushed. */
3406        .ruled-figure {
3407            border-top: 2px solid var(--line-2);
3408            padding: clamp(24px, 3vw, 40px) 0 0
3409        }
3410
3411        .ruled-figure.is-pick { border-top-color: var(--signal) }
3412
3413        .ruled-figure .lbl {
3414            display: block;
3415            font-family: var(--mono);
3416            font-size: 11px;
3417            letter-spacing: .18em;
3418            text-transform: uppercase;
3419            color: var(--mute)
3420        }
3421
3422        .ruled-figure .big {
3423            display: block;
3424            margin-top: 16px;
3425            font-family: var(--serif);
3426            font-weight: 600;
3427            font-size: clamp(46px, 5vw, 72px);
3428            line-height: 1;
3429            letter-spacing: -.03em;
3430            color: var(--paper)
3431        }
3432
3433        .ruled-figure .big small {
3434            font-family: var(--mono);
3435            font-size: 12px;
3436            letter-spacing: .08em;
3437            color: var(--mute)
3438        }
3439
3440        /* A list inside the ruled language leads with an arrow in the signal
3441           colour, over a dashed rule. No bullets, no ticks in circles. */
3442        .ruled-list {
3443            margin-top: 24px;
3444            list-style: none;
3445            display: flex;
3446            flex-direction: column;
3447            gap: 12px;
3448            border-top: 1px dashed var(--line);
3449            padding-top: 22px
3450        }
3451
3452        .ruled-list li {
3453            display: flex;
3454            gap: 12px;
3455            color: var(--bone);
3456            font-size: 14px;
3457            line-height: 1.5
3458        }
3459
3460        .ruled-list li::before {
3461            content: "\2192";
3462            color: var(--signal);
3463            font-family: var(--mono)
3464        }
3465
3466        /* The list started life as a list of statements. The trade and town
3467           indexes use it as navigation instead, so a link inside one has to
3468           read as a link: the arrow already leads the row, and this gives the
3469           words themselves the signal colour and something on hover. */
3470        .ruled-list li a {
3471            color: var(--signal);
3472            transition: color .2s var(--ease)
3473        }
3474
3475        .ruled-list li a:hover { color: var(--signal-warm) }
3476
3477        /* An aside is ruled down its edge rather than boxed in a tinted panel. */
3478        .ruled-aside {
3479            padding: 4px 0 4px 18px;
3480            border-left: 2px solid var(--plasma);
3481            color: var(--bone);
3482            font-size: 14px;
3483            line-height: 1.6
3484        }
3485
3486        .ruled-aside.is-ok { border-left-color: var(--signal) }
3487
3488        @media (prefers-reduced-motion: reduce) {
3489            .ruled-col::after { transition: none; transform: scaleX(1) }
3490        }
3491
3492        @media (max-width: 1000px) {
3493            .ruled-set.cols-3, .ruled-set.cols-4 { grid-template-columns:repeat(2, 1fr) }
3494        }
3495
3496        @media (max-width: 640px) {
3497            .ruled-set.cols-2, .ruled-set.cols-3, .ruled-set.cols-4 { grid-template-columns:1fr }
3498            .ruled-set.in .ruled-col::after { transition-delay: 0s }
3499        }
3500
3501        /* ====== SCROLL REVEAL ======
3502       .r hides a block until it scrolls into view. Two things it must never
3503       do: hold content back for a full second, and hide it for ever when the
3504       observer never runs. So the hidden state is applied only once the
3505       script has declared itself (html.js), and only where motion is wel
3505come.
3506       No JS, or reduced motion, means everything is simply visible. */
3507        html.js .r {
3508            opacity: 0;
3509            transform: translateY(16px);
3510            transition: opacity .4s var(--ease-out), transform .4s var(--ease-out)
3511        }
3512
3513        html.js .r.in {
3514            opacity: 1;
3515            transform: none
3516        }
3517
3518        .r-1 { transition-delay: .05s }
3519
3520        .r-2 { transition-delay: .1s }
3521
3522        @media (prefers-reduced-motion: reduce) {
3523            html.js .r, html.js .r.in, .r, .r.in {
3524                opacity: 1;
3525                transform: none;
3526                transition: none
3527            }
3528        }
3529
3530        /* ====== STEPS ====== */
3531        .steps {
3532            display: grid;
3533            grid-template-columns:repeat(3, 1fr);
3534            gap: clamp(20px, 3vw, 40px);
3535            margin-top: 56px;
3536            position: relative
3537        }
3538
3539        /* There was a connector line here, threaded through the middle of the
3540           circular step badges at a fixed 36px from the top. The badges are
3541           outlined numerals now and each step carries its own rule, so the
3542           connector had nothing left to connect and simply struck through the
3543           numbers. */
3544
3545        /* V2 numbered steps: a hairline over each that fills with the brand
3546           gradient as it scrolls in, rather than a filled card that lifts. */
3547        .step {
3548            position: relative;
3549            padding: 30px 0 0;
3550            display: flex;
3551            flex-direction: column;
3552            gap: 16px
3553        }
3554
3555        .step::before, .step::after {
3556            content: "";
3557            position: absolute;
3558            top: 0;
3559            left: 0;
3560            right: 0;
3561            height: 1px
3562        }
3563
3564        .step::before {
3565            background: var(--line-2)
3566        }
3567
3568        .step::after {
3569            background: var(--grad);
3570            transform: scaleX(0);
3571            transform-origin: left;
3572            transition: transform .9s var(--ease-out)
3573        }
3574
3575        .step.in::after, .steps.in .step::after {
3576            transform: scaleX(1)
3577        }
3578
3579        .steps.in .step:nth-child(2)::after {
3580            transition-delay: .12s
3581        }
3582
3583        .steps.in .step:nth-child(3)::after {
3584            transition-delay: .24s
3585        }
3586
3587        .step:hover::after {
3588            transform: scaleX(1)
3589        }
3590
3591        /* V2 numbers a step with a big outlined italic numeral rather than a
3592           digit inside a circular badge. */
3593        .step .num {
3594            font-family: var(--serif);
3595            font-weight: 600;
3596            font-size: 64px;
3597            line-height: 1;
3598            color: transparent;
3599            -webkit-text-stroke: 1px var(--line-2);
3600            position: relative;
3601            z-index: 1
3602        }
3603
3604        .step h4 {
3605            font-family: var(--serif);
3606            font-weight: 400;
3607            font-size: 24px;
3608            letter-spacing: -.01em;
3609            line-height: 1.1
3610        }
3611
3612        .step h4 .it {
3613            font-family: var(--serif);
3614            font-weight: 600;
3615            color: var(--mute)
3616        }
3617
3618        .step h4 {
3619            margin-top: 2px
3620        }
3621
3622        .step p {
3623            color: var(--bone);
3624            font-size: var(--t-body);
3625            line-height: 1.6
3626        }
3627
3628        .hero-steps-hd {
3629            margin-top: 34px;
3630            font-family: var(--serif);
3631            font-weight: 600;
3632            font-size: 34px;
3633            letter-spacing: -.02em;
3634            line-height: 1.1;
3635            color: var(--paper);
3636            opacity: 0;
3637            animation: rise2 .9s 1.1s var(--ease-out) forwards
3638        }
3639
3640        .hero-steps-hd .it {
3641            font-family: var(--serif);
3642            font-weight: 600;
3643            color: var(--signal)
3644        }
3645
3646        /* Vertical variant, so the steps can run down a narrow hero column
3647           beside a tall form instead of across the page. */
3648        .steps.stack {
3649            grid-template-columns:1fr;
3650            gap: 12px;
3651            margin-top: 30px;
3652            max-width: 560px
3653        }
3654
3655        .steps.stack::before {
3656            display: none
3657        }
3658
3659        .steps.stack .step {
3660            flex-direction: row;
3661            align-items: flex-start;
3662            gap: 20px;
3663            padding: 22px 0 0
3664        }
3665
3666        .steps.stack .step .num {
3667            flex: 0 0 auto;
3668            font-size: 40px;
3669            line-height: .9
3670        }
3671
3672        .steps.stack .step .body {
3673            display: grid;
3674            gap: 8px
3675        }
3676
3677        .steps.stack .step h4 {
3678            font-size: 20px
3679        }
3680
3681        .steps.stack .step p {
3682            font-size: 13px
3683        }
3684
3685        /* ====== CAPABILITY PLATE ======
3686           Capabilities in the V2 design language, the same vocabulary the /v2
3687           homepage and the wellness page use: top-ruled columns rather than
3688           boxed cards. Each cell is a hairline and the copy under it, and the
3689           hairline fills with the brand gradient as the plate scrolls in.
3690
3691           It was a filled, rounded plate whose cells were divided by letting a
3692           1px grid gap show the plate's own background through. That is 
3692what
3693           made a short last row read as a slab of grey, and what made the set
3694           look like cards floating on the page rather than part of it.
3695
3696           Each cell still leads with the moment in the call it fires, so the
3697           set reads as a timeline rather than a feature dump. */
3698        .cap-plate {
3699            display: grid;
3700            gap: clamp(22px, 3vw, 44px);
3701            grid-template-columns:repeat(3, 1fr)
3702        }
3703
3704        .cap {
3705            position: relative;
3706            padding: 30px 0 0;
3707            display: flex;
3708            flex-direction: column;
3709            gap: 10px
3710        }
3711
3712        /* the standing hairline, and the gradient that draws over it */
3713        .cap::before, .cap::after {
3714            content: "";
3715            position: absolute;
3716            top: 0;
3717            left: 0;
3718            right: 0;
3719            height: 1px
3720        }
3721
3722        .cap::before {
3723            background: var(--line-2)
3724        }
3725
3726        .cap::after {
3727            background: var(--grad);
3728            transform: scaleX(0);
3729            transform-origin: left;
3730            transition: transform .9s var(--ease-out)
3731        }
3732
3733        /* the plate carries .r, so the site-wide reveal observer is what starts
3734           the fill; the cells stagger across the row behind it */
3735        .cap-plate.in .cap::after {
3736            transform: scaleX(1)
3737        }
3738
3739        .cap-plate .cap:nth-child(3n + 2)::after {
3740            transition-delay: .12s
3741        }
3742
3743        .cap-plate .cap:nth-child(3n)::after {
3744            transition-delay: .24s
3745        }
3746
3747        /* No icon marks in this language: the rule and the type carry the cell,
3748           and a glyph per capability was the last of the card furniture. The
3749           mark is still rendered so the components keep their contract; it just
3750           has nothing to say here. */
3751        .cap-mark {
3752            display: none
3753        }
3754
3755        .cap .when {
3756            font-family: var(--mono);
3757            font-size: var(--t-label);
3758            letter-spacing: .16em;
3759            text-transform: uppercase;
3760            color: var(--signal);
3761            display: flex;
3762            align-items: center;
3763            justify-content: space-between;
3764            gap: 14px
3765        }
3766
3767        /* the mark is gone, so this is just the title's own line now */
3768        .cap-hd {
3769            display: block
3770        }
3771
3772        .cap h3 {
3773            font-family: var(--serif);
3774            font-weight: 400;
3775            font-size: 24px;
3776            line-height: 1.14;
3777            letter-spacing: -.012em;
3778            color: var(--paper);
3779            padding-bottom: 2px
3780        }
3781
3782        .cap h3 .it {
3783            font-family: var(--serif);
3784            font-weight: 600;
3785            color: var(--signal)
3786        }
3787
3788        .cap h3 .blue {
3789            font-family: var(--serif);
3790            font-weight: 600;
3791            color: var(--plasma-bright)
3792        }
3793
3794        /* .green was never styled inside the old bento h4s, so it rendered as
3795           flat body text there. Carried onto the plate it gets the same
3796           treatment as .it, matching the tuner headings. */
3797        .cap h3 .green {
3798            font-family: var(--serif);
3799            font-weight: 600;
3800            color: var(--signal)
3801        }
3802
3803        .cap p {
3804            color: var(--bone);
3805            font-size: var(--t-body);
3806            line-height: 1.62
3807        }
3808
3809        .cap p b {
3810            color: var(--paper);
3811            font-weight: 500
3812        }
3813
3814        /* The closing call to action sits under the plate rather than in it. As
3815           a cell it was three times the width of its neighbours and read as a
3816           row that had failed to fill, so it carries no fill of its own.
3817
3818           It does carry a rule across the full width, which is what closes the
3819           plate off now that the plate has no border: the cells are ruled at
3820           the top, this rules underneath them, and the set reads as one block
3821           rather than a run of columns that simply stops. */
3822        .cap-foot {
3823            display: flex;
3824            align-items: center;
3825            justify-content: space-between;
3826            flex-wrap: wrap;
3827            gap: 20px 36px;
3828            margin-top: clamp(38px, 4vw, 56px);
3829            padding: clamp(26px, 3vw, 38px) 0 0;
3830            border-top: 1px solid var(--line-2)
3831        }
3832
3833        .cap-foot > div {
3834            max-width: 62ch;
3835            display: flex;
3836            flex-direction: column;
3837            gap: 8px
3838        }
3839
3840        .cap-foot h3 {
3841            font-family: var(--serif);
3842            font-weight: 600;
3843            font-size: 26px;
3844            line-height: 1.2;
3845            letter-spacing: -.015em;
3846            color: var(--paper);
3847            margin: 0
3848        }
3849
3850        .cap-foot h3 .it {
3851            font-family: var(--serif);
3852            font-weight: 600;
3853        }
3854
3855        .cap-foot p {
3856            font-size: var(--t-body);
3857            line-height: 1.6;
3858            color: var(--mute);
3859            margin: 0
3860        }
3861
3862        @media (max-width: 640px) {
3863            .cap-foot {
3864                margin-top: 24px
3865            }
3866
3867            .cap-foot h3 {
3868                font-size: 22px
3869            }
3870        }
3871
3872        /* Industry pages keep their own emphasis: two lead cells across the
3873           top, three underneath. A six-column track divides cleanly both ways,
3874           so neither row is left with a hole. */
3875        .cap-plate.mixed {
3876            grid-template-columns:repeat(6, 1fr)
3877        }
3878
3879        .cap-plate.mixed .cap.half {
3880            grid-column:span 3
3881        }
3882
3883        .cap-plate.mixed .cap.third {
3884            grid-column:span 2
3885        }
3886
3887        /* There used to be a set of rules here that stretched whatever was left
3888           alone on the final row so it filled the width. That existed only
3889           because the old plate drew its rules by letting its own background
3890           through a 1px grid gap, so a row the cells did not fill showed up as
3891           a slab of grey.
3892
3893           Top-ruled columns have no fill to show through, so a short last row
3894           is simply empty space and needs no correction. Stretching a lone cell
3895           now would be actively wrong: its hairline would run three times the
3896           length of every other cell's and break the measure. The plates are
3897           still authored to fill their rows, and CapabilityPlateTest still
3898           guards that, but it is a composition rule now rather than a patch
3899           over an artefact.
3900
3901           (The old block also had a stray half-comment in it, which made the
3902           browser discard the first of the two rules outright.) */
3903
3904        @media (max-width: 1000px) {
3905            .cap-plate {
3906                grid-template-columns:repeat(2, 1fr)
3907            }
3908
3909            .cap-plate.mixed {
3910                grid-template-columns:repeat(2, 1fr)
3911            }
3912
3913            .cap-plate.mixed .cap.half,
3914            .cap-plate.mixed .cap.third {
3915                grid-column:auto
3916            }
3917
3918            /* two across, so the three-column stagger no longer describes a row */
3919            .cap-plate .cap:nth-child(3n + 2)::after,
3920            .cap-plate .cap:nth-child(3n)::after {
3921                transition-delay: 0s
3922            }
3923
3924            .cap-plate .cap:nth-child(even)::after {
3925                transition-delay: .12s
3926            }
3927        }
3928
3929        @media (max-width: 640px) {
3930            .cap-plate,
3931            .cap-plate.mixed {
3932                grid-template-columns:1fr
3933            }
3934
3935            /* one column, so nothing is beside anything: no stagger */
3936            .cap-plate .cap::after {
3937                transition-delay: 0s
3938            }
3939
3940            .cap.wide {
3941                flex-direction: column;
3942                align-items: flex-start
3943            }
3944        }
3945
3946        @media (prefers-reduced-motion: reduce) {
3947            .cap::after {
3948                transition: none;
3949                transform: scaleX(1)
3950            }
3951        }
3952
3953        /* ====== HERO PHONE ======
3954           The one device mock on the site. It earns its place by being
3955           interactive: the chips drive the notification and pause the cycle. */
3956        .hphone {
3957            display: flex;
3958            flex-direction: column;
3959            align-items: center;
3960            gap: 20px;
3961            width: 100%
3962        }
3963
3964        .hphone-frame {
3965            width: min(268px, 72vw);
3966            aspect-ratio: 9/18.6;
3967            border-radius: 38px;
3968            padding: 9px;
3969            background: linear-gradient(160deg, #23262b, #0e1013 60%, #191c20);
3970            box-shadow: 0 30px 70px var(--shadow-deep), 0 0 0 1px rgba(255, 255, 255, .07) inset;
3971            flex: 0 0 auto
3972        }
3973
3974        .hphone-screen {
3975            position: relative;
3976            height: 100%;
3977            border-radius: 30px;
3978            overflow: hidden;
3979            background: radial-gradient(120% 80% at 50% 0%, #1c2330, #0a0d12 70%);
3980            display: flex;
3981            flex-direction: column;
3982            padding: 26px 12px 14px
3983        }
3984
3985        .hphone-notch {
3986            position: absolute;
3987            top: 8px;
3988            left: 50%;
3989            transform: translateX(-50%);
3990            width: 78px;
3991            height: 20px;
3992            border-radius: 12px;
3993            background: #05070a
3994        }
3995
3996        .hphone-clock {
3997            text-align: center;
3998            margin: 14px 0 18px;
3999            color: #fff
4000        }
4001
4002        .hphone-clock .t {
4003            font-size: 46px;
4004            font-weight: 300;
4005            letter-spacing: -.02em;
4006            line-height: 1
4007        }
4008
4009        .hphone-clock .d {
4010            font-size: 11.5px;
4011            color: rgba(255, 255, 255, .68);
4012            margin-top: 4px
4013        }
4014
4015        .hphone-stack {
4016            display: flex;
4017            flex-direction: column;
4018            gap: 7px;
4019            flex: 1
4020        }
4021
4022        .hpn {
4023            background: rgba(238, 238, 240, .93);
4024            border-radius: 16px;
4025            padding: 9px 11px 11px;
4026            opacity: 0;
4027            /* drops in from above the notch with a little overshoot, the way a
4028               push actually arrives, rather than fading on the spot */
4029            transform: translateY(-22px) scale(.94);
4030            transition: opacity .42s var(--ease-out),
4031                        transform .62s cubic-bezier(.22, 1.4, .36, 1);
4032            pointer-events: none
4033        }
4034
4035        .hpn.is-in {
4036            opacity: 1;
4037            transform: none
4038        }
4039
4040        .hpn header {
4041            display: flex;
4042            align-items: center;
4043            gap: 6px;
4044            margin-bottom: 5px
4045        }
4046
4047        .hpn header img {
4048            border-radius: 5px;
4049            display: block
4050        }
4051
4052        /* hpn- prefixed: a bare .app collides with the app showcase panel,
4053           which is an 80px-padded gradient grid, and it ate the header */
4054        .hpn .hpn-app {
4055            font-size: 10.5px;
4056            color: #63666b;
4057            flex: 1
4058        }
4059
4060        .hpn .hpn-ago {
4061            font-size: 10.5px;
4062            color: #8b8e93
4063        }
4064
4065        .hpn h4 {
4066            font-size: 13.5px;
4067            font-weight: 600;
4068            color: #14171a;
4069            letter-spacing: -.005em
4070        }
4071
4072        .hpn p {
4073            font-size: 11.5px;
4074            color: #4e5155;
4075            margin-top: 1px;
4076            line-height: 1.35
4077        }
4078
4079        .hphone-bar {
4080            width: 96px;
4081            height: 4px;
4082            border-radius: 4px;
4083            background: rgba(255, 255, 255, .55);
4084            margin: 8px auto 0
4085        }
4086
4087        /* A LOCK SCREEN THAT PLAYS. Used by the PA and reception panels, which
4088           tell the same story with different notifications. See
4089           partials/agent-phone.blade.php.
4090
4091           --ag-tilt and --ag-sheen are written by the scroll handler; the
4092           values here are the resting state before it runs and whenever motion
4093           is refused. The two panels lean opposite ways so the pair reads as a
4094           spread rather than as the same picture twice. */
4095        .agent-phone {
4096            transform: rotate(var(--ag-tilt, 3deg));
4097            transition: transform .25s linear
4098        }
4099
4100        .agent-phone--left {
4101            --ag-tilt: -3deg
4102        }
4103
4104        .agent-phone .hphone-frame {
4105            position: relative;
4106            overflow: hidden
4107        }
4108
4109        /* The sheen is what sells the front as glass rather than as a
4110           rectangle. Decorative only: nothing sits under it. */
4111        .agent-phone .hphone-frame::after {
4112            content: "";
4113            position: absolute;
4114            inset: -30%;
4115            pointer-events: none;
4116            z-index: 3;
4117            background: linear-gradient(105deg,
4118                transparent 38%,
4119                rgba(255, 255, 255, .13) 47%,
4120                rgba(255, 255, 255, .22) 50%,
4121                rgba(255, 255, 255, .13) 53%,
4122                transparent 62%);
4123            transform: translateX(var(--ag-sheen, -20%));
4124            transition: transform .25s linear
4125        }
4126
4127        /* iOS shrinks the clock and lifts it the moment something lands on a
4128           locked screen. Doing the same is what makes the notifications read as
4129           arriving rather than as part of the wallpaper. */
4130        .agent-phone .hphone-clock {
4131            transition: margin .55s var(--ease-out)
4132        }
4133
4134        .agent-phone .hphone-clock .t {
4135            transition: font-size .55s var(--ease-out)
4136        }
4137
4138        .agent-phone .hphone-clock .d {
4139            transition: font-size .55s var(--ease-out), opacity .4s var(--ease)
4140        }
4141
4142        .agent-phone .hphone-clock.is-compact {
4143            margin: 2px 0 12px
4144        }
4145
4146        .agent-phone .hphone-clock.is-compact .t {
4147            font-size: 21px
4148        }
4149
4150        .agent-phone .hphone-clock.is-compact .d {
4151            font-size: 10px;
4152            opacity: .8
4153        }
4154
4155        @media (prefers-reduced-motion: reduce) {
4156            .agent-phone,
4157            .agent-phone .hphone-clock,
4158            .agent-phone .hphone-clock .t,
4159            .agent-phone .hphone-clock .d,
4160            .agent-phone .hphone-frame::after {
4161                transition: none
4162            }
4163
4164            .agent-phone {
4165                transform: none
4166            }
4167
4168            .agent-phone .hphone-frame::after {
4169                display: none
4170            }
4171        }
4172
4173        .hphone-chips {
4174            display: flex;
4175            flex-wrap: wrap;
4176            justify-content: center;
4177            gap: 7px;
4178            max-width: 340px
4179        }
4180
4181        .hpc {
4182            font-family: var(--mono);
4183            font-size: var(--t-label);
4184            letter-spacing: .1em;
4185            text-transform: uppercase;
4186            /* --bone not --mute: the label is 10px, so it needs AA, and mute
4187               only clears 3:1 against the chip fill in light theme */
4188            color: var(--bone);
4189            background: var(--surface-2);
4190            border: 1px solid var(--line);
4191            border-radius: 7px;
4192            padding: 6px 9px;
4193            cursor: pointer;
4194            transition: color .25s var(--ease), border-color .25s var(--ease), background .25s var(--ease)
4195        }
4196
4197        .hpc:hover {
4198            color: var(--paper);
4199            border-color: var(--line-2)
4200        }
4201
4202        .hpc.is-on {
4203            /* fixed dark ink rather than --on-accent: it has to clear AA on
4204               both the light-theme green and the brighter dark-theme one */
4205            color: #0b0d0a;
4206            background: var(--signal);
4207            border-color: transparent
4208        }
4209
4210        .hpc:focus-visible {
4211            outline: 2px solid var(--plasma-bright);
4212            outline-offset: 2px
4213        }
4214
4215        @media (max-width: 900px) {
4216            .hphone {
4217                margin-top: 34px
4218            }
4219
4220            .hphone-frame {
4221                width: min(232px, 62vw)
4222            }
4223        }
4224
4225        @media (prefers-reduced-motion: reduce) {
4226            .hpn {
4227                transition: none
4228            }
4229        }
4230
4231        /* ====== TRADE INDEX ======
4232           Photographic directory. The tiles were held inside one rounded,
4233           filled container and ruled off each other by letting its background
4234           through a 1px grid gap. In the V2 language the container goes and the
4235           tiles are ruled individually, so the set sits on the page rather than
4236           on a plate laid over it. The photography stays: V2 keeps photographs,
4237           it is the boxes around them it does without. */
4238        .trade-plate {
4239            display: grid;
4240            gap: clamp(20px, 2.6vw, 36px)
4241        }
4242
4243        .trade-plate.cols-3 {
4244            grid-template-columns:repeat(3, 1fr)
4245        }
4246
4247        .trade-plate.cols-4 {
4248            grid-template-columns:repeat(4, 1fr)
4249        }
4250
4251        /* four across is tighter, so the type steps down with it */
4252        .trade-plate.cols-4 .body {
4253            padding: 19px 20px 18px;
4254            gap: 8px
4255        }
4256
4257        .trade-plate.cols-4 h3 {
4258            font-size: 20px
4259        }
4260
4261        .trade-plate.cols-4 p {
4262            font-size: 13px;
4263            line-height: 1.55
4264        }
4265
4266        .trade-plate.cols-4 .go {
4267            padding-top: 13px;
4268            font-size: 10px
4269        }
4270
4271        .trade {
4272            position: relative;
4273            display: flex;
4274            flex-direction: column;
4275            text-decoration: none;
4276            color: inherit;
4277            transition: background .35s var(--ease)
4278        }
4279
4280        .trade:hover {
4281            background: var(--surface-2)
4282        }
4283
4284        .trade .shot {
4285            position: relative;
4286            aspect-ratio: 16/10;
4287            overflow: hidden;
4288            /* the notification card inside is sized in cqw against this */
4289            container-type: inline-size
4290        }
4291
4292        /* THE NOTIFICATION ON A PHOTOGRAPH. See components/frontend/shot-alert.
4293           It used to be composited into the JPEG, which pinned it to one spot
4294           in a portrait frame and froze an old mark inside it. Drawn here it
4295           takes the mark from the brand component and sits where each context
4296           needs it.
4297
4298           Everything is derived from one unit, --u, so the whole card scales
4299           together: type, padding, corner radius, mark and tail all stay in
4300           proportion at every tile size. The card is 56 units wide, and .75cqw
4301           makes that 42% of the photo, which is the proportion the composited
4302           card had and the one the crops were framed around.
4303
4304           The clamp holds both ends of that. Below about a 350px tile a strict
4305           42% would put the subtitle under 10px, so the card is allowed to take
4306           a larger share of a small photo rather than become unreadable on it.
4307           Above about a 730px tile it stops growing, because past that the card
4308           has stopped reading as a notification and started reading as a
4309           banner. Anything holding a .shot-alert needs container-type:
4310           inline-size for cqw to resolve.
4311
4312           Light in both themes on purpose: it sits on a daylight photograph,
4313           not on the page. */
4314        .shot-alert {
4315            --u: clamp(3.1px, .75cqw, 5.5px);
4316            --alert-ground: rgba(244, 244, 242, .93);
4317            position: absolute;
4318            z-index: 2;
4319            display: flex;
4320            flex-direction: column;
4321            gap: calc(1.1 * var(--u));
4322            width: calc(56 * var(--u));
4323            padding: calc(3.6 * var(--u)) calc(4 * var(--u)) calc(4 * var(--u));
4324            border-radius: calc(4.4 * var(--u));
4325            background: var(--alert-ground);
4326            backdrop-filter: blur(7px);
4327            -webkit-backdrop-filter: blur(7px);
4328            box-shadow: 0 calc(3 * var(--u)) calc(6 * var(--u)) calc(-2 * var(--u)) rgba(8, 12, 16, .32);
4329            color: #101820;
4330            font-family: var(--sans);
4331            line-height: 1.25;
4332            text-wrap: balance;
4333            pointer-events: none
4334        }
4335
4336        /* the tail, on the side the card is anchored to */
4337        .shot-alert::after {
4338            content: "";
4339            position: absolute;
4340            bottom: calc(-2.6 * var(--u));
4341            width: 0;
4342            height: 0;
4343            border-top: calc(3 * var(--u)) solid var(--alert-ground);
4344            border-right: calc(3.4 * var(--u)) solid transparent
4345        }
4346
4347        /* Insets stay a fraction of the photo rather than of the card, so the
4348           gap to the frame edge reads the same on a tile and on a hero. */
4349        .shot-alert.at-top-left, .shot-alert.at-bottom-left {
4350            left: min(4cqw, 24px)
4351        }
4352
4353        .shot-alert.at-top-right, .shot-alert.at-bottom-right {
4354            right: min(4cqw, 24px)
4355        }
4356
4357        .shot-alert.at-top-left, .shot-alert.at-top-right {
4358            top: min(4.5cqw, 26px)
4359        }
4360
4361        .shot-alert.at-bottom-left, .shot-alert.at-bottom-right {
4362            bottom: min(7cqw, 40px)
4363        }
4364
4365        .shot-alert.at-top-left::after, .shot-alert.at-bottom-left::after {
4366            left: calc(9 * var(--u))
4367        }
4368
4369        .shot-alert.at-top-right::after, .shot-alert.at-bottom-right::after {
4370            right: calc(9 * var(--u));
4371            border-right: 0;
4372            border-left: calc(3.4 * var(--u)) solid transparent
4373        }
4374
4375        /* a card anchored to the bottom points its tail upward instead */
4376        .shot-alert.at-bottom-left::after, .shot-alert.at-bottom-right::after {
4377            bottom: auto;
4378            top: calc(-2.6 * var(--u));
4379            border-top: 0;
4380            border-bottom: calc(3 * var(--u)) solid var(--alert-ground)
4381        }
4382
4383        .shot-alert-hd {
4384            display: flex;
4385            align-items: center;
4386            gap: calc(1.8 * var(--u))
4387        }
4388
4389        .shot-alert-mark {
4390            width: calc(5.2 * var(--u));
4391            height: calc(5.2 * var(--u));
4392            flex: none
4393        }
4394
4395        .shot-alert-app {
4396            font-size: calc(2.8 * var(--u));
4397            font-weight: 500;
4398            color: #5b6570
4399        }
4400
4401        .shot-alert-stamp {
4402            margin-left: auto;
4403            font-size: calc(2.66 * var(--u));
4404            color: #8c949d
4405        }
4406
4407        .shot-alert-title {
4408            font-size: calc(3.86 * var(--u));
4409            font-weight: 600;
4410            letter-spacing: -.01em
4411        }
4412
4413        .shot-alert-body {
4414            font-size: calc(3.06 * var(--u));
4415            color: #3d4650
4416        }
4417
4418        /* Four across on a small laptop makes a tile barely wider than the card
4419           itself. The floor has already stopped the type shrinking, so the only
4420           thing left to give is the detail line: below this the card keeps the
4421           headline and drops the rest, the way a notification does when the
4422           space it has is one line deep. */
4423        @container (max-width: 300px) {
4424            .shot-alert-body {
4425                display: none
4426            }
4427        }
4428
4429        /* inner layer carries the photo so the scale-on-hover never touches type */
4430        .trade .shot i {
4431            position: absolute;
4432            inset: 0;
4433            background-image: var(--shot-dark);
4434            background-size: cover;
4435            /* --pos is set per entry: the source photos are a mix of portrait
4436               and landscape, so each one gets its own crop anchor to keep the
4437               face and the phone in frame */
4438            background-position: var(--pos, center);
4439            filter: saturate(.8) contrast(1.03);
4440            transform: scale(1.01);
4441            transition: transform .9s var(--ease-out), filter .5s var(--ease)
4442        }
4443
4444        html[data-theme="light"] .trade .shot i {
4445            background-image: var(--shot-light, var(--shot-dark));
4446            /* two of the day shots are portrait where their night twin is
4447               landscape, so they need their own anchor */
4448            background-position: var(--pos-light, var(--pos, center))
4449        }
4450
4451        .trade:hover .shot i {
4452            transform: scale(1.06);
4453            filter: none
4454        }
4455
4456        /* brand rule wipes along the photo edge, standing in for a hover lift */
4457        .trade .shot::after {
4458            content: "";
4459            position: absolute;
4460            top: 0;
4461            left: 0;
4462            right: 0;
4463            height: 2px;
4464            background: var(--grad);
4465            transform: scaleX(0);
4466            transform-origin: left;
4467            transition: transform .55s var(--ease-out)
4468        }
4469
4470        .trade:hover .shot::after {
4471            transform: scaleX(1)
4472        }
4473
4474        .trade .body {
4475            flex: 1;
4476            display: flex;
4477            flex-direction: column;
4478            gap: 9px;
4479            padding: 22px 24px 20px
4480        }
4481
4482        .trade .hd {
4483            display: flex;
4484            align-items: flex-start;
4485            justify-content: space-between;
4486            gap: 18px
4487        }
4488
4489        .trade h3 {
4490            font-family: var(--serif);
4491            font-weight: 400;
4492            font-size: 23px;
4493            line-height: 1.14;
4494            letter-spacing: -.012em;
4495            padding-bottom: 2px
4496        }
4497
4498        .trade h3 .it {
4499            font-family: var(--serif);
4500            font-weight: 600;
4501            color: var(--signal)
4502        }
4503
4504        .trade h3 .blue {
4505            font-family: var(--serif);
4506            font-weight: 600;
4507            color: var(--plasma-bright)
4508        }
4509
4510        /* the mark: bare glyph, no tile, no fill, muted until you reach for it.
4511           --mute not --mute-2: mute-2 only clears 2.8:1 on the light paper
4512           ground, which fails both the AA text and the 3:1 graphics minimum */
4513        .trade .mark {
4514            flex: 0 0 auto;
4515            color: var(--mute);
4516            transition: color .35s var(--ease)
4517        }
4518
4519        .trade:hover .mark {
4520            color: var(--signal)
4521        }
4522
4523        .trade p {
4524            color: var(--bone);
4525            font-size: var(--t-small);
4526            line-height: 1.58
4527        }
4528
4529        .trade .go {
4530            margin-top: auto;
4531            padding-top: 16px;
4532            display: flex;
4533            align-items: center;
4534            gap: 9px;
4535            font-family: var(--mono);
4536            font-size: var(--t-label);
4537            letter-spacing: .16em;
4538            text-transform: uppercase;
4539            color: var(--mute);
4540            transition: color .35s var(--ease)
4541        }
4542
4543        .trade:hover .go {
4544            color: var(--paper)
4545        }
4546
4547        .trade .go em {
4548            font-style: normal;
4549            transition: transform .35s var(--ease-out)
4550        }
4551
4552        .trade:hover .go em {
4553            transform: translateX(5px)
4554        }
4555
4556        /* full-width entry: photo becomes a left band, rule wipes down its edge */
4557        .trade.wide {
4558            grid-column:1 / -1;
4559            flex-direction: row;
4560            align-items: stretch
4561        }
4562
4563        .trade.wide .shot {
4564            flex: 0 0 36%;
4565            aspect-ratio: auto;
4566            min-height: 216px
4567        }
4568
4569        .trade.wide .shot::after {
4570            top: 0;
4571            bottom: 0;
4572            left: 0;
4573            right: auto;
4574            width: 2px;
4575            height: auto;
4576            transform: scaleY(0);
4577            transform-origin: top
4578        }
4579
4580        .trade.wide:hover .shot::after {
4581            transform: scaleY(1)
4582        }
4583
4584        .trade.wide .body {
4585            justify-content: center;
4586            padding: 34px 38px;
4587            max-width: 62ch
4588        }
4589
4590        .trade.wide h3 {
4591            font-size: 30px
4592        }
4593
4594        .trade.wide p {
4595            font-size: var(--t-body)
4596        }
4597
4598        /* compact ruled entries for the non-trade set: no photo, mark leads the row */
4599        /* The row variant carries no photo, so it is the V2 service index: a
4600           hairline over each row, the name, the description, and the tag with
4601           an arrow that slides on hover. It used to be a filled bar with a
4602           gradient stripe running down its left edge and an icon opposite. */
4603        .trade-plate:has(.trade.row) {
4604            gap: 0;
4605            border-bottom: 1px solid var(--line-2)
4606        }
4607
4608        .trade.row {
4609            flex-direction: row;
4610            align-items: center;
4611            gap: clamp(14px, 2vw, 28px);
4612            padding: 22px clamp(4px, 1vw, 12px);
4613            border-top: 1px solid var(--line-2)
4614        }
4615
4616        /* the icon mark goes with the boxes */
4617        .trade.row .mark {
4618            display: none
4619        }
4620
4621        .trade.row h3 {
4622            flex: 0 0 clamp(190px, 21vw, 270px);
4623            font-family: var(--serif);
4624            font-weight: 400;
4625            font-size: clamp(19px, 1.8vw, 24px);
4626            letter-spacing: -.01em;
4627            color: var(--paper);
4628            transition: color .3s var(--ease)
4629        }
4630
4631        .trade.row:hover h3 {
4632            color: var(--signal)
4633        }
4634
4635        .trade.row .go em {
4636            display: inline-block;
4637            color: var(--signal);
4638            font-style: normal;
4639            transition: transform .3s var(--ease-out)
4640        }
4641
4642        .trade.row:hover .go em {
4643            transform: translateX(6px)
4644        }
4645
4646        .trade.row p {
4647            flex: 1
4648        }
4649
4650        .trade.row .go {
4651            margin: 0;
4652            padding: 0;
4653            flex: 0 0 auto
4654        }
4655
4656        @media (max-width: 1240px) {
4657            .trade-plate.cols-4 {
4658                grid-template-columns:repeat(3, 1fr)
4659            }
4660        }
4661
4662        @media (max-width: 940px) {
4663            .trade-plate.cols-4 {
4664                grid-template-columns:repeat(2, 1fr)
4665            }
4666        }
4667
4668        @media (max-width: 1100px) {
4669            .trade-plate.cols-3 {
4670                grid-template-columns:repeat(2, 1fr)
4671            }
4672
4673            .trade.row h3 {
4674                flex-basis: 210px
4675            }
4676
4677            .trade.row .go span {
4678                display: none
4679            }
4680        }
4681
4682        @media (max-width: 640px) {
4683            .trade-plate.cols-4 {
4684                grid-template-columns:1fr
4685            }
4686
4687            .trade-plate.cols-3 {
4688                grid-template-columns:1fr
4689            }
4690
4691            .trade.wide {
4692                flex-direction: column
4693            }
4694
4695            .trade.wide .shot {
4696                flex: none;
4697                aspect-ratio: 16/9;
4698                min-height: 0
4699            }
4700
4701            .trade.wide .shot::after {
4702                top: 0;
4703                bottom: auto;
4704                left: 0;
4705                right: 0;
4706                width: auto;
4707                height: 2px;
4708                transform: scaleX(0);
4709                transform-origin: left
4710            }
4711
4712            .trade.wide:hover .shot::after {
4713                transform: scaleX(1)
4714            }
4715
4716            .trade.wide .body {
4717                padding: 22px 24px 20px
4718            }
4719
4720            .trade.wide h3 {
4721                font-size: 24px
4722            }
4723
4724            .trade.row {
4725                flex-direction: column;
4726                align-items: flex-start;
4727                gap: 10px;
4728                padding: 22px 24px
4729            }
4730
4731            .trade.row h3 {
4732                flex: none
4733            }
4734
4735            .trade.row .go span {
4736                display: inline
4737            }
4738        }
4739
4740        @media (prefers-reduced-motion: reduce) {
4741            .trade, .trade .shot i, .trade .shot::after, .trade .mark, .trade .go, .trade .go em, .trade.row::before {
4742                transition: none
4743            }
4744
4745            .trade:hover .shot i {
4746                transform: scale(1.01)
4747            }
4748        }
4749
4750        /* ====== CONVO ====== */
4751        .convo {
4752            display: flex;
4753            flex-direction: column;
4754            gap: 14px;
4755            max-width: 760px;
4756            margin: 0 auto;
4757            font-family: var(--mono);
4758            font-size: 13px
4759        }
4760
4761        .convo .bub {
4762            padding: 14px 18px;
4763            border-radius: 14px;
4764            border: 1px solid var(--line);
4765            max-width: 78%;
4766            line-height: 1.55;
4767            position: relative;
4768            opacity: 0;
4769            transform: translateY(12px) scale(.97);
4770            transition: opacity .55s var(--ease-out), transform .55s var(--ease-out)
4771        }
4772
4773        .convo .bub.in {
4774            opacity: 1;
4775            transform: translateY(0) scale(1)
4776        }
4777
4778        .convo .bub.caller {
4779            align-self: flex-start;
4780            background: rgba(49, 138, 190, .06);
4781            border-color: rgba(49, 138, 190, .25);
4782            color: var(--paper);
4783            border-bottom-left-radius: 4px
4784        }
4785
4786        .convo .bub.agent {
4787            align-self: flex-end;
4788            background: color-mix(in srgb, var(--signal) 6%, transparent);
4789            border-color: color-mix(in srgb, var(--signal) 25%, transparent);
4790            color: var(--paper);
4791            border-bottom-right-radius: 4px
4792        }
4793
4794        .convo .bub .lbl {
4795            font-size: 9px;
4796            color: var(--mute);
4797            text-transform: uppercase;
4798            letter-spacing: .2em;
4799            display: block;
4800            margin-bottom: 6px
4801        }
4802
4803        .convo .bub.caller .lbl {
4804            color: var(--plasma-bright)
4805        }
4806
4807        .convo .bub.agent .lbl {
4808            color: var(--signal)
4809        }
4810
4811        /* Typing indicator inside .convo */
4812        .convo-typing {
4813            align-self: flex-end;
4814            background: color-mix(in srgb, var(--signal) 6%, transparent);
4815            border: 1px solid color-mix(in srgb, var(--signal) 25%, transparent);
4816            border-radius: 14px;
4817            border-bottom-right-radius: 4px;
4818            padding: 14px 18px;
4819            display: none;
4820            align-items: center;
4821            gap: 10px;
4822            opacity: 0;
4823            transition: opacity .25s ease
4824        }
4825
4826        .convo-typing.on {
4827            display: inline-flex;
4828            opacity: 1
4829        }
4830
4831        .convo-typing.caller {
4832            align-self: flex-start;
4833            background: rgba(49, 138, 190, .06);
4834            border-color: rgba(49, 138, 190, .25);
4835            border-bottom-left-radius: 4px;
4836            border-bottom-right-radius: 14px
4837        }
4838
4839        .convo-typing .lbl {
4840            font-size: 9px;
4841            color: var(--signal);
4842            text-transform: uppercase;
4843            letter-spacing: .2em
4844        }
4845
4846        .convo-typing.caller .lbl {
4847            color: var(--plasma-bright)
4848        }
4849
4850        .convo-typing .dotset {
4851            display: inline-flex;
4852            gap: 4px;
4853            align-items: center
4854        }
4855
4856        .convo-typing .dotset i {
4857            width: 6px;
4858            height: 6px;
4859            border-radius: 50%;
4860            background: var(--signal);
4861            opacity: .4;
4862            animation: typingDot 1.2s ease-in-out infinite
4863        }
4864
4865        .convo-typing.caller .dotset i {
4866            background: var(--plasma)
4867        }
4868
4869        .convo-typing .dotset i:nth-child(2) {
4870            animation-delay: .2s
4871        }
4872
4873        .convo-typing .dotset i:nth-child(3) {
4874            animation-delay: .4s
4875        }
4876
4877        /* ====== INTEGRATION LOGOS ROW ====== */
4878        .integrations {
4879            display: grid;
4880            grid-template-columns:repeat(6, 1fr);
4881            gap: 1px;
4882            background: var(--line);
4883            border-top: 1px solid var(--line);
4884            border-bottom: 1px solid var(--line);
4885            overflow: hidden
4886        }
4887
4888        .integrations .ig {
4889            padding: 24px;
4890            background: var(--ink);
4891            display: flex;
4892            align-items: center;
4893            justify-content: center;
4894            font-family: var(--serif);
4895            font-size: 18px;
4896            color: var(--bone);
4897            transition: .25s;
4898            text-align: center
4899        }
4900
4901        .integrations .ig:hover {
4902            background: var(--ink-3);
4903            color: var(--paper)
4904        }
4905
4906        .integrations .ig small {
4907            font-family: var(--mono);
4908            font-size: var(--t-label);
4909            color: var(--mute);
4910            letter-spacing: .14em;
4911            text-transform: uppercase;
4912            display: block;
4913            margin-top: 4px
4914        }
4915
4916        /* ====== PAGE INDICATORS ====== */
4917        .crumb {
4918            font-family: var(--mono);
4919            font-size: 11px;
4920            color: var(--mute);
4921            text-transform: uppercase;
4922            letter-spacing: .18em;
4923            display: flex;
4924            gap: 10px;
4925            align-items: center
4926        }
4927
4928        .crumb a {
4929            color: var(--mute);
4930            transition: .25s
4931        }
4932
4933        .crumb a:hover {
4934            color: var(--signal)
4935        }
4936
4937        /* ====== RESPONSIVE ====== */
4938        @media (max-width: 1100px) {
4939            .hero-shell, .slab, .editorial, .app {
4940                grid-template-columns:1fr;
4941                gap: 48px
4942            }
4943
4944            .metric {
4945                grid-column: span 6
4946            }
4947
4948            .metric.wide {
4949                grid-column: span 12
4950            }
4951
4952            .tiers {
4953                grid-template-columns:1fr
4954            }
4955
4956            .nav ul {
4957                display: none
4958            }
4959
4960            /* Collapsed nav: the Agents menu stops being a floating panel and
4961               becomes an inline accordion inside the stacked menu, opened by
4962               tapping (never by hover, which does not exist on touch). */
4963            .nav-drop {
4964                width: 100%
4965            }
4966
4967            .nav-drop-btn {
4968                width: 100%;
4969                justify-content: flex-start
4970            }
4971
4972            .nav-drop-chev {
4973                margin-left: auto
4974            }
4975
4976            .nav-drop:hover .nav-drop-panel,
4977            .nav-drop:focus-within .nav-drop-panel {
4978                display: none
4979            }
4980
4981            .nav-drop.is-open .nav-drop-panel {
4982                display: grid
4983            }
4984
4985            /* No hover on touch, and the panel is inline here, so the bridge
4986               has nothing to bridge. */
4987            .nav-drop-panel::before {
4988                display: none
4989            }
4990
4991            .nav-drop-panel {
4992                position: static;
4993                min-width: 0;
4994                width: 100%;
4995                grid-template-columns: 1fr;
4996                gap: 14px;
4997                margin: 6px 0 4px;
4998                padding: 12px;
4999                max-height: min(58vh, 460px);
5000                overflow-y: auto;
5001                -webkit-overflow-scrolling: touch;
5002                box-shadow: none;
5003                background: var(--ink-3)
5004            }
5005
5006            .nav ul .nav-drop-panel a {
5007                padding: 10px
5008            }
5009
5010            /* Stacked on mobile, so there is no second column to line up with. */
5011            .nav ul .nav-drop-all {
5012                margin-top: 6px
5013            }
5014
5015            /* Descriptions are noise on a small screen; the labels carry it. */
5016            .nav ul .nav-drop-panel a em {
5017                display: none
5018            }
5019
5020            /* Collapsed nav: the wide signup-plus-number pill gives way to a
5021               compact call button that actually dials (this is a phone), and
5022               the full number stays in the footer. Sign in + CTA keep their
5023               places. */
5024            .nav .actions .num-signup {
5025                display: none
5026            }
5027
5028            .nav .actions .num-call {
5029                display: inline-flex
5030            }
5031
5032            .menu-btn {
5033                display: inline-flex;
5034                align-items: center;
5035                justify-content: center;
5036                width: 38px;
5037                height: 38px;
5038                border: 1px solid var(--line-2);
5039                border-radius: 8px
5040            }
5041
5042            .foot-grid {
5043                grid-template-columns:1fr 1fr;
5044                gap: 32px
5045            }
5046
5047            .steps {
5048                grid-template-columns:1fr
5049            }
5050
5051            .steps::before {
5052                display: none
5053            }
5054
5055            .integrations {
5056                grid-template-columns:repeat(3, 1fr)
5057            }
5058
5059            .form .row {
5060                grid-template-columns:1fr
5061            }
5062
5063            .form .radios {
5064                grid-template-columns:1fr
5065            }
5066        }
5067
5068        @media (max-width: 640px) {
5069            .nav {
5070                grid-template-columns:1fr auto;
5071                gap: 12px;
5072                padding: 14px var(--shell-pad)
5073            }
5074
5075            /* Small phones: also drop Sign in (still in the footer), leaving
5076               toggle + call icon + Start free + menu. The call icon stays: a
5077               phone is the one place the number can actually be rung. */
5078            .nav .actions .num {
5079                display: none
5080            }
5081
5082            .nav .actions .num-call {
5083                display: inline-flex
5084            }
5085
5086            /* Tighter again on a short screen, where the fold is the whole
5087               argument and every pixel above the headline is spent. */
5088            .hero {
5089                padding-top: 96px
5090            }
5091
5092            .hero-meta {
5093                gap: 24px 32px
5094            }
5095
5096            .hero-meta dd {
5097                font-size: 24px
5098            }
5099
5100            .slab-l, .app {
5101                padding: 36px 28px
5102            }
5103
5104            .slab-r {
5105                padding: 48px 0;
5106                min-height: 480px
5107            }
5108
5109            .metric {
5110                grid-column: span 12
5111            }
5112
5113            .foot-grid {
5114                grid-template-columns:1fr
5115            }
5116
5117            .editorial {
5118                gap: 32px
5119            }
5120
5121            .endcta .num-big {
5122                font-size: 32px;
5123                padding: 16px 24px
5124            }
5125
5126            .strip {
5127                font-size: 24px
5128            }
5129
5130            /* Pricing tier cards on phones: tighter padding + smaller price so $
5131        129/mo fits */
5132            .tier {
5133                padding: 28px 22px;
5134                gap: 18px
5135            }
5136
5137            .tier .price {
5138                font-size: 48px
5139            }
5140
5141            .tier .price small {
5142                font-size: 12px
5143            }
5144
5145            .tier .name {
5146                font-size: 10px
5147            }
5148
5149            .tier .desc {
5150                padding-top: 16px
5151            }
5152
5153            .tier ul {
5154                font-size: 13px
5155            }
5156
5157            .tier ul li {
5158                gap: 8px
5159            }
5160
5161            /* Pricing FAQ */
5162            .pricing-faq-grid {
5163                grid-template-columns:1fr !important
5164            }
5165        }
5166    </style>
5167
5168    </head>
5169<body data-page="blog">
5170<!-- Google Tag Manager (noscript) -->
vendor: 73 bytes, lines 5170-5172
5170
5171<noscript>
5172    <iframe src="https://www.googletagmanager.com/ns.html?id=
5172GTM-TTGHDLQ4
vendor: 97 bytes, lines 5172-5175
5172"
5173            height="0" width="0" style="display:none;visibility:hidden"></iframe>
5174</noscript>
5175
5176<!-- End Google Tag Manager (noscript) -->
5177<div class="grain"></div>
5178<div class="scanlines"></div>
5179<div class="vignette"></div>
5180
5181<nav class="nav">
5182  
5183  <a href="https://talkify.nz" class="logo" aria-label="Talkify, home">
5184    <svg class="tk-logo" viewBox="-3 -3 317.81 106"
5185     width="113.93" height="38"
5186     xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Talkify" focusable="false">
5187            <defs>
5188            <linearGradient id="tkgEEMmve" gradientUnits="userSpaceOnUse" x1="8" y1="92" x2="92" y2="8">
5189                <stop offset="0" stop-color="#318abe"/>
5190                <stop offset="1" stop-color="#a3d654"/>
5191            </linearGradient>
5192        </defs>
5193        <circle cx="50" cy="50" r="50" fill="url(#tkgEEMmve)"/>
5194    
5195    <g fill="none" stroke="#ffffff" stroke-width="10" stroke-linecap="round">
5196        <path d="M34 26 V54 C34 74 62 80 76 62"/>
5197        <path d="M20 40 H46"/>
5198    </g>
5199    
5200    <g transform="translate(56 20) scale(0.30)">
5201        <g class="tk-eye">
5202            <path d="M50 8 Q55.5 39 92 50 Q55.5 61 50 92 Q44.5 61 8 50 Q44.5 39 50 8 Z" fill="#ffffff"/>
5203        </g>
5204    </g>
5205            <path d="M271.37 19.44 L274.1 19.47 L276.98 20.13 L279.56 21.51 L281.93 23.58 L276.86 28.65 L275.24 27.45 L274.04 26.97 L273.32 26.85 L270.62 26.97 L269.6 27.27 L268.28 28.05 L267.23 29.28 L266.57 30.96 L266.39 32.28 L266.39 37.38 L284.84 37.41 L293.66 59.85 L302.99 37.5 L311.81 37.44 L289.55 86.04 L289.34 86.37 L288.98 86.37 L280.61 86.34 L289.25 68.4 L276.89 39.18 L276.8 44.61 L266.39 44.64 L266.36 71.97 L258.47 71.94 L258.47 44.64 L250.19 44.58 L250.19 37.44 L258.44 37.41 L258.47 32.28 L258.71 30 L259.49 27.36 L260.69 25.14 L262.52 23.01 L264.98 21.21 L267.8 20.01 L270.08 19.53ZM190.01 20.16 L197.93 20.16 L197.93 71.94 L190.01 71.94ZM204.53 20.16 L212.45 20.16 L212.48 53.61 L226.46 37.41 L235.85 37.44 L221.33 53.94 L230.24 64.47 L236.57 71.94 L226.52 71.97 L212.48 55.05 L212.45 71.94 L204.53 71.94ZM131.63 23.04 L139.55 23.04 L139.58 37.41 L147.83 37.44 L147.8 44.61 L139.55 44.64 L139.55 71.94 L131.63 71.94 L131.63 44.64 L123.35 44.58 L123.38 37.41 L131.63 37.38ZM164.09 36.72 L167.06 36.81 L170.24 37.59 L171.92 38.37 L173.42 39.33 L175.4 41.19 L175.52 37.41 L183.41 37.44 L183.41 71.94 L175.52 71.97 L175.46 68.25 L174.08 69.57 L172.85 70.44 L170.84 71.55 L169.34 72.09 L167.84 72.45 L165.8 72.69 L163.76 72.69 L161.84 72.45 L159.92 71.97 L158.48 71.43 L156.44 70.35 L154.76 69.15 L152.27 66.66 L150.47 63.96 L149.57 62.04 L148.91 60.06 L148.55 58.5 L148.25 55.86 L148.37 52.2 L148.79 49.86 L149.39 47.88 L149.93 46.56 L151.01 44.58 L152.33 42.72 L153.65 41.28 L156.5 39.03 L158.54 37.95 L159.98 37.41 L161.9 36.93ZM239.21 37.44 L247.13 37.44 L247.13 71.94 L239.21 71.94ZM165.2 44.19 L163.04 44.61 L161.48 45.27 L159.98 46.29 L158.51 47.82 L157.73 49.02 L156.83 51.18 L156.41 53.52 L156.41 55.86 L156.65 57.48 L157.31 59.52 L158.51 61.56 L160.04 63.15 L161.48 64.11 L163.46 64.89 L165.32 65.19 L167.12 65.13 L169.34 64.77 L171.14 63.99 L172.34 63.15 L173.99 61.38 L175.01 59.64 L175.67 57.66 L175.97 55.44 L175.91 53.1 L175.49 51 L174.53 48.78 L173.81 47.7 L172.52 46.35 L170.84 45.21 L169.16 44.55 L167.18 44.19Z" fill="var(--tk-word, #101820)" fill-rule="evenodd"/>
5206        
5207        <g transform="translate(231.30 6.84) scale(0.216)">
5208            <path d="M50 8 Q55.5 39 92 50 Q55.5 61 50 92 Q44.5 61 8 50 Q44.5 39 50 8 Z"
5209                  fill="#a3d654"/>
5210        </g>
5211    </svg>
5212  </a>
5213  <ul>
5214    <li class="nav-drop" data-nav-drop>
5215      <button type="button" class="nav-drop-btn "
5216              aria-expanded="false" aria-controls="nav-agents-menu" aria-haspopup="true">
5217        <span class="dot"></span>Agents
5218        <svg class="nav-drop-chev" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 9l6 6 6-6"/></svg>
5219      </button>
5220
5221      
5222      <div class="nav-drop-panel" id="nav-agents-menu">
5223        <div class="nav-drop-col">
5224          <span class="nav-drop-hd">Answering calls</span>
5225          <a href="https://talkify.nz/reception"><span>Reception</span><em>Answers every call, books the job</em></a>
5226          <a href="https://talkify.nz/personal-assistant"><span>Personal Assistant</span><em>Your own PA on the phone</em></a>
5227          <a href="https://talkify.nz/booking-service"><span>Booking Service</span><em>Fills the diary while you work</em></a>
5228          <a href="https://talkify.nz/front-counter"><span>Front Counter</span><em>Orders and bookings on a screen by the till</em></a>
5229          <a href="https://talkify.nz/ai-call-centre"><span>AI Call Centre</span><em>5, 10 or 15 lines at once</em></a>
5230          <span class="nav-drop-hd" style="margin-top:18px">Other channels</span>
5231          <a href="https://talkify.nz/website-chat"><span>Website Chat</span><em>The same agent, in a chat box on your site</em></a>
5232          <a href="https://talkify.nz/calendar"><span>Calendar</span><em>The diary the agent books into</em></a>
5233          <a href="https://talkify.nz/lead-management"><span>Leads</span><em>Every enquiry on one board, whatever door it came through</em></a>
5234                    <a href="https://talkify.nz/agent-coach"><span>Coach</span><em>Your agent listens back to its own calls</em></a>
5235                  </div>
5236        <div class="nav-drop-col">
5237          <span class="nav-drop-hd">Ringing out</span>
5238          <a href="https://talkify.nz/sales-agent"><span>Sales Agent</span><em>Qualifies and follows up leads</em></a>
5239          <a href="https://talkify.nz/outbound-calls"><span>Outbound Calls</span><em>Campaigns, reminders, win-backs</em></a>
5240          <a href="https://talkify.nz/ai-marketing-campaigns"><span>Marketing Campaigns</span><em>Offers, launches and reviews, by phone</em></a>
5241          <a href="https://talkify.nz/ai-phone-surveys"><span>Campaign Agent</span><em>Rings your list, asks your questions, reports back</em></a>
5242          <a href="https://talkify.nz/debt-collection"><span>Debt Collection</span><em>Chases overdue invoices from Xero</em></a>
5243          <a href="https://talkify.nz/ai-wellness-checks"><span>Wellness Checks</span><em>Rings to check somebody is alright</em></a>
5244          
5245          <a href="https://talkify.nz/dialler"><span>Dialler</span><em>Your own team ringing out, from the browser</em></a>
5246          <a href="https://talkify.nz/agents" class="nav-drop-all">See all agents <span class="arr">&rarr;</span></a>
5247        </div>
5248      </div>
5249    </li>
5250    
5251    <li class="nav-drop" data-nav-drop>
5252      <button type="button" class="nav-drop-btn "
5253              aria-expanded="false" aria-controls="nav-industries-menu" aria-haspopup="true">
5254        <span class="dot"></span>Industries
5255        <svg class="nav-drop-chev" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 9l6 6 6-6"/></svg>
5256      </button>
5257
5258      
5259      <div class="nav-drop-panel nav-drop-panel--industries" id="nav-industries-menu">
5260        <div class="nav-drop-col">
5261          <span class="nav-drop-hd">Trades</span>
5262          <a href="https://talkify.nz/tradesman">All Trades</a>
5263          <a href="https://talkify.nz/builder">Builders</a>
5264          <a href="https://talkify.nz/electrician">Electricians</a>
5265          <a href="https://talkify.nz/hvac">Heat Pump &amp; HVAC</a>
5266          <a href="https://talkify.nz/landscaping">Landscaping</a>
5267          <a href="https://talkify.nz/automotive">Mechanics</a>
5268          <a href="https://talkify.nz/pest-control">Pest Control</a>
5269          <a href="https://talkify.nz/plumber">Plumbing</a>
5270        </div>
5271        <div class="nav-drop-col">
5272          <span class="nav-drop-hd">Health &amp; beauty</span>
5273          <a href="https://talkify.nz/barber">Barbers</a>
5274          <a href="https://talkify.nz/beauty">Beauty &amp; Wellness</a>
5275          <a href="https://talkify.nz/gym">Gyms &amp; Studios</a>
5276          <a href="https://talkify.nz/personal-trainer">Personal Trainers</a>
5277          <a href="https://talkify.nz/physio">Physio &amp; Clinics</a>
5278          <span class="nav-drop-hd" style="margin-top:18px">Office &amp; property</span>
5279          <a href="https://talkify.nz/accountant">Accountants</a>
5280          <a href="https://talkify.nz/professional-services">Professional Services</a>
5281          <a href="https://talkify.nz/real-estate">Real Estate</a>
5282          <a href="https://talkify.nz/retail">Retail</a>
5283        </div>
5284        <div class="nav-drop-col">
5285          <span class="nav-drop-hd">Food &amp; hospitality</span>
5286          <a href="https://talkify.nz/cafe">Cafes</a>
5287          <a href="https://talkify.nz/chinese-takeaway">Chinese Takeaways</a>
5288          <a href="https://talkify.nz/fish-and-chip-shop">Fish &amp; Chip Shops</a>
5289          <a href="https://talkify.nz/hotel">Hotels &amp; Motels</a>
5290          <a href="https://talkify.nz/pizza-shop">Pizza Shops</a>
5291          <a href="https://talkify.nz/restaurant-bookings">Restaurants</a>
5292          <a href="https://talkify.nz/industries" class="nav-drop-all">See all industries <span class="arr">&rarr;</span></a>
5293        </div>
5294      </div>
5295    </li>
5296    <li class="nav-drop" data-nav-drop>
5297      <button type="button" class="nav-drop-btn "
5298              aria-expanded="false" aria-controls="nav-integrations-menu" aria-haspopup="true">
5299        <span class="dot"></span>Integrations
5300        <svg class="nav-drop-chev" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6 9l6 6 6-6"/></svg>
5301      </button>
5302
5303      <div class="nav-drop-panel nav-drop-panel--single" id="nav-integrations-menu">
5304        <div class="nav-drop-col">
5305          <span class="nav-drop-hd">Plugs into</span>
5306          <a href="https://talkify.nz/integrations"><span>All integrations</span><em>The software the agent already talks to</em></a>
5307          <a href="https://talkify.nz/business-phone-lines"><span>Phone Lines</span><em>Numbers, porting and how calls reach us</em></a>
5308        </div>
5309      </div>
5310    </li>
5311    <li><a href="https://talkify.nz/pricing" class=""><span class="dot"></span>Pricing</a></li>
5312    <li><a href="https://talkify.nz/blog" class="is-active"><span class="dot"></span>Journal</a></li>
5313        <li><a href="https://talkify.nz/signup" class=""><span class="dot"></span>Get started</a></li>
5314      </ul>
5315  <div class="actions">
5316    <button type="button" class="theme-toggle" data-theme-toggle aria-label="Switch between light and dark theme" title="Switch theme">
5317      <svg class="icon-sun" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><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 12h2M6.34 17.66l-1.41 1.41M19.07 4.93l-1.41 1.41"/></svg>
5318      <svg class="icon-moon" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"/></svg>
5319    </button>
5320            
5321        <a href="https://talkify.nz/signup" class="num num-signup" title="Sign up online, or ring 0800 002 967">Sign up · <b>0800 002 967</b></a>
5322        <a href="tel:+64800002967" class="num num-call" title="Call us on 0800 002 967" aria-label="Call us on 0800 002 967">
5323      <svg width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M22 16.92v3a2 2 0 01-2.18 2 19.79 19.79 0 01-8.63-3.07 19.5 19.5 0 01-6-6 19.79 19.79 0 01-3.07-8.67A2 2 0 014.11 2h3a2 2 0 012 1.72c.127.96.361 1.903.7 2.81a2 2 0 01-.45 2.11L8.09 9.91a16 16 0 006 6l1.27-1.27a2 2 0 012.11-.45c.907.339 1.85.573 2.81.7A2 2 0 0122 16.92z"/></svg>
5324    </a>
5325              <a href="https://talkify.nz/login" class="num" style="font-family:var(--sans);font-size:13px;color:var(--bone)">Sign in</a>
5326      <a href="https://talkify.nz/signup" class="btn btn-primary">Start free <span class="arr">→</span></a>
5327        <button class="menu-btn" aria-label="Open menu">
5328      <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M4 7h16M4 12h16M4 17h16"/></svg>
5329    </button>
5330  </div>
5331</nav>
5332
5333<section class="hero" style="padding-bottom:60px">
5334  <div class="hero-bg">
5335    <div class="glow1"></div>
5336    <div class="glow2"></div>
5337    <div class="grid-lines"></div>
5338  </div>
5339  <div class="hero-shell single">
5340    <div>
5341      <div class="crumb"><a href="https://talkify.nz">Talkify</a> <span>/</span> <span style="color:var(--paper)">Journal</span></div>
5342      <span class="eyebrow" style="margin-top:18px"><span class="pin"></span>Field notes from the front line of NZ phone work</span>
5343      <h1 class="display" style="font-size:clamp(56px,9vw,128px);max-width:18ch">
5344        <span class="ln"><span>The Talkify <span class="it">journal.</span></span></span>
5345      </h1>
5346      <p class="hero-sub" style="max-width:680px">
5347        Real data, real call recordings (de-identified), and plain-English playbooks. Published weekly. No fluff, no AI hype, no "10 ways" listicles.
5348      </p>
5349    </div>
5350  </div>
5351</section>
5352
5353
5354<section class="shell tight" style="padding-top:0">
5355  <a href="https://talkify.nz/blog/where-does-your-ai-receptionist-send-your-calls" class="r" style="display:grid;grid-template-columns:1.1fr 1fr;gap:40px;border-top:2px solid var(--line-2);padding-top:32px;text-decoration:none;color:inherit;transition:.3s" id="featured-card">
5356    <div style="padding:56px 56px 40px;display:flex;flex-direction:column;gap:24px;justify-content:space-between">
5357      <div>
5358        <div style="display:flex;align-items:center;gap:14px;margin-bottom:24px">
5359          <span style="font-family:var(--mono);font-size:10px;letter-spacing:.22em;text-transform:uppercase;color:var(--signal)">Featured</span>
5360          <span style="font-family:var(--mono);font-size:10px;letter-spacing:.16em;text-transform:uppercase;color:var(--mute)">Guides · 7 min read</span>
5361        </div>
5362        <h2 style="font-family:var(--serif);font-weight:300;font-size:clamp(32px,4vw,52px);line-height:1.02;letter-spacing:-.02em;color:var(--paper)">Where does your AI receptionist actually send your calls?</h2>
5363        <p style="margin-top:18px;font-weight:600;font-size:20px;color:var(--bone);line-height:1.4">One partner had forty AI receptionist companies apply in a single month. Most are a layer of glue code on somebody else&#039;s stack in somebody else&#039;s country. Five questions to ask before you forward your main line to one.</p>
5364        <p style="margin-top:24px;color:var(--bone);font-size:15px;line-height:1.6">The AI receptionist market is being flooded, and most of the flood is thin. Here is what actually sits underneath these things, what happens when one goes down at nine on a Monday, and the five questions that separate a phone company from a weekend project.</p>
5365      </div>
5366      <div style="display:flex;justify-content:space-between;align-items:center;border-top:1px dashed var(--line);padding-top:18px;font-family:var(--mono);font-size:11px;color:var(--mute);letter-spacing:.06em">
5367        <span>The Talkify team · 13 Sep 2026</span>
5368        <span style="display:inline-flex;align-items:center;gap:8px;color:var(--signal)">Read the article <span class="arr">→</span></span>
5369      </div>
5370    </div>
5371    <div style="background:url('https://talkify.nz/media/frontend/blog/where-does-your-ai-receptionist-send-your-calls.jpg') center/cover no-repeat,linear-gradient(135deg,rgba(49,138,190,.2),color-mix(in srgb, var(--signal) 15%, transparent));min-height:420px;position:relative">
5372      <div style="position:absolute;inset:0;background:linear-gradient(90deg,var(--scrim-mid) 0%,transparent 30%)"></div>
5373    </div>
5374  </a>
5375  <style>
5376    #featured-card:hover{border-color:var(--signal);transform:translateY(-2px);box-shadow:0 30px 60px -20px rgba(0,0,0,.5),0 0 0 1px color-mix(in srgb, var(--signal) 20%, transparent) inset}
5377    #featured-card:hover .arr{transform:translateX(3px)}
5378    @media (max-width:1100px){
5379      #featured-card{grid-template-columns:1fr !important}
5380      #featured-card > div:first-child{padding:40px 32px 32px !important}
5381      #featured-card > div:last-child{min-height:240px !important;order:-1}
5382    }
5383  </style>
5384</section>
5385
5386<section class="shell tight">
5387  <div class="section-hd">
5388    <h2 class="r">More from the <span class="it">journal.</span></h2>
5389    <p class="lede r r-1">Stories, numbers, and how-tos from our customers' phone lines, ours, and the broader NZ small-business call-handling scene.</p>
5390  </div>
5391  <div class="r" style="display:grid;grid-template-columns:repeat(3,1fr);gap:24px" id="post-grid">
5392          <a href="https://talkify.nz/blog/one-calendar-for-your-whole-team" class="post-card">
5393        <div class="post-hero" style="background-image:url('https://talkify.nz/media/frontend/blog/one-calendar-for-your-whole-team.jpg')"></div>
5394        <div class="post-body">
5395          <div class="post-meta">Product · 5 min</div>
5396          <h3 class="post-title">One calendar for your whole team, and proof of where every booking went</h3>
5397          <p class="post-excerpt">Talkify now has a Calendar. Every diary in your business on one screen, what your agent booked while you were on the tools, and proof of whe...</p>
5398          <div class="post-foot">4 Sep 2026 <span>Read →</span></div>
5399        </div>
5400      </a>
5401          <a href="https://talkify.nz/blog/best-ai-receptionist-nz" class="post-card">
5402        <div class="post-hero" style="background-image:url('https://talkify.nz/media/frontend/blog/best-ai-receptionist-nz.jpg')"></div>
5403        <div class="post-body">
5404          <div class="post-meta">Guides · 7 min</div>
5405          <h3 class="post-title">The best AI receptionists in New Zealand (2026), ranked by one of them<
5405/h3>
5406          <p class="post-excerpt">Every &quot;best AI receptionist NZ&quot; ranking is either an overseas content farm recommending American services or a vendor putting itself first....</p>
5407          <div class="post-foot">25 Aug 2026 <span>Read →</span></div>
5408        </div>
5409      </a>
5410          <a href="https://talkify.nz/blog/is-an-ai-receptionist-worth-it-nz" class="post-card">
5411        <div class="post-hero" style="background-image:url('https://talkify.nz/media/frontend/blog/is-an-ai-receptionist-worth-it-nz.jpg')"></div>
5412        <div class="post-body">
5413          <div class="post-meta">Guides · 5 min</div>
5414          <h3 class="post-title">Is an AI receptionist worth it for a New Zealand business?</h3>
5415          <p class="post-excerpt">An AI receptionist is worth it the moment missed calls cost more per month than the service does, and for most trades and clinics one saved...</p>
5416          <div class="post-foot">25 Aug 2026 <span>Read →</span></div>
5417        </div>
5418      </a>
5419          <a href="https://talkify.nz/blog/can-ai-understand-kiwi-accent" class="post-card">
5420        <div class="post-hero" style="background-image:url('https://talkify.nz/media/frontend/blog/can-ai-understand-kiwi-accent.jpg')"></div>
5421        <div class="post-body">
5422          <div class="post-meta">Guides · 4 min</div>
5423          <h3 class="post-title">Can an AI phone agent understand a Kiwi accent?</h3>
5424          <p class="post-excerpt">A well-built AI phone agent understands New Zealand accents, pronounces Whangārei and Ōtautahi properly, and follows a caller who switches i...</p>
5425          <div class="post-foot">25 Aug 2026 <span>Read →</span></div>
5426        </div>
5427      </a>
5428          <a href="https://talkify.nz/blog/ai-phone-calls-legal-nz" class="post-card">
5429        <div class="post-hero" style="background-image:url('https://talkify.nz/media/frontend/blog/ai-phone-calls-legal-nz.jpg')"></div>
5430        <div class="post-body">
5431          <div class="post-meta">Guides · 5 min</div>
5432          <h3 class="post-title">Is it legal for an AI to answer and make phone calls in New Zealand?</h3>
5433          <p class="post-excerpt">AI answering and AI outbound calling are both legal in New Zealand under the same rules as any business phone call. The anti-spam act covers...</p>
5434          <div class="post-foot">25 Aug 2026 <span>Read →</span></div>
5435        </div>
5436      </a>
5437          <a href="https://talkify.nz/blog/talkify-for-professional-firms-nz" class="post-card">
5438        <div class="post-hero" style="background-image:url('https://talkify.nz/media/frontend/blog/talkify-for-professional-firms-nz.jpg')"></div>
5439        <div class="post-body">
5440          <div class="post-meta">Guides · 6 min</div>
5441          <h3 class="post-title">Why professional firms in New Zealand choose Talkify</h3>
5442          <p class="post-excerpt">For an accountant, lawyer, adviser or agency, the phone is your reputation answered out loud. Talkify brings twelve years of phone automatio...</p>
5443          <div class="post-foot">16 Aug 2026 <span>Read →</span></div>
5444        </div>
5445      </a>
5446          <a href="https://talkify.nz/blog/daily-wellness-check-calls-nz" class="post-card">
5447        <div class="post-hero" style="background-image:url('https://talkify.nz/media/frontend/blog/daily-wellness-check-calls-nz.jpg')"></div>
5448        <div class="post-body">
5449          <div class="post-meta">Product · 5 min</div>
5450          <h3 class="post-title">A friendly call every day, so you know they are okay</h3>
5451          <p class="post-excerpt">You cannot ring mum or koro every single day. The Talkify wellness check agent can, calling on a schedule you choose, asking how they are, g...</p>
5452          <div class="post-foot">15 Aug 2026 <span>Read →</span></div>
5453        </div>
5454      </a>
5455          <a href="https://talkify.nz/blog/talkify-mechanicdesk-integration" class="post-card">
5456        <div class="post-hero" style="background-image:url('https://talkify.nz/media/frontend/blog/talkify-mechanicdesk-integration.jpg')"></div>
5457        <div class="post-body">
5458          <div class="post-meta">Integrations · 4 min</div>
5459          <h3 class="post-title">Talkify now works with MechanicDesk</h3>
5460          <p class="post-excerpt">Workshop phones ring while you are under a car. Talkify now connects to MechanicDesk, so your AI agent answers, offers your real services an...</p>
5461          <div class="post-foot">4 Aug 2026 <span>Read →</span></div>
5462        </div>
5463      </a>
5464          <a href="https://talkify.nz/blog/talkify-xero-integration-overdue-invoices" class="post-card">
5465        <div class="post-hero" style="background-image:url('https://talkify.nz/media/frontend/blog/talkify-xero-integration-overdue-invoices.jpg')"></div>
5466        <div class="post-body">
5467          <div class="post-meta">Integrations · 5 min</div>
5468          <h3 class="post-title">Talkify now works with Xero</h3>
5469          <p class="post-excerpt">Every business has an aged receivables report and a fortnight of good intentions about ringing the names on it. Talkify now connects to Xero...</p>
5470          <div class="post-foot">1 Aug 2026 <span>Read →</span></div>
5471        </div>
5472      </a>
5473          <a href="https://talkify.nz/blog/what-makes-talkify-different-nz" class="post-card">
5474        <div class="post-hero" style="background-image:url('https://talkify.nz/media/frontend/blog/what-makes-talkify-different-nz.jpg')"></div>
5475        <div class="post-body">
5476          <div class="post-meta">Guides · 8 min</div>
5477          <h3 class="post-title">What makes Talkify different from other AI phone services in NZ</h3>
5478          <p class="post-excerpt">Most AI receptionists just answer the phone in an American voice. Talkify is built in NZ, answers and makes calls, and is the only NZ AI pho...</p>
5479          <div class="post-foot">31 Jul 2026 <span>Read →</span></div>
5480        </div>
5481      </a>
5482          <a href="https://talkify.nz/blog/ai-call-centre-agents-nz" class="post-card">
5483        <div class="post-hero" style="background-image:url('https://talkify.nz/media/frontend/blog/ai-call-centre-agents-nz.jpg')"></div>
5484        <div class="post-body">
5485          <div class="post-meta">Product · 4 min</div>
5486          <h3 class="post-title">A call centre without the call centre</h3>
5487          <p class="post-excerpt">Talkify now runs full AI call centres for NZ businesses. Pick 5, 10 or 15 simultaneous lines, and every one of them answers the instant it r...</p>
5488          <div class="post-foot">6 Jul 2026 <span>Read →</span></div>
5489        </div>
5490      </a>
5491          <a href="https://talkify.nz/blog/talkify-gymmaster-integration" class="post-card">
5492        <div class="post-hero" style="background-image:url('https://talkify.nz/media/frontend/blog/talkify-gymmaster-integration.jpg')"></div>
5493        <div class="post-body">
5494          <div class="post-meta">Integrations · 4 min</div>
5495          <h3 class="post-title">Talkify now works with GymMaster</h3>
5496          <p class="post-excerpt">Gyms and studios field the same calls all day: what classes are on, is there space, can I book. Talkify now connects to GymMaster so your AI...</p>
5497          <div class="post-foot">26 Jun 2026 <span>Read →</span></div>
5498        </div>
5499      </a>
5500          <a href="https://talkify.nz/blog/talkify-mobile-app-android-ios" class="post-card">
5501        <div class="post-hero" style="background-image:url('https://talkify.nz/media/frontend/blog/talkify-mobile-app-android-ios.jpg')"></div>
5502        <div class="post-body">
5503          <div class="post-meta">Product · 4 min</div>
5504          <h3 class="post-title">Your Talkify PA now lives in your pocket</h3>
5505          <p class="post-excerpt">Your Talkify PA has been answering your phone, booking jobs and following up. Now the whole thing fits in your pocket. The Talkify app is ou...</p>
5506          <div class="post-foot">24 Jun 2026 <span>Read →</span></div>
5507        </div>
5508      </a>
5509          <a href="https://talkify.nz/blog/outbound-agent-surveys-leads" class="post-card">
5510        <div class="post-hero" style="background-image:url('https://talkify.nz/media/frontend/blog/outbound-agent-surveys-leads.jpg')"></div>
5511        <div class="post-body">
5512          <div class="post-meta">Product · 6 min</div>
5513          <h3 class="post-title">The calls you keep meaning to make, made for you</h3>
5514          <p class="post-excerpt">Every business has a list of calls it knows it should make and never gets to: every customer after a job, the happy ones who would leave a r...</p>
5515          <div class="post-foot">15 Jun 2026 <span>Read →</span></div>
5516        </div>
5517      </a>
5518          <a href="https://talkify.nz/blog/natural-voice-not-robotic" class="post-card">
5519        <div class="post-hero" style="background-image:url('https://talkify.nz/media/frontend/blog/natural-voice-not-robotic.jpg')"></div>
5520        <div class="post-body">
5521          <div class="post-meta">Product · 5 min</div>
5522          <h3 class="post-title">Your callers will not know it is AI</h3>
5523          <p class="post-excerpt">When people hear &quot;AI will answer your phone&quot;, they picture a flat robot voice and a menu of options nobody wants. Talkify sounds nothing lik...</p>
5524          <div class="post-foot">13 Jun 2026 <span>Read →</span></div>
5525        </div>
5526      </a>
5527          <a href="https://talkify.nz/blog/cheap-ai-receptionist-nz" class="post-card">
5528        <div class="post-hero" style="background-image:url('https://talkify.nz/media/frontend/blog/cheap-ai-receptionist-nz.jpg')"></div>
5529        <div class="post-body">
5530          <div class="post-meta">Guides · 6 min</div>
5531          <h3 class="post-title">The cheap AI receptionist trap: what the low price actually buys</h3>
5532          <p class="post-excerpt">The NZ AI receptionist market filled up fast, and a lot of it is cheap in ways the pricing page does not show: 80c-a-minute overage, setup f...</p>
5533          <div class="post-foot">13 Jun 2026 <span>Read →</span></div>
5534        </div>
5535      </a>
5536          <a href="https://talkify.nz/blog/ring-your-customer-list" class="post-card">
5537        <div class="post-hero" style="background-image:url('https://talkify.nz/media/frontend/blog/ring-your-customer-list.jpg')"></div>
5538        <div class="post-body">
5539          <div class="post-meta">Product · 6 min</div>
5540          <h3 class="post-title">Your customer list is an asset. Ring it.</h3>
5541          <p class="post-excerpt">Every business has a list of past customers it never rings, because ringing 180 people is a day of work nobody wants. Talkify&#039;s outbound age...</p>
5542          <div class="post-foot">13 Jun 2026 <span>Read →</span></div>
5543        </div>
5544      </a>
5545          <a href="https://talkify.nz/blog/what-does-a-receptionist-cost-nz" class="post-card">
5546        <div class="post-hero" style="background-image:url('https://talkify.nz/media/frontend/blog/what-does-a-receptionist-cost-nz.jpg')"></div>
5547        <div class="post-body">
5548          <div class="post-meta">Data · 7 min</div>
5549          <h3 class="post-title">What a receptionist really costs in NZ in 2026</h3>
5550          <p class="post-excerpt">A hired receptionist runs $65,000 to $75,000 a year all-in and covers 40 hours of the week. A human answering service runs $200 to $500 a mo...</p>
5551          <div class="post-foot">12 Jun 2026 <span>Read →</span></div>
5552        </div>
5553      </a>
5554          <a href="https://talkify.nz/blog/website-chat-same-brain-as-your-phone-agent" class="post-card">
5555        <div class="post-hero" style="background-image:url('https://talkify.nz/media/frontend/blog/website-chat-same-brain-as-your-phone-agent.jpg')"></div>
5556        <div class="post-body">
5557          <div class="post-meta">Product · 5 min</div>
5558          <h3 class="post-title">Your website chat, with the same brain as your phone agent</h3>
5559          <p class="post-excerpt">Most website chat is a contact form in disguise. The Talkify orb is the same AI agent that answers your phone, living on your website, ready...</p>
5560          <div class="post-foot">12 Jun 2026 <span>Read →</span></div>
5561        </div>
5562      </a>
5563          <a href="https://talkify.nz/blog/never-miss-a-job-on-the-tools" class="post-card">
5564        <div class="post-hero" style="background-image:url('https://talkify.nz/media/frontend/blog/never-miss-a-job-on-the-tools.jpg')"></div>
5565        <div class="post-body">
5566          <div class="post-meta">Trades · 6 min</div>
5567          <h3 class="post-title">Who answers the phone when you are on the tools?</h3>
5568          <p class="post-excerpt">Your AI receptionist does: it picks up in a real Kiwi voice on the first ring, tells the caller when you can get to them, books the job into...</p>
5569          <div class="post-foot">12 Jun 2026 <span>Read →</span></div>
5570        </div>
5571      </a>
5572          <a href="https://talkify.nz/blog/give-your-front-desk-their-day-back" class="post-card">
5573        <div class="post-hero" style="background-image:url('https://talkify.nz/media/frontend/blog/give-your-front-desk-their-day-back.jpg')"></div>
5574        <div class="post-body">
5575          <div class="post-meta">Operations · 6 min</div>
5576          <h3 class="post-title">Give your front desk their day back</h3>
5577          <p class="post-excerpt">Every ring pulls your receptionist off whatever they were doing, and most of those calls are just a time or a price. Talkify answers all of...</p>
5578          <div class="post-foot">12 Jun 2026 <span>Read →</span></div>
5579        </div>
5580      </a>
5581          <a href="https://talkify.nz/blog/missed-calls-cost-nz-business-2026" class="post-card">
5582        <div class="post-hero" style="background-image:url('https://talkify.nz/media/frontend/hero-phone-night.jpg')"></div>
5583        <div class="post-body">
5584          <div class="post-meta">Data · 9 min</div>
5585          <h3 class="post-title">How much are missed calls costing your NZ business in 2026?</h3>
5586          <p class="post-excerpt">A NZ tradesman misses 35% of his calls. An accountant misses 30%. The maths gets ugly fast: at $2,000 per lost customer and 85% of callers n...</p>
5587          <div class="post-foot">7 May 2026 <span>Read →</span></div>
5588        </div>
5589      </a>
5590      </div>
5591  <style>
5592    /* V2 design language: top-ruled columns with the photograph under the
5593       rule, rather than filled cards. */
5594    .post-card{position:relative;display:flex;flex-direction:column;padding-top:22px;text-decoration:none;color:inherit}
5595    .post-card::before,.post-card::after{content:"";position:absolute;top:0;left:0;right:0;height:1px}
5596    .post-card::before{background:var(--line-2)}
5597    .post-card::after{background:var(--grad);
5597transform:scaleX(0);transform-origin:left;transition:transform .5s var(--ease-out)}
5598    .post-card:hover::after{transform:scaleX(1)}
5599    .post-card:hover .post-title{color:var(--signal)}
5600    .post-card .post-hero{aspect-ratio:16/10;background-size:cover;background-position:center}
5601    .post-card .post-body{padding:20px 0 0;display:flex;flex-direction:column;gap:12px;flex:1}
5602    .post-card .post-meta{font-family:var(--mono);font-size:10px;color:var(--mute);letter-spacing:.16em;text-transform:uppercase}
5603    .post-card .post-title{font-family:var(--serif);font-weight:400;font-size:22px;line-height:1.15;letter-spacing:-.01em;color:var(--paper);transition:color .3s var(--ease)}
5604    .post-card .post-excerpt{color:var(--bone);font-size:14px;line-height:1.55;flex:1}
5605    .post-card .post-foot{font-family:var(--mono);font-size:11px;color:var(--mute);letter-spacing:.06em;border-top:1px dashed var(--line);padding-top:14px;display:flex;justify-content:space-between;align-items:center}
5606    .post-card .post-foot span{color:var(--signal)}
5607    @media (max-width:1100px){ #post-grid{grid-template-columns:1fr !important} }
5608  </style>
5609</section>
5610
5611<section class="shell tight">
5612  <div class="r" style="border-top:1px dashed var(--line-2);padding:36px 0 0;display:flex;justify-content:space-between;align-items:center;gap:32px;flex-wrap:wrap">
5613    <div>
5614      <span class="eyebrow eb-blue"><span class="pin"></span>Subscribe</span>
5615      <h3 style="margin-top:14px;font-family:var(--serif);font-weight:300;font-size:32px;letter-spacing:-.02em;color:var(--paper)">One useful piece a week. <span style="font-weight:600;color:var(--plasma-bright)">No spam, no fluff.</span></h3>
5616    </div>
5617    <a href="https://talkify.nz/contact" class="btn btn-primary btn-lg">Get on the list <span class="arr">→</span></a>
5618  </div>
5619</section>
5620
5621<section class="endcta endcta-has-form" id="endcta">
5622    <div class="endcta-photo" aria-hidden="true"></div>
5623
5624    
5625    <div class="endcta-wrap" id="signup">
5626        <div class="endcta-pitch">
5627            <div class="stamp">TWO WAYS TO HEAR THE AGENT</div>
5628            <h2>Don&#039;t read about it.<br><span class="it">Talk to it.</span></h2>
5629
5630            <div class="endcta-numbers">
5631                                <a href="tel:+6432421262" class="num-big" data-talkify-agent="default"
5632                   title="Hear the agent yourself">
5633      <span class="ic ic-demo">
5634        <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4"
5635             stroke-linecap="round"><path
5636                d="M3 5a2 2 0 012-2h2.5a1 1 0 01.96.73l1.2 4.2a1 1 0 01-.5 1.16l-1.94.97a11 11 0 005.7 5.7l.97-1.94a1 1 0 011.16-.5l4.2 1.2a1 1 0 01.73.96V19a2 2 0 01-2 2A16 16 0 013 5z"/></svg>
5637      </span>
5638                    <span>
5639        <small>Hear it yourself · our AI agent, 24/7 · ask it anything</small>
5640        03 242 1262
5641      </span>
5642                </a>
5643                
5644                                    <a href="tel:+64800002967" class="num-big num-blue" title="Sign up, sales and support">
5645      <span class="ic ic-signup">
5646        <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4"
5647             stroke-linecap="round"><path
5648                d="M16 21v-2a4 4 0 00-4-4H6a4 4 0 00-4 4v2M9 11a4 4 0 100-8 4 4 0 000 8zM19 8v6M22 11h-6"/></svg>
5649      </span>
5650                        <span>
5651        <small>Sign up, sales &amp; support · we'll set you up</small>
5652        0800 002 967
5653      </span>
5654                    </a>
5655                            </div>
5656
5657            <div class="endcta-meta">
5658                                    <span>● No card</span><span>● No lock-in</span><span>● Free to call</span><span>● The demo line can sign you up too</span>                            </div>
5659
5660            
5661                        <div class="endcta-alt">
5662                <a href="sms:+64272048827" class="btn btn-ghost btn-lg"
5663       title="Text us instead of ringing">
5664        <svg width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"
5665             stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" style="flex:none">
5666            <path d="M21 11.5a8.4 8.4 0 01-9 8.4 9.5 9.5 0 01-2.6-.4L3 21l1.6-4.2A8.2 8.2 0 013 11.5 8.4 8.4 0 0112 3a8.4 8.4 0 019 8.5z"/>
5667        </svg>
5668        Text our agent · 027 204 8827    </a>
5669            </div>
5670            
5671            
5672                            <p class="endcta-app-line">Or run it from your pocket</p>
5673                <div class="app-stores" style="--app-badge-h: 46px">
5674    <a class="app-badge" href="https://apps.apple.com/nz/app/talkify-mobile/id6766709308"
5675       target="_blank" rel="noopener">
5676        <img src="https://talkify.nz/media/branding/apple-app-store.svg"
5677             alt="Download Talkify Mobile on the App Store"
5678             width="137.6" height="46" loading="lazy">
5679    </a>
5680    <a class="app-badge" href="https://play.google.com/store/apps/details?id=com.talkifynz.app"
5681       target="_blank" rel="noopener">
5682        <img src="https://talkify.nz/media/branding/google-app-store.svg"
5683             alt="Get Talkify Mobile on Google Play"
5684             width="155.3" height="46" loading="lazy">
5685    </a>
5686</div>
5687                    </div>
5688
5689                    <div class="endcta-form">
5690                
5691                <span class="eyebrow"><span class="pin"></span>Get your first agent ·  No card needed </span>
5692
5693                <form method="POST" action="https://talkify.nz/contact" class="form">
5694                    <input type="hidden" name="_token" value="UX4ET0SMIjqjlAZpeGEHEC08v4Jm710J6eCeeiVT" autocomplete="off">                                        <div class="row">
5695                        <div class="field">
5696                            <label>Your name</label>
5697                            <input type="text" name="name" required placeholder="Your full name" autocomplete="name" value="">
5698                        </div>
5699                        <div class="field">
5700                            <label>Company</label>
5701                            <input type="text" name="company" required placeholder="Your company" autocomplete="organization" value="">
5702                        </div>
5703                    </div>
5704                    <div class="row">
5705                        <div class="field">
5706                            <label>Email</label>
5707                            <input type="email" name="email" required placeholder="Your email" autocomplete="email" value="">
5708                        </div>
5709                        <div class="field">
5710                            <label>Mobile (NZ)</label>
5711                            <input type="tel" name="phone" required placeholder="Your mobile" autocomplete="tel" value="">
5712                        </div>
5713                    </div>
5714                    <div class="field">
5715  <label for="country-signup">Country</label>
5716  <select name="country" id="country-signup" required data-country-select autocomplete="country">
5717    <option value="" disabled selected>Select your country</option>
5718    <option value="NZ" >New Zealand</option>
5719    <option value="AU" >Australia</option>
5720  </select>
5721  <p style="margin-top:8px;font-family:var(--mono);font-size:11px;letter-spacing:.04em;color:var(--mute)">
5722    Talkify is currently available to businesses in New Zealand &amp; Australia only.
5723  </p>
5724</div>
5725
5726
5727<div aria-hidden="true" style="position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0">
5728  <input type="text" name="company_reference" tabindex="-1" autocomplete="off" value="" aria-hidden="true">
5729</div>
5730
5731<script>
5732(function () {
5733  var script = document.currentScript;
5734  var form = script && script.closest('form');
5735  if (!form) return;
5736  var select = form.querySelector('select[name="country"]');
5737  if (!select || select.value) return; // respect old() / a choice already made
5738
5739  try {
5740    var tz = (Intl.DateTimeFormat().resolvedOptions().timeZone || '').toLowerCase();
5741    var lang = (navigator.language || '').toLowerCase();
5742    var code = null;
5743
5744    if (tz.indexOf('auckland') >= 0 || tz.indexOf('chatham') >= 0 || lang === 'en-nz' || lang === 'mi') {
5745      code = 'NZ';
5746    } else if (tz.indexOf('australia/') >= 0 || lang === 'en-au') {
5747      code = 'AU';
5748    }
5749
5750    if (code) select.value = code;
5751  } catch (e) { /* detection is best-effort */ }
5752})();
5753</script>
5753
5754                    <div class="field">
5755                        <label>Pick your agent</label>
5756                        <div class="radios">
5757                                                        <label class="radio"><input type="radio" name="agent_type" value="assistant"  data-plan-key="assistant"><span class="dot"></span><div><div class="ttl">Personal Assistant</div><div class="sub">One mobile or landline. Personal use.</div></div></label>
5758                            <label class="radio"><input type="radio" name="agent_type" value="reception" checked data-plan-key="reception"><span class="dot"></span><div><div class="ttl">Reception</div><div class="sub">24/7 call answering for a business</div></div></label>
5759                            <label class="radio"><input type="radio" name="agent_type" value="sales"  data-plan-key="sales"><span class="dot"></span><div><div class="ttl">Sales Agent</div><div class="sub">Inbound qualifier, CRM-synced</div></div></label>
5760                            <label class="radio"><input type="radio" name="agent_type" value="booking"  data-plan-key="booking"><span class="dot"></span><div><div class="ttl">Booking Service</div><div class="sub">Live calendar, conflict-aware</div></div></label>
5761                            <label class="radio"><input type="radio" name="agent_type" value="outgoing"  data-plan-key="outgoing"><span class="dot"></span><div><div class="ttl">Outgoing Agent</div><div class="sub">Your agent does the ringing, billed per call</div></div></label>
5762                            <label class="radio"><input type="radio" name="agent_type" value="survey"  data-plan-key="survey"><span class="dot"></span><div><div class="ttl">Campaign Agent</div><div class="sub">Rings your list, asks your questions, billed per call</div></div></label>
5763                            <label class="radio"><input type="radio" name="agent_type" value="wellness"  data-plan-key="wellness"><span class="dot"></span><div><div class="ttl">Wellness Checks</div><div class="sub">Rings someone daily to check they're alright</div></div></label>
5764                        </div>
5765                        <p class="plan-recommend" data-plan-recommend style="display:none">
5766                            We recommend running an incoming agent alongside an outgoing or campaign agent. People you ring will often ring you
5767                            back, and an incoming agent makes sure those return calls are answered rather than missed. If you would
5768                            rather not add one, we can clone your business caller ID so return calls come straight back to your
5769                            existing phone.
5770                        </p>
5771                    </div>
5772
5773                    <div class="field">
5774                        <label>How you want to pay</label>
5775                        <div class="radios">
5776                            <label class="radio">
5777                                <input type="radio" name="plan" value="broadcast" checked>
5778                                <span class="dot"></span>
5779                                <div><div class="ttl">Monthly plan</div><div class="sub">A set monthly price with included minutes. Most people choose this. Cancel anytime.</div></div>
5780                            </label>
5781                            <label class="radio">
5782                                <input type="radio" name="plan" value="payg" >
5783                                <span class="dot"></span>
5784                                <div><div class="ttl">Pay as you go</div><div class="sub">$1 a minute and 15c a text, prepaid from a balance. $10/month covers your phone number, and you start with $10 of free credit on top. Cancel anytime.</div></div>
5785                            </label>
5786                        </div>
5787                    </div>
5788
5789                    <div class="plan-display" data-plan-display>
5790                        <div class="plan-display-left">
5791                            <div class="plan-display-label" data-plan-label>Personal Assistant</div>
5792                            <div class="plan-display-sub" data-plan-sub>Single mobile or landline. Built for one person, not a business.</div>
5793                        </div>
5794                        <div class="plan-display-right">
5795                            <div class="plan-display-price" data-plan-price>$89<small>/mo</small></div>
5796                            <div class="plan-display-tier" data-plan-tier>Shortwave plan</div>
5797                                                        <div class="plan-display-note" data-plan-note  style="display:none" ></div>
5798                        </div>
5799                    </div>
5800                    <p class="founding-line">
5801                                                    <span class="fl-tag">Founding rate</span> On a monthly plan your price is locked in at the founding rate for your first 3 months, then the standard rate applies. Pay as you go has no founding step: the rate is just the rate.
5802                                                Plans include 50 to 200 minutes a month, then 10c a minute. The first 20 texts each month are free, then 9c each.
5803                    </p>
5804                    <p class="plan-asterisk" data-plan-asterisk style="display:none">
5805                        <span>*</span> Subject to your CRM or booking system. Additional implementation cost may apply for non-standard integrations.
5806                    </p>
5807
5808                    <div class="actions">
5809                        <span class="note">● Your data stays in NZ.</span>
5810                        <button type="submit" class="btn btn-primary btn-lg">Create your first agent <span class="arr">→</span></button>
5811                    </div>
5812                </form>
5813
5814                
5814<script>
5815                    (function () {
5816                        // A plan only carries a crossed-out "was" price and a founding note while
5817                        // its intro price is genuinely below its standard price; when the two
5818                        // match in the pricing table both come through blank and the picker
5819                        // shows a plain price. Per-call plans never have a founding step.
5820                        const PA_NOTE = "";
5821                        const BIZ_NOTE = "Founding rate for your first 3 months, then $199/mo";
5822                        const PA_WAS = "";
5823                        const BIZ_WAS = "$199";
5824
5825                        const PLANS = {
5826                            assistant: { label: 'Personal Assistant', sub: 'Single mobile or landline. Built for one person, not a business.', was: PA_WAS, price: '$89', suffix: '/mo', tier: 'Shortwave plan · personal use only', note: PA_NOTE, asterisk: false },
5827                            reception: { label: 'Reception',         sub: '24/7 AI call answering for your business. Bundled with Sales on the Broadcast plan.', was: BIZ_WAS, price: '$129', suffix: '/mo', tier: 'Broadcast plan · includes Sales Agent', note: BIZ_NOTE, asterisk: false },
5828                            sales:     { label: 'Sales Agent',       sub: 'Inbound lead qualification with CRM sync. Bundled with Reception on the Broadcast plan.', was: BIZ_WAS, price: '$129', suffix: '/mo', tier: 'Broadcast plan · includes Reception *', note: BIZ_NOTE, asterisk: true },
5829                            booking:   { label: 'Booking Service',   sub: 'Live calendar booking into your booking system, with custom API integration where needed.', was: '', price: 'from $499', suffix: '/mo', tier: 'Custom setup · 12-month contract *', note: 'Quoted per build, on a 12-month term.', asterisk: true },
5830                            outgoing:  { label: 'Outgoing Agent',    sub: 'Your agent makes the calls: follow-ups, appointment reminders, confirmations and callbacks. It rings out on a Talkify number, or we can show your own business caller ID instead.', was: '', price: '$59', suffix: '/mo', tier: 'Outgoing campaigns · 20 minutes included, then 50c/min', note: 'Charged only in months you run campaigns. One-off calls outside a campaign are just 50c a minute, no monthly fee.', asterisk: false, recommend: true },
5831                            survey:    { label: 'Campaign Agent',    sub: 'Import your list and the agent rings everyone, asks your questions and reads each conversation against your goal, so you get answers, sentiment and hot leads by name.', was: '', price: '$59', suffix: '/mo', tier: 'Outgoing campaigns · 20 minutes included, then 50c/min', note: 'Marketing runs and phone surveys are the same plan, charged only in months you run one.', asterisk: false, recommend: true },
5832                            wellness:  { label: 'Wellness Checks',   sub: 'Scheduled or randomly timed check-in calls to somebody living alone. The agent asks how they are, gives medication and appointment reminders, texts you after every call and escalates down your contact list when nobody answers.', was: '', price: 'from $59', suffix: '/mo', tier: 'Family Member (one person) · $599 for as many as you like', note: 'Includes 20 call minutes, or 200 pooled minutes on Providers. Priced by how many people are rung, not by features.', asterisk: false },
5833                        };
5834                        // The pay-as-you-go face of the same picker: whatever agent they chose,
5835                        // the money side is the per-minute wallet, so the price panel follows
5836                        // the payment choice rather than quoting a monthly plan.
5837                        const PAYG = {
5838                            price: '$1',
5839                            suffix: '/min',
5840                            tier: 'Pay as you go · $10/month covers your phone number',
5841                            note: '$10 free credit to start, on top of the number. Calls and texts come off your prepaid balance.',
5842                        };
5843                        const form = document.currentScript.closest('.endcta-form') || document;
5844                        const radios = form.querySelectorAll('input[name="agent_type"]');
5845                        const payRadios = form.querySelectorAll('input[name="plan"]');
5846                        const labelEl = form.querySelector('[data-plan-label]');
5847                        const subEl = form.querySelector('[data-plan-sub]');
5848                        const priceEl = form.querySelector('[data-plan-price]');
5849                        const tierEl = form.querySelector('[data-plan-tier]');
5850                        const noteEl = form.querySelector('[data-plan-note]');
5851                        const astEl = form.querySelector('[data-plan-asterisk]');
5852                        const recEl = form.querySelector('[data-plan-rec
5852ommend]');
5853
5854                        function update(){
5855                            const checked = form.querySelector('input[name="agent_type"]:checked');
5856                            if (!checked) return;
5857                            const plan = PLANS[checked.value];
5858                            if (!plan) return;
5859                            const pay = form.querySelector('input[name="plan"]:checked');
5860                            const payg = pay && pay.value === 'payg';
5861                            labelEl.textContent = plan.label;
5862                            subEl.textContent = plan.sub;
5863                            priceEl.innerHTML = payg
5864                                ? PAYG.price + '<small>' + PAYG.suffix + '</small>'
5865                                : (plan.was ? '<s class="was-price">'+plan.was+'</s> ' : '') + plan.price + (plan.suffix ? '<small>'+plan.suffix+'</small>' : '');
5866                            tierEl.textContent = payg ? PAYG.tier : plan.tier;
5867                            if (noteEl) {
5868                                const note = payg ? PAYG.note : (plan.note || '');
5869                                noteEl.textContent = note;
5870                                noteEl.style.display = note ? 'block' : 'none';
5871                            }
5872                            astEl.style.display = (!payg && plan.asterisk) ? 'block' : 'none';
5873                            if (recEl) recEl.style.display = plan.recommend ? 'block' : 'none';
5874                        }
5875                        radios.forEach(r => r.addEventListener('change', update));
5876                        payRadios.forEach(r => r.addEventListener('change', update));
5877                        update();
5878                    })();
5879                </script>
5879
5880            </div>
5881            </div>
5882
5883            <style>
5884            /* Two top-ruled columns rather than two pills side by side. The pair is
5885               held to a readable measure and centred under the headline, so the
5886               block still reads as the close of the page even though the section
5887               itself is centred and these two are ruled and left-aligned. */
5888            .endcta-numbers {
5889                display: grid;
5890                grid-template-columns: 1fr 1fr;
5891                gap: clamp(24px, 4vw, 56px);
5892                margin: 56px auto 0;
5893                max-width: 780px;
5894                text-align: left
5895            }
5896
5897            @media (max-width: 800px) {
5898                .endcta-numbers {
5899                    grid-template-columns: 1fr;
5900                    gap: 30px;
5901                    max-width: 460px
5902                }
5903            }
5904
5905            .endcta-alt {
5906                margin-top: 36px;
5907                display: flex;
5908                flex-wrap: wrap;
5909                gap: 12px;
5910                justify-content: center
5911            }
5912
5913            /* The app line sits under the two ways to reach us and quieter than
5914               either, because it is aimed at people who have already signed up. */
5915            .endcta-app-line {
5916                margin-top: 40px;
5917                font-family: var(--mono);
5918                font-size: 10px;
5919                letter-spacing: .18em;
5920                text-transform: uppercase;
5921                color: var(--mute)
5922            }
5923
5924            .endcta .app-stores {
5925                margin-top: 14px;
5926                justify-content: center
5927            }
5928
5929            /* ── With the form in it ───────────────────────────────────────────
5930               The pitch stops being a centred banner and becomes the left half
5931               of one closing block, with the get-started form on the right. No
5932               panel and no rounding: the two columns simply share the page. */
5933            .endcta-has-form .endcta-wrap {
5934                display: grid;
5935                grid-template-columns: 1fr 1.05fr;
5936                gap: clamp(40px, 5vw, 76px);
5937                align-items: start;
5938                max-width: 1240px;
5939                margin: 0 auto;
5940                text-align: left
5941            }
5942
5943            /* The skyline sits behind a short centred banner comfortably. Behind
5944               a block three times as tall it runs up under the form fields and
5945               the price panel, where a photograph is just noise, so it is held
5946               well back and the scrim is carried the whole way down instead of
5947               fading out in the middle. */
5948            .endcta.endcta-has-form .endcta-photo {
5949                opacity: .12;
5950                background-position: center bottom
5951            }
5952
5953            html[data-theme="light"] .endcta.endcta-has-form .endcta-photo {
5954                opacity: .16
5955            }
5956
5957            .endcta.endcta-has-form .endcta-photo::after {
5958                background: linear-gradient(180deg, var(--scrim-mid) 0%, var(--scrim-strong) 30%, var(--scrim-strong) 100%)
5959            }
5960
5961            .endcta-has-form .endcta-numbers {
5962                grid-template-columns: 1fr;
5963                gap: 26px;
5964                margin: 44px 0 0;
5965                max-width: none
5966            }
5967
5968            .endcta-has-form .endcta-meta {
5969                justify-content: flex-start;
5970                gap: 22px
5971            }
5972
5973            .endcta-has-form .endcta-alt,
5974            .endcta-has-form .app-stores {
5975                justify-content: flex-start
5976            }
5977
5978            .endcta-form .eyebrow {
5979                display: inline-flex;
5980                margin-bottom: 20px
5981            }
5982
5983            @media (max-width: 1000px) {
5984                .endcta-has-form .endcta-wrap {
5985                    grid-template-columns: 1fr;
5986                    gap: 48px
5987                }
5988
5989                .endcta-has-form .endcta-numbers {
5990                    max-width: 460px
5991                }
5992            }
5993
5994            /* Carried over from the signup section this block absorbed: that
5995               partial's styles only ship on the page that includes it, and it
5996               is now only included by /v2. */
5997            .signup-errors {
5998                margin-bottom: 18px;
5999                padding: 14px 0 14px 16px;
6000                border-left: 2px solid var(--coral);
6001                font-family: var(--mono);
6002                font-size: 12px;
6003                line-height: 1.6;
6004                color: var(--paper)
6005            }
6006
6007            .was-price {
6008                font-size: .55em;
6009                color: var(--mute-2);
6010                text-decoration: line-through;
6011                text-decoration-color: var(--coral);
6012                margin-right: 4px;
6013                font-weight: 300
6014            }
6015
6016            .founding-line {
6017                margin-top: 14px;
6018                font-family: var(--sans);
6019                font-size: 12px;
6020                line-height: 1.55;
6021                color: var(--mute)
6022            }
6023
6024            .founding-line .fl-tag {
6025                font-family: var(--mono);
6026                font-size: 10px;
6027                letter-spacing: .14em;
6028                text-transform: uppercase;
6029                color: var(--signal);
6030                margin-right: 8px
6031            }
6032        </style>
6033    </section>
6034
6035<style>
6036    .foot-social {
6037        display: inline-flex;
6038        align-items: center;
6039        gap: 8px;
6040        padding: 6px 0;
6041        font-family: var(--mono);
6042        font-size: 11px;
6043        color: var(--mute);
6044        letter-spacing: .06em;
6045        transition: color .25s var(--ease);
6046    }
6047
6048    .foot-social:hover { color: var(--paper); }
6049
6050    /* The badges sit tighter than the marketing rows and wrap rather than
6051       squeeze, because this column is the narrowest place they appear. */
6052    .foot-apps {
6053        margin-top: 22px;
6054        gap: 10px;
6055    }
6056</style>
6057<footer class="foot">
6058    <div class="foot-grid">
6059        <div class="foot-brand">
6060            
6061            <a class="logo" href="https://talkify.nz" aria-label="Talkify, home"
6062               style="display:flex;align-items:center;gap:14px;color:inherit;text-decoration:none">
6063                <svg class="tk-logo" viewBox="-3 -3 317.81 106"
6064     width="125.92" height="42"
6065     xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Talkify" focusable="false">
6066        <circle cx="50" cy="50" r="50" fill="var(--tk-word, #101820)"/>
6067    
6068    <g fill="none" stroke="var(--tk-ground, #ffffff)" stroke-width="10" stroke-linecap="round">
6069        <path d="M34 26 V54 C34 74 62 80 76 62"/>
6070        <path d="M20 40 H46"/>
6071    </g>
6072    
6073    <g transform="translate(56 20) scale(0.30)">
6074        <g class="tk-eye">
6075            <path d="M50 8 Q55.5 39 92 50 Q55.5 61 50 92 Q44.5 61 8 50 Q44.5 39 50 8 Z" fill="var(--tk-ground, #ffffff)"/>
6076        </g>
6077    </g>
6078            <path d="M271.37 19.44 L274.1 19.47 L276.98 20.13 L279.56 21.51 L281.93 23.58 L276.86 28.65 L275.24 27.45 L274.04 26.97 L273.32 26.85 L270.62 26.97 L269.6 27.27 L268.28 28.05 L267.23 29.28 L266.57 30.96 L266.39 32.28 L266.39 37.38 L284.84 37.41 L293.66 59.85 L302.99 37.5 L311.81 37.44 L289.55 86.04 L289.34 86.37 L288.98 86.37 L280.61 86.34 L289.25 68.4 L276.89 39.18 L276.8 44.61 L266.39 44.64 L266.36 71.97 L258.47 71.94 L258.47 44.64 L250.19 44.58 L250.19 37.44 L258.44 37.41 L258.47 32.28 L258.71 30 L259.49 27.36 L260.69 25.14 L262.52 23.01 L264.98 21.21 L267.8 20.01 L270.08 19.53ZM190.01 20.16 L197.93 20.16 L197.93 71.94 L190.01 71.94ZM204.53 20.16 L212.45 20.16 L212.48 53.61 L226.46 37.41 L235.85 37.44 L221.33 53.94 L230.24 64.47 L236.57 71.94 L226.52 71.97 L212.48 55.05 L212.45 71.94 L204.53 71.94ZM131.63 23.04 L139.55 23.04 L139.58 37.41 L147.83 37.44 L147.8 44.61 L139.55 44.64 L139.55 71.94 L131.63 71.94 L131.63 44.64 L123.35 44.58 L123.38 37.41 L131.63 37.38ZM164.09 36.72 L167.06 36.81 L170.24 37.59 L171.92 38.37 L173.42 39.33 L175.4 41.19 L175.52 37.41 L183.41 37.44 L183.41 71.94 L175.52 71.97 L175.46 68.25 L174.08 69.57 L172.85 70.44 L170.84 71.55 L169.34 72.09 L167.84 72.45 L165.8 72.69 L163.76 72.69 L161.84 72.45 L159.92 71.97 L158.48 71.43 L156.44 70.35 L154.76 69.15 L152.27 66.66 L150.47 63.96 L149.57 62.04 L148.91 60.06 L148.55 58.5 L148.25 55.86 L148.37 52.2 L148.79 49.86 L149.39 47.88 L149.93 46.56 L151.01 44.58 L152.33 42.72 L153.65 41.28 L156.5 39.03 L158.54 37.95 L159.98 37.41 L161.9 36.93ZM239.21 37.44 L247.13 37.44 L247.13 71.94 L239.21 71.94ZM165.2 44.19 L163.04 44.61 L161.48 45.27 L159.98 46.29 L158.51 47.82 L157.73 49.02 L156.83 51.18 L156.41 53.52 L156.41 55.86 L156.65 57.48 L157.31 59.52 L158.51 61.56 L160.04 63.15 L161.48 64.11 L163.46 64.89 L165.32 65.19 L167.12 65.13 L169.34 64.77 L171.14 63.99 L172.34 63.15 L173.99 61.38 L175.01 59.64 L175.67 57.66 L175.97 55.44 L175.91 53.1 L175.49 51 L174.53 48.78 L173.81 47.7 L172.52 46.35 L170.84 45.21 L169.16 44.55 L167.18 44.19Z" fill="var(--tk-word, #101820)" fill-rule="evenodd"/>
6079        
6080        <g transform="translate(231.30 6.84) scale(0.216)">
6081            <path d="M50 8 Q55.5 39 92 50 Q55.5 61 50 92 Q44.5 61 8 50 Q44.5 39 50 8 Z"
6082                  fill="var(--tk-word, #101820)"/>
6083        </g>
6084    </svg>
6085            </a>
6086                                        <p>The voice operating system for New Zealand business. Built in Aotearoa, hosted in Aotearoa, working while
6087                    you don't.</p>
6088                        <div
6089                style="margin-top:20px;font-family:var(--mono);font-size:12px;color:var(--mute);letter-spacing:.06em;line-height:1.7">
6090                                <span style="color:var(--mute);font-size:10px;text-transform:uppercase;letter-spacing:.18em">Sign up by phone</span><br>
6091                <a href="tel:+64800002967" style="color:var(--bone);transition:.25s">0800 002 967</a><br>
6092                                <span
6093                    style="color:var(--mute);font-size:10px;text-transform:uppercase;letter-spacing:.18em;margin-top:8px;display:inline-block">Hear an agent demo</span><br>
6094                <a href="tel:+6432421262" data-talkify-agent="default" style="color:var(--bone);transition:.25s">03 242 1262</a>
6095                                    <br>
6096                    <span
6097                        style="color:var(--mute);font-size:10px;text-transform:uppercase;letter-spacing:.18em;margin-top:8px;display:inline-block">Text our agent</span><br>
6098                    <a href="sms:+64272048827" style="color:var(--bone);transition:.25s">027 204 8827</a>
6099                            </div>
6100            <div style="margin-top:20px;
6100display:flex;flex-wrap:wrap;gap:8px 22px;align-items:center">
6101                <a href="https://www.facebook.com/profile.php?id=61572226258048" target="_blank"
6102                   rel="noopener noreferrer" aria-label="Facebook"
6103                   class="foot-social">
6104                    <svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor">
6105                        <path
6106                            d="M24 12.073c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.99 4.388 10.954 10.125 11.854v-8.385H7.078v-3.47h3.047V9.43c0-3.007 1.792-4.669 4.533-4.669 1.312 0 2.686.235 2.686.235v2.953H15.83c-1.491 0-1.956.925-1.956 1.874v2.25h3.328l-.532 3.47h-2.796v8.385C19.612 23.027 24 18.062 24 12.073z"/>
6107                    </svg>
6108                    Facebook
6109                </a>
6110                <a href="https://www.instagram.com/talkifynz/" target="_blank"
6111                   rel="noopener noreferrer" aria-label="Instagram"
6112                   class="foot-social">
6113                    <svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor">
6114                        <path
6115                            d="M12 2.16c3.2 0 3.58.012 4.85.07 1.17.054 1.805.25 2.227.415.56.217.96.477 1.38.896.42.42.68.82.897 1.38.164.423.36 1.058.413 2.228.058 1.27.07 1.65.07 4.85s-.012 3.58-.07 4.85c-.054 1.17-.25 1.805-.413 2.227a3.72 3.72 0 0 1-.897 1.382c-.42.42-.82.68-1.38.896-.423.165-1.058.36-2.228.414-1.27.058-1.65.07-4.85.07s-3.58-.012-4.85-.07c-1.17-.054-1.805-.25-2.227-.414a3.72 3.72 0 0 1-1.38-.896 3.72 3.72 0 0 1-.897-1.382c-.164-.422-.36-1.057-.414-2.227C2.173 15.58 2.16 15.2 2.16 12s.013-3.58.07-4.85c.055-1.17.25-1.805.415-2.228.217-.56.477-.96.896-1.38.42-.42.82-.68 1.38-.896.423-.165 1.058-.36 2.228-.414C8.42 2.173 8.8 2.16 12 2.16zM12 0C8.74 0 8.333.014 7.053.072 5.775.13 4.905.333 4.14.63a5.88 5.88 0 0 0-2.126 1.384A5.88 5.88 0 0 0 .63 4.14C.333 4.905.13 5.775.072 7.053.014 8.333 0 8.74 0 12s.014 3.667.072 4.947c.058 1.277.261 2.148.558 2.913a5.88 5.88 0 0 0 1.384 2.126 5.88 5.88 0 0 0 2.126 1.384c.765.296 1.635.499 2.913.558C8.333 23.986 8.74 24 12 24s3.667-.014 4.947-.072c1.277-.06 2.148-.262 2.913-.558a5.88 5.88 0 0 0 2.126-1.384 5.88 5.88 0 0 0 1.384-2.126c.296-.765.499-1.636.558-2.913C23.986 15.667 24 15.26 24 12s-.014-3.667-.072-4.947c-.06-1.278-.262-2.148-.558-2.913a5.88 5.88 0 0 0-1.384-2.126A5.88 5.88 0 0 0 19.86.63c-.765-.297-1.636-.5-2.913-.558C15.667.014 15.26 0 12 0zm0 5.838a6.162 6.162 0 1 0 0 12.324 6.162 6.162 0 0 0 0-12.324zM12 16a4 4 0 1 1 0-8 4 4 0 0 1 0 8zm7.846-10.405a1.44 1.44 0 1 1-2.88 0 1.44 1.44 0 0 1 2.88 0z"/>
6116                    </svg>
6117                    Instagram
6118                </a>
6119                <a href="https://www.linkedin.com/company/talkify-nz/" target="_blank"
6120                   rel="noopener noreferrer" aria-label="LinkedIn"
6121                   class="foot-social">
6122                    <svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor">
6123                        <path
6124                            d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433a2.062 2.062 0 0 1-2.063-2.065 2.064 2.064 0 1 1 2.063 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z"/>
6125                    </svg>
6126                    LinkedIn
6127                </a>
6128            </div>
6129
6130            
6131            <div class="app-stores foot-apps" style="--app-badge-h: 38px">
6132    <a class="app-badge" href="https://apps.apple.com/nz/app/talkify-mobile/id6766709308"
6133       target="_blank" rel="noopener">
6134        <img src="https://talkify.nz/media/branding/apple-app-store.svg"
6135             alt="Download Talkify Mobile on the App Store"
6136             width="113.7" height="38" loading="lazy">
6137    </a>
6138    <a class="app-badge" href="https://play.google.com/store/apps/details?id=com.talkifynz.app"
6139       target="_blank" rel="noopener">
6140        <img src="https://talkify.nz/media/branding/google-app-store.svg"
6141             alt="Get Talkify Mobile on Google Play"
6142             width="128.3" height="38" loading="lazy">
6143    </a>
6144</div>
6145        </div>
6146        <div>
6147            <h4>Agents</h4>
6148            <ul>
6149                <li><a href="https://talkify.nz/reception">Reception</a></li>
6150                <li><a href="https://talkify.nz/personal-assistant">Personal Assistant</a></li>
6151                <li><a href="https://talkify.nz/booking-service">Booking Service</a></li>
6152                <li><a href="https://talkify.nz/sales-agent">Sales Agent</a></li>
6153                <li><a href="https://talkify.nz/ai-phone-surveys">Campaign Agent</a></li>
6154                <li><a href="https://talkify.nz/debt-collection">Debt Collection</a></li>
6155                <li><a href="https://talkify.nz/ai-wellness-checks">Wellness Checks</a></li>
6156                <li>
6156<a href="https://talkify.nz/outbound-calls">Outbound Calls</a></li>
6157                <li><a href="https://talkify.nz/ai-marketing-campaigns">Marketing Campaigns</a></li>
6158                <li><a href="https://talkify.nz/website-chat">Website Chat</a></li>
6159                <li><a href="https://talkify.nz/calendar">Team Calendar</a></li>
6160                <li><a href="https://talkify.nz/dialler">Dialler</a></li>
6161                <li><a href="https://talkify.nz/agents">All agents &rarr;</a></li>
6162            </ul>
6163        </div>
6164        
6165        <div>
6166            <h4>Trades</h4>
6167            <ul>
6168                <li><a href="https://talkify.nz/plumber">Plumbing</a></li>
6169                <li><a href="https://talkify.nz/electrician">Electricians</a></li>
6170                <li><a href="https://talkify.nz/builder">Builders</a></li>
6171                <li><a href="https://talkify.nz/hvac">Heat Pump &amp; HVAC</a></li>
6172                <li><a href="https://talkify.nz/automotive">Mechanics &amp; Workshops</a></li>
6173                <li><a href="https://talkify.nz/landscaping">Landscaping</a></li>
6174                <li><a href="https://talkify.nz/pest-control">Pest Control</a></li>
6175                <li><a href="https://talkify.nz/tradesman">All Trades</a></li>
6176            </ul>
6177        </div>
6178        <div>
6179            <h4>Industries</h4>
6180            <ul>
6181                <li><a href="https://talkify.nz/beauty">Beauty &amp; Wellness</a></li>
6182                <li><a href="https://talkify.nz/real-estate">Real Estate</a></li>
6183                <li><a href="https://talkify.nz/retail">Retail</a></li>
6184                <li><a href="https://talkify.nz/professional-services">Professional Services</a></li>
6185                <li><a href="https://talkify.nz/barber">Barbers</a></li>
6186                <li><a href="https://talkify.nz/gym">Gyms &amp; Studios</a></li>
6187                <li><a href="https://talkify.nz/personal-trainer">Personal Trainers</a></li>
6188                <li><a href="https://talkify.nz/hotel">Hotels &amp; Motels</a></li>
6189                <li><a href="https://talkify.nz/accountant">Accountants</a></li>
6190                <li><a href="https://talkify.nz/industries">All industries &rarr;</a></li>
6191            </ul>
6192        </div>
6193        <div>
6194            
6195            <h4>Call answering</h4>
6196            <ul>
6197                <li><a href="https://talkify.nz">AI receptionist NZ</a></li>
6198                <li><a href="https://talkify.nz/ai-phone-agent">AI phone agent NZ</a></li>
6199                <li><a href="https://talkify.nz/virtual-receptionist">Virtual receptionist NZ</a></li>
6200                <li><a href="https://talkify.nz/ai-answering-service">AI answering service NZ</a></li>
6201                <li><a href="https://talkify.nz/after-hours-answering">After hours answering NZ</a></li>
6202                <li><a href="https://talkify.nz/on-call-roster">On-Call Roster</a></li>
6203                <li><a href="https://talkify.nz/ai-call-centre">AI Call Centre Agents</a></li>
6204                <li><a href="https://talkify.nz/business-phone-lines">Business Phone Lines</a></li>
6205                
6206                <li style="margin-top:6px;color:var(--mute);line-height:1.8">
6207                    By city:
6208                    <a
6209                            href="https://talkify.nz/ai-receptionist-auckland">Auckland</a><span
6210                            style="color:var(--line-2)"> · </span><a
6211                            href="https://talkify.nz/ai-receptionist-wellington">Wellington</a><span
6212                            style="color:var(--line-2)"> · </span><a
6213                            href="https://talkify.nz/ai-receptionist-christchurch">Christchurch</a><span
6214                            style="color:var(--line-2)"> · </span><a
6215                            href="https://talkify.nz/ai-receptionist-hamilton">Hamilton</a><span
6216                            style="color:var(--line-2)"> · </span><a
6217                            href="https://talkify.nz/ai-receptionist-tauranga">Tauranga</a><span
6218                            style="color:var(--line-2)"> · </span><a
6219                            href="https://talkify.nz/ai-receptionist-dunedin">Dunedin</a>                </li>
6220            </ul>
6221        </div>
6222        <div>
6223            
6224            <h4>Company</h4>
6225            <ul>
6226                <li><a href="https://talkify.nz/pricing">Pricing</a></li>
6227                <li><a href="https://talkify.nz/integrations">Integrations</a></li>
6228                
6229                <li><a href="https://talkify.nz/compare">Compare Providers</a><span
6230                        style="color:var(--line-2)"> · </span><a
6231                        href="https://talkify.nz/alternatives">Alternatives</a></li>
6232                <li><a href="https://talkify.nz/missed-call-calculator">Missed Call Calculator</a></li>
6233                <li><a href="https://talkify.nz/blog">Journal</a></li>
6234                
6235                <li><a href="https://talkify.nz/help">Help centre</a><span
6236                        style="color:var(--line-2)"> · </span><a
6237                        href="https://talkify.nz/contact-us">Contact us</a></li>
6238                <li><a href="https://talkify.nz/demo">Live demo</a></li>
6239                <li><a href="https://talkify.nz/signup">Get started</a></li>
6240            </ul>
6241        </div>
6242    </div>
6243    <div class="foot-bot">
6244                    <span>© <span id="year">2026</span> · Talkify Limited · NZ owned and hosted</span>
6245                <span>
6246            
6247                            <span aria-current="page">New Zealand</span> · <a href="https://talkify.nz/au" style="color:var(--bone)">Australia</a> ·
6248                        <a href="https://talkify.nz/privacy" style="color:var(--bone)">Privacy</a> ·
6249            <a href="https://talkify.nz/terms" style="color:var(--bone)">Terms</a> ·
6250            <a href="https://talkify.nz/support" style="color:var(--bone)">Support</a> ·
6251                            <a href="https://talkify.nz/login" style="color:var(--bone)">Sign in</a>
6252                        · <a href="https://d3v.nz" style="color:var(--bone)">Made by D3V</a>
6253        </span>
6254    </div>
6255</footer>
6256
6257
6258
6259
6260
6261
6262
6263
6264
6265
6266<script>
6267    function tick() {
6268        const d = new Date();
6269        const f = new Intl.DateTimeFormat('en-NZ', {
6270            timeZone: 'Pacific/Auckland',
6271            hour: '2-digit',
6272            minute: '2-digit',
6273            second: '2-digit',
6274            hour12: false
6275        });
6276        const el = document.getElementById('clock');
6277        if (el) el.textContent = f.format(d);
6278    }
6279
6280    tick();
6281    setInterval(tick, 1000);
6282    const yEl = document.getElementById('year');
6283    if (yEl) yEl.textContent = new Date().getFullYear();
6284
6285    /* Scroll reveal. Fires once per block. Anybody who has asked for less
6286       motion, and any browser without IntersectionObserver, gets the lot
6287       revealed immediately rather than a page of invisible sections. */
6288    (function () {
6289        const blocks = document.querySelectorAll('.r');
6290        if (!blocks.length) return;
6291        const reduce = window.matchMedia
6292            && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
6293        if (reduce || !('IntersectionObserver' in window)) {
6294            blocks.forEach(el => el.classList.add('in'));
6295            return;
6296        }
6297        const io = new IntersectionObserver((entries) => {
6298            entries.forEach(e => {
6299                if (e.isIntersecting) {
6300                    e.target.classList.add('in');
6301                    io.unobserve(e.target);
6302                }
6303            });
6304        }, {rootMargin: '-8% 0px -5% 0px'});
6305        blocks.forEach(el => io.observe(el));
6306    })();
6307
6308    /* Agent phones. Each opens on a plain lock screen, then the clock drops to
6309       its compact size and the notifications land on top of it, which is the
6310       order an iPhone does it in. Plays once, when the panel is on screen.
6311
6312       The clock is the VISITOR'S OWN time and every stamp is counted back from
6313       it, so a screen can never show a notification that arrived after the time
6314       printed above it. Nothing is written into the markup, so a cached page
6315       cannot go stale either.
6316
6317       The tilt and the sheen are a couple of degrees and a highlight eased
6318       across the viewport. Both are off on coarse pointers, where there is no
6319       hover to reward them and the scroll handler is pure cost, and the whole
6320       thing collapses to "already arrived" under prefers-reduced-motion. */
6321    (function () {
6322        const phones = [...document.querySelectorAll('[data-agent-phone]')];
6323        if (!phones.length) return;
6324
6325        const clockOf = d => d.toLocaleTimeString('en-NZ', {hour: 'numeric', minute: '2-digit', hour12: false});
6326        const stampOf = d => d.toLocaleTimeString('en-NZ', {hour: 'numeric', minute: '2-digit', hour12: true})
6327            .replace(/\s/g, '').toLowerCase();
6328        const dateOf = d => d.toLocaleDateString('en-NZ', {weekday: 'long', day: 'numeric', month: 'long'});
6329
6330        const still = matchMedia('(prefers-reduced-motion: reduce)').matches;
6331        const coarse = matchMedia('(pointer: coarse)').matches;
6332
6333        phones.forEach(phone => {
6334            // A phone may pin its own clock with data-agent-at="HH:MM". The
6335            // after-hours story is an escalation at a quarter to midnight, and
6336            // stamped 2pm on a daytime visitor's own clock it reads as
6337            // nonsense. Everything else still shows the visitor's real time,
6338            // counted back from, so nothing arrives after the clock above it.
6339            const now = new Date();
6340            const pinned = (phone.dataset.agentAt || '').match(/^(\d{1,2}):(\d{2})$/);
6341            if (pinned) now.setHours(+pinned[1], +pinned[2], 0, 0);
6342
6343            const t = phone.querySelector('[data-agent-time]');
6344            const dt = phone.querySelector('[data-agent-date]');
6345            if (t) t.textContent = clockOf(now);
6346            if (dt) dt.textContent = dateOf(now);
6347
6348            phone.querySelectorAll('[data-agent-ago]').forEach(el => {
6349                const mins = parseInt(el.dataset.agentAgo, 10);
6350                if (!Number.isFinite(mins)) return;
6351                el.textContent = stampOf(new Date(now.getTime() - mins * 60000));
6352            });
6353
6354            const clock = phone.querySelector('[data-agent-clock]');
6355            const notes = [...phone.querySelectorAll('.hpn')];
6356            if (!clock || !notes.length) return;
6357
6358            if (still) {
6359                clock.classList.add('is-compact');
6360                notes.forEach(n => n.classList.add('is-in'));
6361                return;
6362            }
6363
6364            let played = false;
6365            const play = () => {
6366                if (played) return;
6367                played = true;
6368                setTimeout(() => clock.classList.add('is-compact'), 420);
6369                notes.forEach((n, i) => setTimeout(() => n.classList.add('is-in'), 780 + i * 380));
6370            };
6371
6372            const io = new IntersectionObserver(entries => {
6373                entries.forEach(e => {
6374                    if (!e.isIntersecting) return;
6375                    play();
6376                    io.unobserve(phone);
6377                });
6378            }, {threshold: .35});
6379            io.observe(phone);
6380
6381            if (coarse) return;
6382
6383            const lean = phone.classList.contains('agent-phone--left') ? -1 : 1;
6384            let queued = false;
6385            const tilt = () => {
6386                queued = false;
6387                const r = phone.getBoundingClientRect();
6388                if (r.bottom < 0 || r.top > innerHeight) return;
6389                // -0.5 above the fold, +0.5 below it
6390                const p = (r.top + r.height / 2 - innerHeight / 2) / innerHeight;
6391                phone.style.setProperty('--ag-tilt', (lean * (3 - p * 4.5)).toFixed(2) + 'deg');
6392                phone.style.setProperty('--ag-sheen', (p * -150).toFixed(1) + '%');
6393            };
6394            addEventListener('scroll', () => {
6395                if (queued) return;
6396                queued = true;
6397                requestAnimationFrame(tilt);
6398            }, {passive: true});
6399            tilt();
6400        });
6401    })();
6402
6403
6404    /* Hero phone. The chips are the data source, so the markup stays the one
6405       place the copy lives. Cycling pauses the moment the visitor takes over,
6406       and never starts at all under prefers-reduced-motion. */
6407    (function () {
6408        const root = document.querySelector('[data-hp-stack]');
6409        if (!root) return;
6410        const chips = [...document.querySelectorAll('[data-hp-chip]')];
6411        if (!chips.length) return;
6412
6413        const reduce = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
6414        const icon = document.querySelector('.hpn header img');
6415        const iconSrc = icon ? icon.getAttribute('src') : '';
6416        let i = 0, timer = null, taken = false;
6417
6418        // the phone shows the viewer's own clock, so it reads as their phone
6419        // rather than a screenshot taken at some other time
6420        const clock = () => {
6421            const now = new Date();
6422            const t = document.querySelector('[data-hp-time]');
6423            const d = document.querySelector('[data-hp-date]');
6424            if (t) t.textContent = now.toLocaleTimeString('en-NZ', {hour: 'numeric', minute: '2-digit'})
6425                .replace(/\s?(am|pm)$/i, '');
6426            if (d) d.textContent = now.toLocaleDateString('en-NZ', {weekday: 'long', day: 'numeric', month: 'long'});
6427        };
6428
6429        const AGO = ['now', '2m ago', '8m ago'];
6430
6431        const build = (chip) => {
6432            const frag = document.createDocumentFragment();
6433            // two or three per screen: one card at a time made the phone look
6434            // idle, and a digest is the thing being sold
6435            [['title', 'body'], ['title2', 'body2'], ['title3', 'body3']].forEach((keys, i) => {
6436                const title = chip.dataset[keys[0]], body = chip.dataset[keys[1]];
6437                if (!title) return;
6438                const n = document.createElement('article');
6439                n.className = 'hpn';
6440                n.style.transitionDelay = (i * 620) + 'ms';
6441                n.innerHTML =
6442                    '<header><img src="' + iconSrc + '" alt="" width="18" height="18">' +
6443                    '<span class="hpn-app">Talkify</span><span class="hpn-ago"></span></header>' +
6444                    '<h4></h4><p></p>';
6445                n.querySelector('.hpn-ago').textContent = AGO[i] || 'earlier';
6446                n.querySelector('h4').textContent = title;
6447                n.querySelector('p').textContent = body;
6448                frag.appendChild(n);
6449            });
6450            return frag;
6451        };
6452
6453        const show = (idx) => {
6454            i = (idx + chips.length) % chips.length;
6455            chips.forEach((c, n) => c.classList.toggle('is-on', n === i));
6456            chips.forEach((c, n) => c.setAttribute('aria-selected', n === i ? 'true' : 'false'));
6457            root.replaceChildren(build(chips[i]));
6458            // let the browser paint the start state before transitioning in
6459            requestAnimationFrame(() => requestAnimationFrame(() =>
6460                root.querySelectorAll('.hpn').forEach(n => n.classList.add('is-in'))));
6461        };
6462
6463        const stop = () => { if (timer) { clearInterval(timer); timer = null; } };
6464        const start = () => { if (!reduce && !taken && !timer) timer = setInterval(() => show(i + 1), 7000); };
6465
6466        chips.forEach((chip, n) => {
6467            const take = () => { taken = true; stop(); show(n); };
6468            chip.addEventListener('click', take);
6469            chip.addEventListener('mouseenter', () => { stop(); show(n); });
6470            chip.addEventListener('mouseleave', () => { if (!taken) start(); });
6471        });
6472
6473        // do not animate a phone nobody is looking at
6474        const vis = new IntersectionObserver((es) => {
6475            es.forEach(e => e.isIntersecting ? start() : stop());
6476        }, {threshold: 0.2});
6477        vis.observe(root);
6478
6479        clock();
6480        setInterval(clock, 30000);
6481        show(0);
6482    })();
6483
6484    (function () {
6485        const hero = document.querySelector('.hero-bg');
6486        if (!hero) return;
6487        // Pointer parallax is a mouse affordance: a finger cannot hover, and
6488        // it is exactly the sort of movement prefers-reduced-motion is for.
6489        const mq = (q) => window.matchMedia && window.matchMedia(q).matches;
6490        if (mq('(prefers-reduced-motion: reduce)') || mq('(pointer: coarse)')) return;
6491
6492        let x = 0, y = 0, queued = false;
6493        const paint = () => {
6494            queued = false;
6495            hero.style.transform = `translate(${x}px,${y}px)`;
6496        };
6497        document.addEventListener('mousemove', (e) => {
6498            x = (e.clientX / window.innerWidth - .5) * 24;
6499            y = (e.clientY / window.innerHeight - .5) * 24;
6500            if (!queued) {
6501                queued = true;
6502                requestAnimationFrame(paint);
6503            }
6504        }, {passive: true});
6505    })();
6506
6507    // ─── Live call deck, messages animate in as if the call is happening now ───
6508    (function () {
6509        document.querySelectorAll('.deck').forEach(deck => {
6510            const rows = Array.from(deck.querySelectorAll('.deck-row'));
6511            if (!rows.length) return;
6512
6513            // Insert a typing indicator before each agent row
6514            rows.forEach(row => {
6515                if (row.classList.contains('agent')) {
6516                    const ts = row.querySelector('.ts')?.textContent || '';
6517                    const typing = document.createElement('div');
6518                    typing.className = 'deck-typing';
6519                    typing.innerHTML = `<span class="ts">${ts}</span><span class="who">Talkify</span><span class="dotset"><i></i><i></i><i></i></span>`;
6520                    row.parentNode.insertBefore(typing, row);
6521                }
6522            });
6523
6524            let started = false;
6525            const start = () => {
6526                if (started) return;
6527                started = true;
6528                let t = 400;
6529                rows.forEach(row => {
6530                    if (row.classList.contains('agent')) {
6531                        const typing = row.previousElementSibling;
6532                        if (typing && typing.classList.contains('deck-typing')) {
6533                            setTimeout(() => typing.classList.add('on'), t);
6534                            t += 900;
6535                            setTimeout(() => typing.classList.remove('on'), t);
6536                            t += 200;
6537                        }
6538                    }
6539                    setTimeout(() => row.classList.add('in'), t);
6540                    t += 1200;
6541                });
6542
6543                // After the prepared script plays, optionally append a follow-up exchange
6544                const followup = deck.dataset.followup;
6545                if (followup === 'on') {
6546                    setTimeout(() => {
6547                        appendDeckExchange(deck);
6548                    }, t + 1500);
6549                }
6550            };
6551
6552            const io = new IntersectionObserver(entries => {
6553                entries.forEach(e => {
6554                    if (e.isIntersecting) {
6555                        start();
6556                        io.unobserve(deck);
6557                    }
6558                });
6559            }, {threshold: 0.25});
6560            io.observe(deck);
6561        });
6562
6563        function appendDeckExchange(deck) {
6564            // Append one extra caller + agent exchange to the home hero deck
6565            const followups = [
6566                {
6567                    caller: "One more thing, can my partner come too?",
6568                    agent: "Of course. I'll add them to the appointment. Anything else?"
6569                },
6570                {
6571                    caller: "Is there parking?",
6572                    agent: "Yep, two-hour free parking on Vivian Street, or paid building parking off the lobby."
6573                },
6574            ];
6575            const ex = followups[Math.floor(Math.random() * followups.length)];
6576            const wave = deck.querySelector('.wave');
6577            const insertBefore = wave || deck.querySelector('.deck-foot');
6578
6579            const lastTs = deck.querySelectorAll('.deck-row .ts');
6580            const baseSec = parseInt((lastTs[lastTs.length - 1]?.textContent || '00:14').split(':')[1]) + 6;
6581            const fmtTs = s => `00:${String(s).padStart(2, '0')}`;
6582
6583            const callerRow = document.createElement('div');
6584            callerRow.className = 'deck-row caller';
6585            callerRow.innerHTML = `<span class="ts">${fmtTs(baseSec)}</span><span class="who">Caller</span><span class="msg">${ex.caller}</span>`;
6586            deck.insertBefore(callerRow, insertBefore);
6587
6588            const typingRow = document.createElement('div');
6589            typingRow.className = 'deck-typing';
6590            typingRow.innerHTML = `<span class="ts">${fmtTs(baseSec + 2)}</span><span class="who">Talkify</span><span class="dotset"><i></i><i></i><i></i></span>`;
6591            deck.insertBefore(typingRow, insertBefore);
6592
6593            const agentRow = document.createElement('div');
6594            agentRow.className = 'deck-row agent';
6595            agentRow.innerHTML = `<span class="ts">${fmtTs(baseSec + 3)}</span><span class="who">Talkify</span><span class="msg">${ex.agent}</span>`;
6596            deck.insertBefore(agentRow, insertBefore);
6597
6598            requestAnimationFrame(() => callerRow.classList.add('in'));
6599            setTimeout(() => typingRow.classList.add('on'), 1100);
6600            setTimeout(() => typingRow.classList.remove('on'), 2400);
6601            setTimeout(() => agentRow.classList.add('in'), 2500);
6602        }
6603    })();
6604
6605    // ─── Real conversations, bubbles type into existence as user scrolls in ───
6606    (function () {
6607        document.querySelectorAll('.convo').forEach(convo => {
6608            const bubs = Array.from(convo.querySelectorAll('.bub'));
6609            if (!bubs.length) return;
6610
6611            let started = false;
6612            const start = () => {
6613                if (started) return;
6614                started = true;
6615
6616                let t = 200;
6617                bubs.forEach((bub) => {
6618                    // Show typing indicator with the same alignment + colour, then swap to bubble
6619                    const typing = document.createElement('div');
6620                    typing.className = 'convo-typing' + (bub.classList.contains('caller') ? ' caller' : '');
6621                    const who = bub.classList.contains('caller') ? 'Caller' : 'Talkify';
6622                    typing.innerHTML = `<span class="lbl">${who}</span><span class="dotset"><i></i><i></i><i></i></span>`;
6623                    convo.insertBefore(typing, bub);
6624
6625                    const typingMs = bub.classList.contains('caller') ? 500 : 800;
6626                    setTimeout(() => typing.classList.add('on'), t);
6627                    t += typingMs;
6628                    setTimeout(() => {
6629                        typing.classList.remove('on');
6630                        typing.remove();
6631                    }, t);
6632                    setTimeout(() => bub.classList.add('in'), t + 50);
6633                    t += 450; // settle time before next message
6634                });
6635            };
6636
6637            /* Watch the transcript's wrapper where it has one. On the home page
6638               the transcript sits inside a phone, and a clipped flex child that
6639               deep gets no intersection entries at all, so a threshold against
6640               the transcript itself never fires and the conversation never
6641               starts. The wrapper is an ordinary block in normal flow. */
6642            const target = convo.closest('.convo-device') || convo;
6643            const io = new IntersectionObserver(entries => {
6644                entries.forEach(e => {
6645                    if (e.isIntersecting) {
6646                        start();
6647                        io.unobserve(target);
6648                    }
6649                });
6650            }, {threshold: 0.2});
6651            io.observe(target);
6652        });
6653    })();
6654
6655    // ─── Live PA digest, notifications drop in on scroll, more arrive as you watch ───
6656    (function () {
6657        document.querySelectorAll('.pa-floater').forEach(floater => {
6658            const initialRows = Array.from(floater.querySelectorAll('.row'));
6659            if (!initialRows.length) return;
6660
6661            const queue = [
6662                {
6663                    lbl: 'Returning client · routed',
6664                    name: 'Liam, message taken for Tom',
6665                    meta: '<span class="vip" style="color:var(--mute)">● Routine</span>'
6666                },
6667                {
6668                    lbl: 'New booking',
6669                    name: 'Te Aroha · Saturday haircut',
6670                    meta: '<span class="vip" style="color:var(--signal)">● Booked</span>'
6671                },
6672                {
6673                    lbl: 'Urgent · escalated to mobile',
6674                    name: 'Maria @ Hartwell, sent to your phone',
6675                    meta: '<span class="vip" style="color:var(--coral)">● VIP</span>'
6676                },
6677                {lbl: 'Quietly handled', name: '14 vendors politely declined', meta: ''},
6678            ];
6679            let qIdx = 0;
6680            let started = false;
6681
6682            const start = () => {
6683                if (started) return;
6684                started = true;
6685                initialRows.forEach((row, i) => {
6686                    setTimeout(() => {
6687                        row.classList.add('in', 'ping');
6688                        setTimeout(() => row.classList.remove('ping'), 1400);
6689                    }, i * 1200 + 400);
6690                });
6691
6692                // After initial settle, push a new notification every 9 seconds
6693                const settled = initialRows.length * 1200 + 2000;
6694                setTimeout(() => {
6695                    const interval = setInterval(() => {
6696                        if (!floater.isConnected) {
6697                            clearInterval(interval);
6698                            return;
6699                        }
6700                        const item = queue[qIdx % queue.length];
6701                        qIdx++;
6702                        const newRow = document.createElement('div');
6703                        newRow.className = 'row in fresh ping';
6704                        newRow.innerHTML = `
6705            <span class="lbl">${item.lbl}</span>
6706            <span class="name">${item.name}</span>
6707            ${item.meta ? '<span>' + item.meta + '</span>' : ''}
6708          `;
6709                        floater.insertBefore(newRow, floater.firstChild);
6710
6711                        // Drop the oldest if we have too many, keep card from growing
6712                        const all = floater.querySelectorAll('.row');
6713                        if (all.length > 4) {
6714                            const oldest = all[all.length - 1];
6715                            oldest.style.transition = 'opacity .5s ease, transform .5s ease, max-height .5s ease, margin .5s ease, padding .5s ease';
6716                            oldest.style.opacity = '0';
6717                            oldest.style.transform = 'translateY(8px)';
6718                            setTimeout(() => oldest.remove(), 600);
6719                        }
6720
6721                        setTimeout(() => newRow.classList.remove('ping'), 1400);
6722                    }, 9000);
6723                }, settled);
6724            };
6725
6726            const io = new IntersectionObserver(entries => {
6727                entries.forEach(e => {
6728                    if (e.isIntersecting) {
6729                        start();
6730                        io.unobserve(floater);
6731                    }
6732                });
6733            }, {threshold: 0.3});
6734            io.observe(floater);
6735        });
6736    })();
6737
6738    // ─── Conversion + engagement events → GA4 / GTM dataLayer ───
6739    // Every tel: tap, CTA click and lead form submit lands in the dataLayer so
6740    // GTM/GA4 can build conversions without touching the templates again.
6741    (function () {
6742        const page = "blog";
6743        const push = (event, params) => {
6744            window.dataLayer = window.dataLayer || [];
6745            window.dataLayer.push(Object.assign({event: event, page_key: page}, params || {}));
6746        };
6747
6748        // Phone taps: the demo line and the sign-up lines are separate conversions.
6749        // The demo lines come from App\Services\Market (they differ by country
6750        // and by how a visitor has to dial them), matched on their last eight
6751        // digits so the local and the international form are the same line.
6752                const demoTails = ["32421262","92420020"];
6753        document.querySelectorAll('a[href^="tel:"]').forEach(a => {
6754            a.addEventListener('click', () => {
6755                const num = (a.getAttribute('href') || '').replace('tel:', '');
6756                const digits = num.replace(/\D/g, '');
6757                const isDemo = demoTails.some(t => t && digits.endsWith(t));
6758                push(isDemo ? 'demo_call_click' : 'phone_signup_click', {
6759                    phone_number: num,
6760                    link_text: (a.textContent || '').trim().slice(0, 80),
6761                });
6762            });
6763        });
6764
6765        // CTA buttons (primary/blue/ghost), which CTA, on which page
6766        document.querySelectorAll('a.btn').forEach(a => {
6767            a.addEventListener('click', () => {
6768                push('cta_click', {
6769                    cta_text: (a.textContent || '').trim().slice(0, 80),
6770                    cta_style: a.classList.contains('btn-primary') ? 'primary'
6771                        : a.classList.contains('btn-blue') ? 'blue' : 'ghost',
6772                    cta_href: a.getAttribute('href') || '',
6773                });
6774            });
6775        });
6776
6777        // Lead forms: signup/contact, live demo call, support
6778        document.querySelectorAll('form').forEach(form => {
6779            const action = form.getAttribute('action') || '';
6780            let event = null;
6781            if (action.includes('/signup/verify')) event = 'sign_up';
6782            else if (action.includes('/signup/send-code')) event = 'sign_up_start';
6783            else if (action.includes('/contact')) event = 'generate_lead';
6784            else if (action.includes('/demo')) event = 'demo_call_request';
6785            else if (action.includes('/support')) event = 'support_request';
6786            if (!event) return;
6787            form.addEventListener('submit', () => {
6788                const agent = form.querySelector('input[name="agent_type"]:checked');
6789                push(event, {
6790                    form_action: action,
6791                    agent_type: agent ? agent.value : undefined,
6792                });
6793            });
6794        });
6795    })();
6796
6797    /* Agents mega-menu. Desktop opens it on hover/focus via CSS; this handles
6798       the click path, which is the only way in on touch, plus Escape and
6799       click-outside. */
6800    (function () {
6801        const drops = document.querySelectorAll('[data-nav-drop]');
6802        if (!drops.length) return;
6803
6804        const closeAll = (except) => drops.forEach((drop) => {
6805            if (drop === except) return;
6806            drop.classList.remove('is-open');
6807            drop.querySelector('.nav-drop-btn')?.setAttribute('aria-expanded', 'false');
6808        });
6809
6810        drops.forEach((drop) => {
6811            const trigger = drop.querySelector('.nav-drop-btn');
6812            if (!trigger) return;
6813
6814            trigger.addEventListener('click', (event) => {
6815                event.preventDefault();
6816                event.stopPropagation();
6817                const open = drop.classList.toggle('is-open');
6818                trigger.setAttribute('aria-expanded', open ? 'true' : 'false');
6819                closeAll(drop);
6820            });
6821        });
6822
6823        document.addEventListener('click', (event) => {
6824            if (!event.target.closest('[data-nav-drop]')) closeAll();
6825        });
6826
6827        document.addEventListener('keydown', (event) => {
6828            if (event.key === 'Escape') closeAll();
6829        });
6830
6831        window.talkifyCloseNavDrops = closeAll;
6832    })();
6833
6834    (function () {
6835        const btn = document.querySelector('.menu-btn');
6836        const nav = document.querySelector('.nav ul');
6837        if (!btn || !nav) return;
6838        btn.addEventListener('click', () => {
6839            const open = nav.style.display === 'flex';
6840            // Collapsing the menu should not leave the Agents accordion open
6841            // behind it, or it reappears expanded next time.
6842            if (open && window.talkifyCloseNavDrops) window.talkifyCloseNavDrops();
6843            nav.style.display = open ? 'none' : 'flex';
6844            nav.style.position = 'fixed';
6845            nav.style.top = '92px';
6846            nav.style.left = '20px';
6847            nav.style.right = '20px';
6848            nav.style.flexDirection = 'column';
6849            nav.style.background = 'var(--ink-2)';
6850            nav.style.border = '1px solid var(--line)';
6851            nav.style.borderRadius = '14px';
6852            nav.style.padding = '12px';
6853            nav.style.zIndex = '85';
6854        });
6855    })();
6856
6857    /* Theme toggle, persist choice, flip data-theme on <html> */
6858    (function () {
6859        var toggles = document.querySelectorAll('[data-theme-toggle]');
6860        if (!toggles.length) return;
6861        toggles.forEach(function (btn) {
6862            btn.addEventListener('click', function () {
6863                var current = document.documentElement.getAttribute('data-theme') === 'light' ? 'light' : 'dark';
6864                var next = current === 'light' ? 'dark' : 'light';
6865                document.documentElement.setAttribute('data-theme', next);
6866                try {
6867                    localStorage.setItem('talkify-theme', next);
6868                } catch (e) {
6869                }
6870            });
6871        });
6872    })();
6873</script>
6873
6874
6875</body>
6876</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.