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>Talkify Pricing | Business AI Agents $129/mo · Personal Assistant $89/mo · No Lock-in</title> 29 <meta name="description" 30 content="Talkify AI phone agent pricing for NZ. Business agents (Broadcast) $129/month at the founding rate for your first 3 months, then $199. Personal Assistant for one person (Shortwave) $89/month. Website Chat $49/month. Custom setups with API integration from $499. No setup fee, no per-seat charges, no lock-in. Free demo, no card needed."> 31 32 33 <link rel="canonical" href="https://talkify.nz/pricing"> 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/pricing"> 44 <meta property="og:site_name" content="Talkify"> 45 <meta property="og:title" content="Talkify Pricing | Business AI Agents $129/mo · Personal Assistant $89/mo · No Lock-in"> 46 <meta property="og:description" 47 content="Talkify AI phone agent pricing for NZ. Business agents (Broadcast) $129/month at the founding rate for your first 3 months, then $199. Personal Assistant for one person (Shortwave) $89/month. Website Chat $49/month. Custom setups with API integration from $499. No setup fee, no per-seat charges, no lock-in. Free demo, no card needed."> 48 <meta property="og:image" content="https://talkify.nz/media/share/pricing.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="Talkify Pricing | Business AI Agents $129/mo · Personal Assistant $89/mo · No Lock-in"> 60 <meta name="twitter:description" 61 content="Talkify AI phone agent pricing for NZ. Business agents (Broadcast) $129/month at the founding rate for your first 3 months, then $199. Personal Assistant for one person (Shortwave) $89/month. Website Chat $49/month. Custom setups with API integration from $499. No setup fee, no per-seat charges, no lock-in. Free demo, no card needed."> 62 <meta name="twitter:image" content="https://talkify.nz/media/share/pricing.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="pricing"> 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="tkghbFwYU" 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(#tkghbFwYU)"/> 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">→</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 & 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 & beauty</span> 5273 <a href="https://talkify.nz/barber">Barbers</a> 5274 <a href="https://talkify.nz/beauty">Beauty & Wellness</a> 5275 <a href="https://talkify.nz/gym">Gyms & Studios</a> 5276 <a href="https://talkify.nz/personal-trainer">Personal Trainers</a> 5277 <a href="https://talkify.nz/physio">Physio & Clinics</a> 5278 <span class="nav-drop-hd" style="margin-top:18px">Office & 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 & 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 & Chip Shops</a> 5289 <a href="https://talkify.nz/hotel">Hotels & 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">→</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="is-active"><span class="dot"></span>Pricing</a></li> 5312 <li><a href="https://talkify.nz/blog" class=""><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:48px"> 5334 <div class="hero-bg"> 5335 <div class="glow1"></div> 5336 <div class="glow2"></div> 5337 <div class="grid-lines"></div> 5338 </div> 5339 5340 <div class="hero-shell"> 5341 <div> 5342 <div class="crumb"><a href="https://talkify.nz">Talkify</a> <span>/</span> <span 5343 style="color:var(--paper)">Pricing</span></div> 5344 <span class="eyebrow" style="margin-top:18px"><span class="pin"></span>Founding rates · No surprises · Cancel anytime</span> 5345 <h1 class="display" style="font-size:clamp(60px,9vw,128px);max-width:20ch"> 5346 <span class="ln"><span>One agent.</span></span> 5347 <span class="ln"><span class="it">Four ways to pay.</span></span> 5348 </h1> 5349 <p class="hero-sub" style="max-width:680px">From as little as 5350 $10 a month* plus 5351 $1 a minute on pay as you go, or a flat monthly plan with 5352 minutes included. No per-seat fees, no setup tax, no lock-in, and every plan keeps every 5353 transcript forever.</p> 5354 5355 <div class="founding-note">
5356 <span class="fn-tag">Founding rate</span> 5357 <span class="fn-txt">On the monthly plans, your <b>first 3 months</b> are locked in at 5358 the founding price below; standard pricing applies after that. Pay as you go has no 5359 founding step. No setup fee, cancel any 5360 time. Wondering how this stacks up? <a href="https://talkify.nz/compare" style="color:var(--brand-blue-bright);text-decoration:underline">See every NZ provider compared</a>, or read <a href="https://talkify.nz/ai-answering-service#cost" style="color:var(--brand-blue-bright);text-decoration:underline">what a phone answering service costs in NZ</a>.</span> 5361 </div> 5362 </div> 5363 5364 <div class="pricing-hero-figures r r-1"> 5365 <a class="ruled-figure" href="#tiers"> 5366 <span class="lbl">Pay as you go</span> 5367 <span class="big">$10<small> /mo*</small></span> 5368 <span class="fig-note">* Covers your phone number, plus $1 a minute as you use it. $10 free credit to start.</span> 5369 </a> 5370 <a class="ruled-figure" href="#tiers"> 5371 <span class="lbl">Personal Assistant</span> 5372 <span class="big">$89<small> /mo</small></span> 5373 <span class="fig-note">One person's own mobile or landline. 50 minutes.</span> 5374 </a> 5375 <a class="ruled-figure is-pick" href="#tiers"> 5376 <span class="lbl">Broadcast · most common</span> 5377 <span class="big">$129<small> /mo</small></span> 5378 <span class="fig-note">Your business number, answered. Up to 3 agents on it, 200 minutes, 3 calls at once.</span> 5379 </a> 5380 <a class="ruled-figure" href="https://talkify.nz/contact"> 5381 <span class="lbl">Fleet</span> 5382 <span class="big">Custom</span> 5383 <span class="fig-note">Multi-location and contact centres. Quoted per account.</span> 5384 </a> 5385 </div> 5386 </div> 5387 </section> 5388 5389 5390 <section class="shell tight" style="padding-top:0" id="service-map"> 5391 <div class="section-hd"> 5392 <h2 class="r">Which agent on <span class="it">which plan.</span></h2> 5393 <p class="lede r r-1">Priced by the phone number, not by the seat and not by the agent. Every number 5394 comes with up to three agents on it (reception, bookings, sales) and three simultaneous calls. 5395 Most businesses start with one number.</p> 5396 </div> 5397 5398 <div class="svc-band r"><span>Answering your phone.</span></div> 5399 5400 <div class="svc-plate r"> 5401 <div class="svc"> 5402 <div class="svc-head"> 5403 <span class="svc-name">Reception & Sales</span> 5404 <span class="svc-price"><s class="svc-was">$199</s>$129<small>/mo</small></span> 5405 </div> 5406 <p class="svc-founding">Founding rate for your first 3 months, then $199/mo.</p> <p class="svc-desc">24/7 reception for your business number plus inbound sales qualification with CRM 5407 sync, bundled on the Broadcast plan. One price per number, with up to three agents on it. 5408 The most common pick.</p> 5409 <p class="svc-aster">* Sales Agent is subject to your CRM. Non-standard CRMs may carry an 5410 implementation cost.</p> 5411 <div class="svc-tier">Broadcast · per number · 200 min a month</div> 5412 </div> 5413 5414 <div class="svc"> 5415 <div class="svc-head"> 5416 <span class="svc-name">Personal Assistant</span> 5417 <span class="svc-price">$89<small>/mo</small></span> 5418 </div> 5419 <p class="svc-desc">One person, one mobile or landline. Screens your calls, takes detailed messages and 5420 books your meetings. Personal use, not a business switchboard.</p> 5421 <div class="svc-tier">Shortwave · 50 min a month</div> 5422 </div> 5423 5424 <div class="svc"> 5425 <div class="svc-head">
5426 <span class="svc-name">AI Call Centre</span> 5427 <span class="svc-price"><small style="margin-right:4px">from</small>$399<small>/mo</small></span> 5428 </div> 5429 <p class="svc-desc">For phone volume: 5, 10 or 15 calls answered at the same instant, no queue and no 5430 hold music. $399, $599 or 5431 $799 a month. 5432 <a href="https://talkify.nz/ai-call-centre" class="svc-link">How it works</a>.</p> 5433 <div class="svc-tier">Answers and dials · by simultaneous lines</div> 5434 </div> 5435 5436 <div class="svc"> 5437 <div class="svc-head"> 5438 <span class="svc-name">Website Chat</span> 5439 <span class="svc-price">$49<small>/mo</small></span> 5440 </div> 5441 <p class="svc-desc">Your agent on your website: a white-labelled text and voice widget trained on the 5442 same knowledge as your phone agent. $39 alongside any 5443 Talkify agent. <a href="https://talkify.nz/website-chat" class="svc-link">See it in action</a>.</p> 5444 <div class="svc-tier">Per website</div> 5445 </div> 5446 </div> 5447 5448 <div class="svc-band r"><span>Making calls for you.</span></div> 5449 5450 <div class="svc-plate r"> 5451 <div class="svc"> 5452 <div class="svc-head"> 5453 <span class="svc-name">Outgoing campaigns</span> 5454 <span class="svc-price">$59<small>/mo</small></span> 5455 </div> 5456 <p class="svc-desc">Campaigns from a list you load: reminders, win-backs, follow-ups on quotes that went 5457 quiet. 20 minutes included each month you run a campaign, 5458 then 50c a minute. One-off calls your agent makes outside a campaign 5459 (booking confirmations, notifications) are just 50c a minute with no 5460 monthly fee. <a href="https://talkify.nz/outboun
5460d-calls" class="svc-link">How campaigns run</a>.</p> 5461 <div class="svc-tier">Per month, in months you campaign</div> 5462 </div> 5463 5464 5465 <div class="svc"> 5466 <div class="svc-head"> 5467 <span class="svc-name">AI Call Centre</span> 5468 <span class="svc-price"><small style="margin-right:4px">from</small>$399<small>/mo</small></span> 5469 </div> 5470 <p class="svc-desc">The same bank of lines, dialling out: 5, 10 or 15 calls running at once through a 5471 list instead of waiting on one. One subscription covers both directions, so lines sized for your 5472 busiest hour on the phone are yours for campaigns the rest of the day. 5473 50c a minute on top. 5474 <a href="https://talkify.nz/ai-call-centre" class="svc-link">How it works</a>.</p> 5475 <div class="svc-tier">Answers and dials · by simultaneous lines</div> 5476 </div> 5477 5478 <div class="svc"> 5479 <div class="svc-head"> 5480 <span class="svc-name">Invoice chase-up</span> 5481 <span class="svc-price">$10<small>/mo</small></span> 5482 </div> 5483 <p class="svc-desc">Connects your Xero, rings the overdue accounts politely, writes what they promised 5484 back onto the invoice and emails your accounts team anything that needs a person. 5485 50c a minute on top. <a href="https://talkify.nz/debt-collection" class="svc-link">What it says</a>.</p> 5486 <div class="svc-tier">Xero add-on</div> 5487 </div> 5488 5489 <div class="svc"> 5490 <div class="svc-head"> 5491 <span class="svc-name">Marketing Campaigns</span> 5492 <span class="svc-price">$59<small>/mo</small></span> 5493 </div> 5494 <p class="svc-desc">Rings your own customer base with promotions, win-backs, launches, review requests 5495 and phone surveys, and hands you the results as people, not statistics. Same plan as outgoing 5496 campaigns: 20 minutes included, then 5497 50c a minute. 5498 <a href="https://talkify.nz/ai-marketing-campaigns" class="svc-link">See the campaigns</a>.</p> 5499 <div class="svc-tier">Part of Outgoing campaigns</div> 5500 </div> 5501 5502 </div> 5503 5504 5505 <div class="svc-foot r"> 5506 <div> 5507 <h3>Custom Setup <span class="svc-foot-price">from $499</span></h3> 5508 <p>Custom API integration into your booking system, CRM or in-house software, built and maintained by 5509 us. Includes the integration work and a dedicated onboarding, on a 12-month contract. The quote 5510 depends on the systems involved.</p> 5511 </div> 5512 <a href="tel:+64800002967" class="btn btn-ghost">Talk to us on 0800 002 967 <span class="arr">→</span></a> 5513 </div> 5514 5515 <style> 5516 /* Same ruled-plate language as the industry index and the agent 5517 pages: one bordered plate per direction, cells ruled off each 5518 other by the 1px grid gap rather than floating as separate cards. */ 5519 .svc-band { 5520 display: flex; 5521 align-items: center; 5522 gap: 20px; 5523 margin: 0 0 20px 5524 } 5525 5526 .svc-plate + .svc-band { 5527 margin-top: 44px 5528 } 5529 5530 .svc-band span { 5531 font-weight:600; 5532 font-size: 19px; 5533 color: var(--mute); 5534 flex: 0 0 auto 5535 } 5536 5537 .svc-band::after { 5538 content: ""; 5539 flex: 1; 5540 height: 1px; 5541 background: var(--line) 5542 } 5543 5544 .svc-foot { 5545 display: flex; 5546 align-items: center; 5547 justify-content: space-between; 5548 flex-wrap: wrap; 5549 gap: 18px 36px; 5550 margin-top: 28px; 5551 padding: 0 4px 5552 } 5553 5554 .svc-foot > div { 5555 max-width: 68ch; 5556 display: flex; 5557 flex-direction: column; 5558 gap: 8px 5559 } 5560 5561 .svc-foot h3 { 5562 font-family: var(--serif); 5563 font-weight: 300; 5564 font-size: 24px; 5565 letter-spacing: -.015em; 5566 color: var(--paper); 5567 margin: 0; 5568 display: flex; 5569 align-items: baseline; 5570 gap: 12px; 5571 flex-wrap: wrap 5572 } 5573 5574 .svc-foot-price { 5575 font-family: var(--mono); 5576 font-size: 12px; 5577 letter-spacing: .06em; 5578 color: var(--mute) 5579 } 5580 5581 .svc-foot p { 5582 font-size: 14.5px; 5583 line-height: 1.6; 5584 color: var(--mute); 5585 margin: 0 5586 } 5587 5588 /* V2 design language, same as the capability plate: top-ruled 5589 columns rather than cells inside a filled, rounded plate. */ 5590 .svc-plate { 5591 display: grid; 5592 grid-template-columns:repeat(4, 1fr); 5593 gap: clamp(20px, 2.6vw, 36px) 5594 } 5595 5596 .svc { 5597 position: relative; 5598 border-top: 1px solid var(--line-2); 5599 padding: 28px 0 0; 5600 display: flex; 5601 flex-direction: column; 5602 gap: 12px; 5603 transition: background .35s var(--ease) 5604 } 5605 5606 .svc:hover { 5607 background: var(--ink-3) 5608 } 5609 5610 .svc::before { 5611 content: ""; 5612 position: absolute; 5613 top: 0; 5614 left: 0; 5615 right: 0; 5616 height: 2px; 5617 background: var(--grad); 5618 transform: scaleX(0); 5619 transform-origin: left; 5620 transition: transform .55s var(--ease-out) 5621 } 5622 5623 .svc:hover::before { 5624 transform: scaleX(1) 5625 } 5626 5627 .svc-head { 5628 display: flex; 5629 justify-content: space-between; 5630 align-items: baseline; 5631 gap: 14px; 5632 flex-wrap: wrap 5633 } 5634 5635 .svc-name { 5636 font-family: var(--serif); 5637 font-weight: 400; 5638 font-size: 21px; 5639 letter-spacing: -.012em; 5640 line-height: 1.14 5641 } 5642 5643 .svc-price { 5644 font-family: var(--mono); 5645 font-size: 19px; 5646 color: var(--paper); 5647 white-space: nowrap 5648 } 5649 5650 .svc-price small { 5651 font-size: 11px; 5652 color: var(--mute) 5653 } 5654 5655 .svc-was { 5656 color: var(--mute-2); 5657 margin-right: 6px; 5658 font-size: 14px 5659 } 5660
5661 .svc-founding { 5662 font-family: var(--mono); 5663 font-size: 10.5px; 5664 letter-spacing: .12em; 5665 text-transform: uppercase; 5666 color: var(--signal) 5667 } 5668 5669 .svc-desc { 5670 color: var(--bone); 5671 font-size: 13.5px; 5672 line-height: 1.58; 5673 flex: 1 5674 } 5675 5676 .svc-link { 5677 color: var(--plasma-bright); 5678 text-decoration: underline 5679 } 5680 5681 .svc-tier { 5682 font-family: var(--mono); 5683 font-size: 10.5px; 5684 letter-spacing: .14em; 5685 text-transform: uppercase; 5686 color: var(--mute); 5687 padding-top: 12px; 5688 border-top: 1px solid var(--line) 5689 } 5690 5691 .svc-aster { 5692 font-size: 11.5px; 5693 line-height: 1.5; 5694 color: var(--mute-2) 5695 } 5696 5697 @media (max-width: 1180px) { 5698 .svc-plate { 5699 grid-template-columns:repeat(2, 1fr) 5700 } 5701 } 5702 5703 @media (max-width: 620px) { 5704 .svc-plate { 5705 grid-template-columns:1fr 5706 } 5707 } 5708 5709 @media (prefers-reduced-motion: reduce) { 5710 .svc, .svc::before { 5711 transition: none 5712 } 5713 } 5714 </style> 5715 </section> 5716 5717 <section class="shell tight" style="padding-top:0" id="tiers"> 5718 <div class="section-hd"> 5719 <h2 class="r">Or pick by <span class="it">plan tier.</span></h2> 5720 <p class="lede r r-1">Same pricing, different lens. Useful if you already know what minutes and concurrency 5721 you need.</p> 5722 </div> 5723 5724 <style> 5725 /* The id outranks the layout's own .tiers rules, so every width 5726 is restated here rather than half-inherited. */ 5727 #tiers .tiers { grid-template-columns: repeat(4, 1fr); } 5728 @media (max-width: 1100px) { 5729 #tiers .tiers { grid-template-columns: repeat(2, 1fr); } 5730 } 5731 @media (max-width: 700px) { 5732 #tiers .tiers { grid-template-columns: 1fr; } 5733 } 5734 </style> 5735 <div class="tiers"> 5736 <div class="tier r"> 5737 <div class="row1"><span class="name">SHORTWAVE · PERSONAL</span></div> 5738 <div class="price">$89<small>/mo</small></div> 5739 <p class="desc">A personal assistant for one person's own mobile or landline. Personal use, not a 5740 business line, businesses start on Broadcast.</p> 5741 <ul> 5742 <li> 5743 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"> 5744 <path d="M5 12l5 5L20 7"/> 5745 </svg> 5746 50 minutes / month 5747 </li> 5748 <li> 5749 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"> 5750 <path d="M5 12l5 5L20 7"/> 5751 </svg> 5752 1 agent · 1 number 5753 </li> 5754 <li> 5755 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"> 5756 <path d="M5 12l5 5L20 7"/> 5757 </svg> 5758 Email + SMS summaries 5759 </li> 5760 <li> 5761 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"> 5762 <path d="M5 12l5 5L20 7"/> 5763 </svg> 5764 Calendar bookings 5765 </li> 5766 <li> 5767 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"> 5768 <path d="M5 12l5 5L20 7"/> 5769 </svg> 5770 Mobile app · iOS & Android 5771 </li> 5772 <li> 5773 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"> 5774 <path d="M5 12l5 5L20 7"/> 5775 </svg> 5776 Full transcripts & recordings 5777 </li> 5778 </ul> 5779 <a href="https://talkify.nz/contact?plan=shortwave" class="btn btn-ghost cta">Choose Shortwave <span 5780 class="arr">â</span></a> 5781 </div> 5782 <div class="tier featured r r-1"> 5783 <div class="row1"><span class="name">BROADCAST</span><span class="badge">Most popular</span></div> 5784 <div class="price"><s class="svc-was">$199</s>$129<small>/mo per number</small></div> 5785 <p class="tier-founding">Founding rate for your first 3 months, then $199/mo.</p> <p class="desc">Growing teams. The complete phone agent suite plus the mobile app, CRM sync and 5786 3 concurrent lines.</p> 5787 <ul> 5788 <li> 5789 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"> 5790 <path d="M5 12l5 5L20 7"/> 5791 </svg> 5792 Up to 3 agents on your number · $39/mo each after 5793 </li> 5794 <li> 5795 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"> 5796 <path d="M5 12l5 5L20 7"/> 5797 </svg> 5798 200 minutes + 50 texts / month 5799 </li> 5800 <li> 5801 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"> 5802 <path d="M5 12l5 5L20 7"/> 5803 </svg> 5804 Or <a href="#annual">$1,990 a year</a> and two months are free 5805 </li> 5806 <li> 5807 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"> 5808 <path d="M5 12l5 5L20 7"/> 5809 </svg> 5810 3 concurrent calls 5811 </li> 5812 <li> 5813 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"> 5814 <path d="M5 12l5 5L20 7"/> 5815 </svg> 5816 Mobile app · view your transcriptions 5817 </li> 5818 <li> 5819 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"> 5820 <path d="M5 12l5 5L20 7"/> 5821 </svg> 5822 CRM & calendar integrations 5823 </li> 5824 <li> 5825 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"> 5826 <path d="M5 12l5 5L20 7"/> 5827 </svg> 5828 Multi-lingual · 32 languages 5829 </li> 5830 <li> 5831 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"> 5832 <path d="M5 12l5 5L20 7"/> 5833 </svg> 5834 A dedicated NZ / Aus Phone Number 5835 </li> 5836 </ul> 5837 <a href="https://talkify.nz/contact?plan=broadcast" class="btn btn-primary cta">Start broadcasting <span 5838 class="arr">â</span></a> 5839 </div> 5840 <div class="tier r r-2"> 5841 <div class="row1"><span class="name">
5841PAY AS YOU GO</span></div> 5842 <div class="price">$1<small>/minute</small></div> 5843 <p class="desc">No monthly plan. A prepaid balance that calls and texts draw down, topped up 5844 automatically from your card. Start with $10 of free credit. Cancel anytime.</p> 5845 <ul> 5846 <li> 5847 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"> 5848 <path d="M5 12l5 5L20 7"/> 5849 </svg> 5850 $1/min incoming & outgoing 5851 </li> 5852 <li> 5853 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"> 5854 <path d="M5 12l5 5L20 7"/> 5855 </svg> 5856 $10 free credit to start 5857 </li> 5858 <li> 5859 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"> 5860 <path d="M5 12l5 5L20 7"/> 5861 </svg> 5862 $10/month covers your NZ or Aussie landline number 5863 </li> 5864 <li> 5865 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"> 5866 <path d="M5 12l5 5L20 7"/> 5867 </svg> 5868 Texts at 15c each, no allowances 5869 </li> 5870 <li> 5871 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"> 5872 <path d="M5 12l5 5L20 7"/> 5873 </svg> 5874 Tops up $20 at a time, automatically 5875 </li> 5876 </ul> 5877 <a href="https://talkify.nz/contact?plan=payg" class="btn btn-ghost cta">Go pay as you go <span 5878 class="arr">â</span></a> 5879 </div> 5880 <div class="tier r r-2"> 5881 <div class="row1"><span class="name">FLEET</span></div> 5882 <div class="price">Custom</div> 5883 <p class="desc">Multi-location operators, franchises and contact centres. SLA-backed, dedicated infra, 5884 custom voices and white-glove onboarding.</p> 5885 <ul> 5886 <li> 5887 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"> 5888 <path d="M5 12l5 5L20 7"/> 5889 </svg> 5890 Unlimited minutes 5891 </li> 5892 <li> 5893 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"> 5894 <path d="M5 12l5 5L20 7"/> 5895 </svg> 5896 Multi-tenant dashboard 5897 </li> 5898 <li> 5899 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"> 5900 <path d="M5 12l5 5L20 7"/> 5901 </svg> 5902 Dedicated voice clone 5903 </li> 5904 <li> 5905 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"> 5906 <path d="M5 12l5 5L20 7"/> 5907 </svg> 5908 Custom integrations · MCP tools 5909 </li> 5910 <li> 5911 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"> 5912 <path d="M5 12l5 5L20 7"/> 5913 </svg> 5914 99.95% SLA · NZ data residency 5915 </li> 5916 <li> 5917 <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"> 5918 <path d="M5 12l5 5L20 7"/> 5919 </svg> 5920 Dedicated success manager 5921 </li> 5922 </ul> 5923 <a href="https://talkify.nz/contact?plan=fleet" class="btn btn-ghost cta">Talk to the team <span 5924 class="arr">â</span></a> 5925 </div> 5926 </div> 5927 </section> 5928 5929 5930 <section class="shell tight" style="padding-top:0" id="annual"> 5931 <div class="annual-band"> 5932 <div class="annual-copy"> 5933 <h2 class="annual-h">Pay for the year and 2 months are free</h2> 5934 <p class="annual-lead">An annual licence for a Broadcast number is 5935 <b>$1,990 + GST</b>, paid once. The same 5936 number month by month comes to <b>$2,388</b>, 5937 so you keep <b>$398</b> and deal with 5938 one payment a year instead of twelve.</p> 5939 <p class="annual-note">Everything else is exactly the same. Your number still includes up to 5940 3 agents, 200 minutes and 5941 50 texts a month, and anything over that is charged at the 5942 usual rates in the month you use it. The allowance is monthly, not a pool you can spend 5943 early. If you are still on your founding rate, stay on it until it ends: it is cheaper than 5944 the licence and we will tell you so rather than sell you this.</p> 5945 <a href="https://talkify.nz/contact?plan=annual" class="btn btn-primary cta">Ask about an annual 5946 licence <span class="arr">â</span></a> 5947 </div> 5948 <div class="annual-figure">
5949 <span class="annual-was">$2,388</span> 5950 <span class="annual-now">$1,990</span> 5951 <span class="annual-unit">+ GST, per number, per year</span> 5952 </div> 5953 </div> 5954 <style> 5955 .annual-band { 5956 display: grid; 5957 grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr); 5958 gap: 2rem; 5959 align-items: center; 5960 padding: 2rem; 5961 border: 1px solid var(--rule, rgba(0, 0, 0, .12)); 5962 } 5963 .annual-h { margin: 0 0 .75rem; } 5964 .annual-lead { margin: 0 0 1rem; } 5965 .annual-note { margin: 0 0 1.5rem; font-size: .92rem; opacity: .78; } 5966 .annual-figure { text-align: right; } 5967 .annual-was { 5968 display: block; 5969 text-decoration: line-through; 5970 opacity: .55; 5971 font-size: 1.1rem; 5972 } 5973 .annual-now { 5974 display: block; 5975 font-size: clamp(2.4rem, 6vw, 3.4rem); 5976 font-weight: 800; 5977 line-height: 1.05; 5978 } 5979 .annual-unit { display: block; font-size: .85rem; opacity: .7; } 5980 @media (max-width: 760px) { 5981 .annual-band { grid-template-columns: 1fr; padding: 1.5rem; } 5982 .annual-figure { text-align: left; } 5983 } 5984 </style> 5985 </section> 5986 5987 <section class="shell tight" style="padding-top:0"> 5988 <div class="usage-strip r"> 5989 <div class="us-col"> 5990 <span class="us-h">Your minutes</span> 5991 <p>Shortwave includes 50 minutes a month, Broadcast 200 per number. Go over and extra minutes are just 5992 <b>10c</b> for your first 3 months, then 20c (Shortwave stays at 10c). Fleet is unlimited.</p> 5993 </div> 5994 <div class="us-col"> 5995 <span class="us-h">Your texts</span> 5996 <p>Every Broadcast number includes <b>50 texts</b> a month, and Shortwave includes 5997 <b>20</b>. After that it's a flat 5998 <b>9c</b> a message. Summaries, confirmations, follow-ups, all counted the same.</p> 5999 </div> 6000 <div class="us-col"> 6001 <span class="us-h">Outgoing calls</span> 6002 <p>Running campaigns (surveys, reminder rounds, win-backs) is <b>$59 a month</b> in the months 6003 you run them, with 20 minutes included, then 6004 <b>50c per minute</b> rounded up to the next minute. Ring more and it comes down: 6005 40c a minute from 200 calls a month, and 35c a minute from 500 calls a month, counted across all your campaigns and backdated over the whole 6006 month. One-off calls outside a campaign are just 50c a minute, no fee.</p> 6007 </div> 6008 <div class="us-col"> 6009 <span class="us-h">No bill shock</span> 6010 <p>We let you know as you near your allowance, so nothing creeps up on you. You are never charged 6011 for usage without warning, and there is no lock-in.</p> 6012 </div> 6013 </div> 6014 6015 <style> 6016 .usage-strip { 6017 display: grid; 6018 grid-template-columns:repeat(4, 1fr); 6019 gap: 18px 6020 } 6021 6022 @media (max-width: 1180px) { 6023 .usage-strip { 6024 grid-template-columns:repeat(2, 1fr) 6025 } 6026 } 6027 6028 .us-col { 6029 border-top: 1px solid var(--line-2); 6030 padding: 28px 0 0 6031 } 6032 6033 .us-h { 6034 font-family: var(--mono); 6035 font-size: 10px; 6036 letter-spacing: .16em; 6037 text-transform: uppercase; 6038 color: var(--signal); 6039 display: block; 6040 margin-bottom: 12px 6041 } 6042 6043 .us-col p { 6044 color: var(--bone); 6045 font-size: 14px; 6046 line-height: 1.6; 6047 margin: 0 6048 } 6049 6050 .us-col p b { 6051 color: var(--paper); 6052 font-weight: 600 6053 } 6054 6055 @media (max-width: 860px) { 6056 .usage-strip { 6057 grid-template-columns:1fr 6058 } 6059 } 6060 </style> 6061 </section> 6062 6063 <section class="shell tight" id="calculator"> 6064 <div class="section-hd"> 6065 <h2 class="r">Build it <span class="it">your way.</span></h2> 6066 <p class="lede r r-1">Slide for the number of agents you would run on your number (the plan includes up to 3), pick the integrations you'd connect, and see live what your monthly looks like. Most businesses start with one. No sign-up needed.</p> 6067 </div> 6068 6069 <div class="r calc-grid" data-calc-grid> 6070 <div class="calc-controls"> 6071 <div class="calc-row-head">
6072 <span class="eyebrow"><span class="pin"></span>How many agents</span> 6073 <span class="mono calc-row-val"><span data-calc-team>1</span> agents</span> 6074 </div> 6075 <input type="range" data-calc-range min="1" max="20" value="1" class="calc-range"> 6076 6077 <div class="calc-row-head" style="margin-top:32px"> 6078 <span class="eyebrow eb-blue"><span class="pin"></span>Integrations</span> 6079 <span class="mono calc-row-val"><span data-calc-ints>0</span> selected</span> 6080 </div> 6081 6082 <div data-calc-pills class="calc-pills"> 6083 <button type="button" class="int-pill" data-int="Google Calendar">Google Calendar</button> 6084 <button type="button" class="int-pill" data-int="Microsoft Outlook">Microsoft Outlook</button> 6085 <button type="button" class="int-pill" data-int="Calendly">Calendly</button> 6086 <button type="button" class="int-pill" data-int="Zenoti">Zenoti</button> 6087 <button type="button" class="int-pill" data-int="GymMaster">GymMaster</button> 6088 <button type="button" class="int-pill" data-int="Cliniko">Cliniko</button> 6089 <button type="button" class="int-pill" data-int="MechanicDesk">MechanicDesk</button> 6090 <button type="button" class="int-pill" data-int="Workshop Software">Workshop Software</button> 6091 <button type="button" class="int-pill" data-int="HubSpot">HubSpot</button> 6092 <button type="button" class="int-pill" data-int="GoHighLevel">GoHighLevel</button> 6093 <button type="button" class="int-pill" data-int="Pipedrive">Pipedrive</button> 6094 <button type="button" class="int-pill" data-int="Xero">Xero</button> 6095 <button type="button" class="int-pill" data-int="MYOB">MYOB</button> 6096 <button type="button" class="int-pill" data-int="Trello">Trello</button> 6097 <button type="button" class="int-pill" data-int="iTrade">iTrade</button> 6098 <button type="button" class="int-pill" data-int="Tradify">Tradify</button> 6099 <button type="button" class="int-pill" data-int="Slack">Slack</button> 6100 <button type="button" class="int-pill" data-int="Microsoft Teams">Microsoft Teams</button> 6101 <button type="button" class="int-pill" data-int="Zapier">Zapier</button> 6102 <button type="button" class="int-pill" data-int="REST API & webhooks">REST API & webhooks</button> 6103 <button type="button" class="int-pill" data-int="Custom MCP">Custom MCP</button> 6104 </div> 6105 </div> 6106 6107 <div class="calc-output"> 6108 <span class="eyebrow"><span class="pin"></span>Your plan</span> 6109 <div class="calc-founding" data-calc-founding > 6110 <s class="calc-was" data-calc-was>$199/mo</s> 6111 <span class="calc-ftag">Founding rate · 3 months</span> 6112 </div> 6113 <div class="calc-price-row"> 6114 <div class="calc-price-num" data-calc-price>$129</div> 6115 <div class="calc-price-suffix">/mo</div> 6116 </div> 6117 <div class="calc-stats"> 6118 <div><div class="mono calc-stat-label">Plan</div><div class="calc-stat-val" data-calc-plan>Broadcast</div></div> 6119 <div><div class="mono calc-stat-label">Minutes</div><div class="calc-stat-val" data-calc-mins>200/mo</div></div> 6120 <div><div class="mono calc-stat-label">At once</div><div class="calc-stat-val" data-calc-conc>3 calls</div></div> 6121 <div><div class="mono calc-stat-label">Numbers</div><div class="calc-stat-val" data-calc-num>1</div></div> 6122 </div> 6123 6124 <p data-calc-desc class="calc-desc">Broadcast fits most growing NZ businesses. One number carries up to 3 agents and three callers at once.</p> 6125 6126 <p data-calc-usage class="calc-usage">Includes 200 minutes a month, then 10c a minute (20c after your first 3 months). Each number includes 50 texts a month, then 9c each.</p> 6127 6128 6129 <p data-calc-extra class="calc-extra">Want more than 3 agents on one number? Extra agents are $39 a month each.</p> 6130 6131 <a href="https://talkify.nz/contact" class="btn btn-primary calc-cta">Start with this plan <span class="arr">â</span></a> 6132 </div> 6133 </div> 6134 6135 <style> 6136 /* V2 design language: the two halves are top-ruled columns, not boxed 6137 panels. This is the same shape as the /v2 missed-call calculator, which 6138 is a rule across the top and two columns under it, the controls on the 6139 left and the number on the right. */ 6140 .calc-grid{ 6141 display:grid;grid-template-columns:1.1fr 1fr; 6142 gap:clamp(28px,5vw,72px);align-items:start; 6143 margin-top:clamp(32px,4vw,52px); 6144 border-top:1px solid var(--line-2); 6145 padding-top:clamp(32px,4vw,56px) 6146 } 6147 .calc-controls{min-width:0} 6148 .calc-output{position:relative;min-width:0} 6149 6150 .calc-row-head{display:flex;justify-content:space-between;align-items:center;gap:12px;margin-bottom:14px;flex-wrap:wrap} 6151 .calc-row-val{font-size:13px;color:var(--bone)} 6152 6153 .calc-range{width:100%;-webkit-appearance:none;appearance:none;height:4px;background:linear-gradient(90deg,var(--brand-blue),var(--brand-green));border-radius:2px;outline:none;cursor:pointer;display:block} 6154 6155 /* The integration toggles were pills. They are still toggles, so they still 6156 need a hit area and an on state, but square corners and a hairline keep 6157 them in the ruled language instead of reading as tags. Selected is a 6158 filled block, which is the one place a fill earns its keep: it has to be 6159 unmistakable at a glance how many are on. */ 6160 .calc-pills{display:flex;flex-wrap:wrap;gap:8px;margin-top:10px} 6161 .int-pill{ 6162 padding:8px 13px;font-family:var(--mono);font-size:11px;letter-spacing:.08em; 6163 border:1px solid var(--line);border-radius:2px;background:none;color:var(--mute); 6164 transition:.25s var(--ease);cursor:pointer;max-width:100%;white-space:nowrap 6165 } 6166 .int-pill:hover{border-color:var(--line-2);color:var(--paper)} 6167 .int-pill.on{background:var(--signal);color:var(--ink);border-color:var(--signal)} 6168 6169 /* Price row */ 6170 .calc-price-row{margin-top:24px;display:flex;align-items:flex-end;
6170gap:8px;flex-wrap:wrap} 6171 .calc-price-num{ 6172 font-family:var(--serif);font-weight:300;line-height:.9;letter-spacing:-.04em; 6173 font-size:clamp(56px,10vw,96px); 6174 min-width:0; 6175 word-break:break-word; 6176 } 6177 .calc-price-suffix{font-family:var(--mono);font-size:12px;color:var(--mute);padding-bottom:clamp(8px,1.4vw,16px)} 6178 6179 /* Founding rate */ 6180 .calc-founding{margin-top:18px;display:flex;align-items:center;gap:10px;flex-wrap:wrap} 6181 .calc-was{font-family:var(--serif);font-weight:300;font-size:22px;color:var(--mute);text-decoration:line-through;text-decoration-color:var(--coral)} 6182 /* was a filled pill; a founding rate is a note, not a badge */ 6183 .calc-ftag{font-family:var(--mono);font-size:10px;letter-spacing:.14em;text-transform:uppercase;color:var(--signal)} 6184 .calc-usage{margin-top:14px;font-family:var(--sans);font-size:12.5px;line-height:1.55;color:var(--mute)} 6185 .calc-extra{margin-top:10px;padding-top:10px;border-top:1px solid var(--line);font-family:var(--sans);font-size:11.5px;line-height:1.5;color:var(--mute-2)} 6186 6187 /* Stat grid, ruled the way the V2 proof stats are: a hairline over each, 6188 the mono label under the figure rather than above it. */ 6189 .calc-stats{margin-top:30px;display:grid;grid-template-columns:1fr 1fr;gap:0 32px} 6190 .calc-stats > div{border-top:1px solid var(--line-2);padding:18px 0 20px;display:flex;flex-direction:column-reverse} 6191 .calc-stat-label{margin-top:8px;font-size:10px;color:var(--mute);text-transform:uppercase;letter-spacing:.16em} 6192 .calc-stat-val{font-family:var(--serif);font-size:clamp(18px,2.6vw,24px);font-weight:300;letter-spacing:-.02em;color:var(--paper);line-height:1.15;word-break:break-word;hyphens:auto} 6193 6194 .calc-desc{color:var(--bone);margin-top:24px;font-size:14px;line-height:1.6} 6195 .calc-cta{margin-top:24px} 6196 6197 /* Slider thumb */ 6198 [data-calc-range]::-webkit-slider-thumb{-webkit-appearance:none;width:22px;height:22px;border-radius:50%;background:var(--paper);border:3px solid var(--ink);cursor:pointer;box-shadow:0 0 12px color-mix(in srgb, var(--signal) 60%, transparent)} 6199 [data-calc-range]::-moz-range-thumb{width:22px;height:22px;border-radius:50%;background:var(--paper);border:3px solid var(--ink);cursor:pointer} 6200 6201 /* Tablet: stack the two cards */ 6202 @media (max-width:960px){ 6203 .calc-grid{grid-template-columns:1fr;gap:18px} 6204 } 6205 6206 /* Small phone: tighten the stat grid */ 6207 @media (max-width:480px){ 6208 .calc-stats{grid-template-columns:1fr 1fr;gap:12px} 6209 .calc-stat-val{font-size:17px} 6210 .calc-row-val{font-size:12px} 6211 .int-pill{padding:7px 11px;font-size:10.5px} 6212 } 6213 </style> 6214</section> 6215 6216 6217 <section class="shell tight"> 6218 <div class="section-hd"> 6219 <h2 class="r">Frequently <span class="it">asked.</span></h2> 6220 </div> 6221 <div class="r pricing-faq-grid"> 6222 <div style="border-top:1px solid var(--line-2);padding:26px 0 0"> 6223 <div 6224 style="font-family:var(--serif);font-weight:400;font-size:20px;letter-spacing:-.01em;line-height:1.2">Can I pay for a year instead of monthly?</div> 6225 <p style="margin-top:10px;color:var(--bone);font-size:14px;line-height:1.55">Yes. An annual licence for a Broadcast number is $1,990 + GST paid once, against $2,388 month by month, so 2 months are free. Nothing else changes: the number still includes up to 3 agents, 200 minutes and 50 texts a month, and anything over that is charged at the usual rate in the month you use it. The allowance is monthly rather than a pool for the whole year. If you are still on your founding rate, that is cheaper than the licence until it ends, and we will say so rather than sell you the licence.</p> 6226 </div> 6227 <div style="border-top:1px solid var(--line-2);padding:26px 0 0"> 6228 <div 6229 style="font-family:var(--serif);font-weight:400;font-size:20px;letter-spacing:-.01em;line-height:1.2">What happens if I run over my minute allowance?</div> 6230 <p style="margin-top:10px;color:var(--bone);font-size:14px;line-height:1.55">Each plan includes monthly minutes, 50 on Shortwave and 200 per number on Broadcast. If you go over, extra minutes on Broadcast are just 10c a minute for your first 3 months, then 20c, and on Shortwave a flat 10c a minute. Texts work the same way: a Broadcast number includes 50 a month and Shortwave includes 20, then 9c a message. We let you know as you near your allowance, so there are never any surprises.</p> 6231 </div> 6232 <div style="border-top:1px solid var(--line-2);padding:26px 0 0"> 6233 <div 6234 style="font-family:var(--serif);font-weight:400;font-size:20px;letter-spacing:-.01em;line-height:1.2">How many agents can I have on one number?</div> 6235 <p style="margin-top:10px;color:var(--bone);font-size:14px;line-height:1.55">Up to 3 agents are included in the one Broadcast price: a reception agent, a bookings agent and a sales agent can all share your number and hand callers between themselves. Agents beyond that are $39 a month each. A second phone number is simply a second plan.</p> 6236 </div> 6237 <div style="border-top:1px solid var(--line-2);padding:26px 0 0"> 6238 <div 6239 style="font-family:var(--serif);font-weight:400;font-size:20px;letter-spacing:-.01em;line-height:1.2">Why is the price crossed out?</div> 6240 <p style="margin-top:10px;color:var(--bone);font-size:14px;line-height:1.55">Every new account locks in our founding rate for its first 3 months: $129/mo for business agents on Broadcast (then $199). After that the standard rate applies, and there is no setup fee and no lock-in either way.</p> 6241 </div> 6242 <div style="border-top:1px solid var(--line-2);padding:26px 0 0"> 6243 <div 6244 style="font-family:var(--serif);font-weight:400;font-size:20px;letter-spacing:-.01em;line-height:1.2">What's the difference between the Personal Assistant and a business agent?</div> 6245 <p style="margin-top:10px;color:var(--bone);font-size:14px;line-height:1.55">
6245The Personal Assistant (Shortwave, $89/mo) answers one person's own mobile or landline: it screens your calls, takes messages and books your meetings. Any AI agent answering for a business (reception, sales, bookings on a business number) runs on Broadcast at $129/mo.</p> 6246 </div> 6247 <div style="border-top:1px solid var(--line-2);padding:26px 0 0"> 6248 <div 6249 style="font-family:var(--serif);font-weight:400;font-size:20px;letter-spacing:-.01em;line-height:1.2">Do I keep my existing phone number?</div> 6250 <p style="margin-top:10px;color:var(--bone);font-size:14px;line-height:1.55">Yes, Talkify works via call forwarding. Forward when you can't answer, or 24/7. Reversible any time, no porting.</p> 6251 </div> 6252 <div style="border-top:1px solid var(--line-2);padding:26px 0 0"> 6253 <div 6254 style="font-family:var(--serif);font-weight:400;font-size:20px;letter-spacing:-.01em;line-height:1.2">Can I clone my voice?</div> 6255 <p style="margin-top:10px;color:var(--bone);font-size:14px;line-height:1.55">On the Broadcast and Fleet plans. We use ElevenLabs voice cloning, you record about three minutes of script and the agent talks like you.</p> 6256 </div> 6257 <div style="border-top:1px solid var(--line-2);padding:26px 0 0"> 6258 <div 6259 style="font-family:var(--serif);font-weight:400;font-size:20px;letter-spacing:-.01em;line-height:1.2">Where is my data stored?</div> 6260 <p style="margin-top:10px;color:var(--bone);font-size:14px;line-height:1.55">Audio, transcripts, and call metadata are stored in NZ. AES-256 at rest. Detailed compliance docs available on request.</p> 6261 </div> 6262 <div style="border-top:1px solid var(--line-2);padding:26px 0 0"> 6263 <div 6264 style="font-family:var(--serif);font-weight:400;font-size:20px;letter-spacing:-.01em;line-height:1.2">Can I edit the agent's prompt?</div> 6265 <p style="margin-top:10px;color:var(--bone);font-size:14px;line-height:1.55">Yes, the dashboard has a live prompt editor. Tweak wording, escalation rules, opening hours, anything. Changes go live in seconds.</p> 6266 </div> 6267 <div style="border-top:1px solid var(--line-2);padding:26px 0 0"> 6268 <div 6269 style="font-family:var(--serif);font-weight:400;font-size:20px;letter-spacing:-.01em;line-height:1.2">Is there a setup fee?</div> 6270 <p style="margin-top:10px;color:var(--bone);font-size:14px;line-height:1.55">No. Onboarding is included, and there's no lock-in. You can switch the agent off any time and keep every transcript.</p> 6271 </div> 6272 </div> 6273 </section> 6274 6275 <section class="shell" id="app"> 6276 <div class="app r"> 6277 <div class="app-l"> 6278 <span class="app-tag">Now shipping · iOS & Android</span> 6279 <h2>Carry your <span class="it">control deck</span> in your pocket.</h2> 6280 <p>The Talkify mobile app puts the dashboard, transcripts and live coaching in your hand. Listen back to any 6281 call, edit your agent's prompt mid-shift, get push-notified the moment a hot lead lands.</p> 6282 6283 <div class="app-stores" style="--app-badge-h: 56px"> 6284 <a class="app-badge" href="https://apps.apple.com/nz/app/talkify-mobile/id6766709308" 6285 target="_blank" rel="noopener"> 6286 <img src="https://talkify.nz/media/branding/apple-app-store.svg" 6287 alt="Download Talkify Mobile on the App Store" 6288 width="167.5" height="56" loading="lazy"> 6289 </a> 6290 <a class="app-badge" href="https://play.google.com/store/apps/details?id=com.talkifynz.app" 6291 target="_blank" rel="noopener"> 6292 <img src="https://talkify.nz/media/branding/google-app-store.svg" 6293 alt="Get Talkify Mobile on Google Play" 6294 width="189" height="56" loading="lazy"> 6295 </a> 6296</div> 6297 </div> 6298 6299 <div class="app-r"> 6300 <div class="phone-frame app-phone"> 6301 <div class="phone-screen"> 6302 <div class="stat-row"><span>9:41</span><span>5G â â</span></div> 6303 <div class="ph-h">Today<br><span class="it">128 calls.</span></div> 6304 <div class="ph-card">
6305 <span class="lbl">Latest · 11:20am</span> 6306 <span class="name">Booked · Sarah H.</span> 6307 <span class="meta"><i>â Reception</i> · 00:42</span> 6308 </div> 6309 <div class="ph-card" style="margin-top:8px"> 6310 <span class="lbl">Live now · 1 line</span> 6311 <div class="wave" style="height:14px;margin-top:4px"> 6312 <i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i><i></i></div> 6313 </div> 6314 <div class="ph-card" style="margin-top:8px"> 6315 <span class="lbl">Sentiment</span> 6316 <div class="ph-bar"><span class="b on"></span><span class="b on"></span><span 6317 class="b on"></span><span class="b on"></span><span class="b"></span></div> 6318 </div> 6319 <div class="ph-cta" style="background:var(--signal);color:var(--on-accent)">Open dashboard</div> 6320 </div> 6321 </div> 6322 </div> 6323 </div> 6324</section> 6325 <section class="endcta endcta-has-form" id="endcta"> 6326 <div class="endcta-photo" aria-hidden="true"></div> 6327 6328 6329 <div class="endcta-wrap" id="signup"> 6330 <div class="endcta-pitch"> 6331 <div class="stamp">TWO WAYS TO HEAR THE AGENT</div> 6332 <h2>Don't read about it.<br><span class="it">Talk to it.</span></h2> 6333 6334 <div class="endcta-numbers"> 6335 <a href="tel:+6432421262" class="num-big" data-talkify-agent="default" 6336 title="Hear the agent yourself"> 6337 <span class="ic ic-demo"> 6338 <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" 6339 stroke-linecap="round"><path 6340 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> 6341 </span> 6342 <span> 6343 <small>Hear it yourself · our AI agent, 24/7 · ask it anything</small> 6344 03 242 1262 6345 </span> 6346 </a> 6347 6348 <a href="tel:+64800002967" class="num-big num-blue" title="Sign up, sales and support"> 6349 <span class="ic ic-signup"> 6350 <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" 6351 stroke-linecap="round"><path 6352 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> 6353 </span> 6354 <span> 6355 <small>Sign up, sales & support · we'll set you up</small> 6356 0800 002 967 6357 </span> 6358 </a> 6359 </div> 6360 6361 <div class="endcta-meta"> 6362 <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> 6363 6364 6365 <div class="endcta-alt"> 6366 <a href="sms:+64272048827" class="btn btn-ghost btn-lg" 6367 title="Text us instead of ringing"> 6368 <svg width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" 6369 stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" style="flex:none"> 6370 <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"/> 6371 </svg> 6372 Text our agent · 027 204 8827 </a> 6373 </div> 6374 6375 6376 </div> 6377 6378 <div class="endcta-form"> 6379 6380 <span class="eyebrow"><span class="pin"></span>Get your first agent · No card needed </span> 6381 6382 <form method="POST" action="https://talkify.nz/contact" class="form"> 6383 <input type="hidden" name="_token" value="wcvUGyANOcL4HP8hrR8UbmGCzMFo0lavIDvlw1XJ" autocomplete="off"> <div class="row"> 6384 <div class="field"> 6385 <label>Your name</label> 6386 <input type="text" name="name" required placeholder="Your full name" autocomplete="name" value=""> 6387 </div> 6388 <div class="field"> 6389 <label>Company</label> 6390 <input type="text" name="company" required placeholder="Your company" autocomplete="organization" value=""> 6391 </div> 6392 </div> 6393 <div class="row"> 6394 <div class="field"> 6395 <label>Email</label> 6396 <input type="email" name="email" required placeholder="Your email" autocomplete="email" value=""> 6397 </div> 6398 <div class="field"> 6399 <label>Mobile (NZ)</label> 6400 <input type="tel" name="phone" required placeholder="Your mobile" autocomplete="tel" value=""> 6401 </div> 6402 </div> 6403 <div class="field"> 6404 <label for="country-signup">Country</label> 6405 <select name="country" id="country-signup" required data-country-select autocomplete="country"> 6406 <option value="" disabled selected>Select your country</option> 6407 <option value="NZ" >New Zealand</option> 6408 <option value="AU" >Australia</option> 6409 </select> 6410 <p style="margin-top:8px;font-family:var(--mono);font-size:11px;letter-spacing:.04em;color:var(--mute)"> 6411 Talkify is currently available to businesses in New Zealand & Australia only. 6412 </p> 6413</div> 6414 6415 6416<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"> 6417 <input type="text" name="company_reference" tabindex="-1" autocomplete="off" value="" aria-hidden="true"> 6418</div> 6419
6420<script> 6421(function () { 6422 var script = document.currentScript; 6423 var form = script && script.closest('form'); 6424 if (!form) return; 6425 var select = form.querySelector('select[name="country"]'); 6426 if (!select || select.value) return; // respect old() / a choice already made 6427 6428 try { 6429 var tz = (Intl.DateTimeFormat().resolvedOptions().timeZone || '').toLowerCase(); 6430 var lang = (navigator.language || '').toLowerCase(); 6431 var code = null; 6432 6433 if (tz.indexOf('auckland') >= 0 || tz.indexOf('chatham') >= 0 || lang === 'en-nz' || lang === 'mi') { 6434 code = 'NZ'; 6435 } else if (tz.indexOf('australia/') >= 0 || lang === 'en-au') { 6436 code = 'AU'; 6437 } 6438 6439 if (code) select.value = code; 6440 } catch (e) { /* detection is best-effort */ } 6441})(); 6442</script>
6442 6443 <div class="field"> 6444 <label>Pick your agent</label> 6445 <div class="radios"> 6446 <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> 6447 <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> 6448 <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> 6449 <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> 6450 <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> 6451 <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> 6452 <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> 6453 </div> 6454 <p class="plan-recommend" data-plan-recommend style="display:none"> 6455 We recommend running an incoming agent alongside an outgoing or campaign agent. People you ring will often ring you 6456 back, and an incoming agent makes sure those return calls are answered rather than missed. If you would 6457 rather not add one, we can clone your business caller ID so return calls come straight back to your 6458 existing phone. 6459 </p> 6460 </div> 6461 6462 <div class="field"> 6463 <label>How you want to pay</label> 6464 <div class="radios"> 6465 <label class="radio"> 6466 <input type="radio" name="plan" value="broadcast" checked> 6467 <span class="dot"></span> 6468 <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> 6469 </label> 6470 <label class="radio"> 6471 <input type="radio" name="plan" value="payg" > 6472 <span class="dot"></span> 6473 <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> 6474 </label> 6475 </div> 6476 </div> 6477 6478 <div class="plan-display" data-plan-display> 6479 <div class="plan-display-left"> 6480 <div class="plan-display-label" data-plan-label>Personal Assistant</div> 6481 <div class="plan-display-sub" data-plan-sub>Single mobile or landline. Built for one person, not a business.</div> 6482 </div> 6483 <div class="plan-display-right"> 6484 <div class="plan-display-price" data-plan-price>$89<small>/mo</small></div> 6485 <div class="plan-display-tier" data-plan-tier>Shortwave plan</div> 6486 <div class="plan-display-note" data-plan-note style="display:none" ></div> 6487 </div> 6488 </div> 6489 <p class="founding-line">
6490 <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. 6491 Plans include 50 to 200 minutes a month, then 10c a minute. The first 20 texts each month are free, then 9c each. 6492 </p> 6493 <p class="plan-asterisk" data-plan-asterisk style="display:none"> 6494 <span>*</span> Subject to your CRM or booking system. Additional implementation cost may apply for non-standard integrations. 6495 </p> 6496 6497 <div class="actions"> 6498 <span class="note">â Your data stays in NZ.</span> 6499 <button type="submit" class="btn btn-primary btn-lg">Create your first agent <span class="arr">â</span></button> 6500 </div> 6501 </form> 6502 6503
6503<script> 6504 (function () { 6505 // A plan only carries a crossed-out "was" price and a founding note while 6506 // its intro price is genuinely below its standard price; when the two 6507 // match in the pricing table both come through blank and the picker 6508 // shows a plain price. Per-call plans never have a founding step. 6509 const PA_NOTE = ""; 6510 const BIZ_NOTE = "Founding rate for your first 3 months, then $199/mo"; 6511 const PA_WAS = ""; 6512 const BIZ_WAS = "$199"; 6513 6514 const PLANS = { 6515 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 }, 6516 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 }, 6517 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 }, 6518 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 }, 6519 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 }, 6520 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 }, 6521 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 }, 6522 }; 6523 // The pay-as-you-go face of the same picker: whatever agent they chose, 6524 // the money side is the per-minute wallet, so the price panel follows 6525 // the payment choice rather than quoting a monthly plan. 6526 const PAYG = { 6527 price: '$1', 6528 suffix: '/min', 6529 tier: 'Pay as you go · $10/month covers your phone number', 6530 note: '$10 free credit to start, on top of the number. Calls and texts come off your prepaid balance.', 6531 }; 6532 const form = document.currentScript.closest('.endcta-form') || document; 6533 const radios = form.querySelectorAll('input[name="agent_type"]'); 6534 const payRadios = form.querySelectorAll('input[name="plan"]'); 6535 const labelEl = form.querySelector('[data-plan-label]'); 6536 const subEl = form.querySelector('[data-plan-sub]'); 6537 const priceEl = form.querySelector('[data-plan-price]'); 6538 const tierEl = form.querySelector('[data-plan-tier]'); 6539 const noteEl = form.querySelector('[data-plan-note]'); 6540 const astEl = form.querySelector('[data-plan-asterisk]'); 6541 const recEl = form.querySelector('[data-plan-rec
6541ommend]'); 6542 6543 function update(){ 6544 const checked = form.querySelector('input[name="agent_type"]:checked'); 6545 if (!checked) return; 6546 const plan = PLANS[checked.value]; 6547 if (!plan) return; 6548 const pay = form.querySelector('input[name="plan"]:checked'); 6549 const payg = pay && pay.value === 'payg'; 6550 labelEl.textContent = plan.label; 6551 subEl.textContent = plan.sub; 6552 priceEl.innerHTML = payg 6553 ? PAYG.price + '<small>' + PAYG.suffix + '</small>' 6554 : (plan.was ? '<s class="was-price">'+plan.was+'</s> ' : '') + plan.price + (plan.suffix ? '<small>'+plan.suffix+'</small>' : ''); 6555 tierEl.textContent = payg ? PAYG.tier : plan.tier; 6556 if (noteEl) { 6557 const note = payg ? PAYG.note : (plan.note || ''); 6558 noteEl.textContent = note; 6559 noteEl.style.display = note ? 'block' : 'none'; 6560 } 6561 astEl.style.display = (!payg && plan.asterisk) ? 'block' : 'none'; 6562 if (recEl) recEl.style.display = plan.recommend ? 'block' : 'none'; 6563 } 6564 radios.forEach(r => r.addEventListener('change', update)); 6565 payRadios.forEach(r => r.addEventListener('change', update)); 6566 update(); 6567 })(); 6568 </script>
6568 6569 </div> 6570 </div> 6571 6572 <style> 6573 /* Two top-ruled columns rather than two pills side by side. The pair is 6574 held to a readable measure and centred under the headline, so the 6575 block still reads as the close of the page even though the section 6576 itself is centred and these two are ruled and left-aligned. */ 6577 .endcta-numbers { 6578 display: grid; 6579 grid-template-columns: 1fr 1fr; 6580 gap: clamp(24px, 4vw, 56px); 6581 margin: 56px auto 0; 6582 max-width: 780px; 6583 text-align: left 6584 } 6585 6586 @media (max-width: 800px) { 6587 .endcta-numbers { 6588 grid-template-columns: 1fr; 6589 gap: 30px; 6590 max-width: 460px 6591 } 6592 } 6593 6594 .endcta-alt { 6595 margin-top: 36px; 6596 display: flex; 6597 flex-wrap: wrap; 6598 gap: 12px; 6599 justify-content: center 6600 } 6601 6602 /* The app line sits under the two ways to reach us and quieter than 6603 either, because it is aimed at people who have already signed up. */ 6604 .endcta-app-line { 6605 margin-top: 40px; 6606 font-family: var(--mono); 6607 font-size: 10px; 6608 letter-spacing: .18em; 6609 text-transform: uppercase; 6610 color: var(--mute) 6611 } 6612 6613 .endcta .app-stores { 6614 margin-top: 14px; 6615 justify-content: center 6616 } 6617 6618 /* ââ With the form in it âââââââââââââââââââââââââââââââââââââââââââ 6619 The pitch stops being a centred banner and becomes the left half 6620 of one closing block, with the get-started form on the right. No 6621 panel and no rounding: the two columns simply share the page. */ 6622 .endcta-has-form .endcta-wrap { 6623 display: grid; 6624 grid-template-columns: 1fr 1.05fr; 6625 gap: clamp(40px, 5vw, 76px); 6626 align-items: start; 6627 max-width: 1240px; 6628 margin: 0 auto; 6629 text-align: left 6630 } 6631 6632 /* The skyline sits behind a short centred banner comfortably. Behind 6633 a block three times as tall it runs up under the form fields and 6634 the price panel, where a photograph is just noise, so it is held 6635 well back and the scrim is carried the whole way down instead of 6636 fading out in the middle. */ 6637 .endcta.endcta-has-form .endcta-photo { 6638 opacity: .12; 6639 background-position: center bottom 6640 } 6641 6642 html[data-theme="light"] .endcta.endcta-has-form .endcta-photo { 6643 opacity: .16 6644 } 6645 6646 .endcta.endcta-has-form .endcta-photo::after { 6647 background: linear-gradient(180deg, var(--scrim-mid) 0%, var(--scrim-strong) 30%, var(--scrim-strong) 100%) 6648 } 6649 6650 .endcta-has-form .endcta-numbers { 6651 grid-template-columns: 1fr; 6652 gap: 26px; 6653 margin: 44px 0 0; 6654 max-width: none 6655 } 6656 6657 .endcta-has-form .endcta-meta { 6658 justify-content: flex-start; 6659 gap: 22px 6660 } 6661 6662 .endcta-has-form .endcta-alt, 6663 .endcta-has-form .app-stores { 6664 justify-content: flex-start 6665 } 6666 6667 .endcta-form .eyebrow { 6668 display: inline-flex; 6669 margin-bottom: 20px 6670 } 6671 6672 @media (max-width: 1000px) { 6673 .endcta-has-form .endcta-wrap { 6674 grid-template-columns: 1fr; 6675 gap: 48px 6676 } 6677 6678 .endcta-has-form .endcta-numbers { 6679 max-width: 460px 6680 } 6681 } 6682 6683 /* Carried over from the signup section this block absorbed: that 6684 partial's styles only ship on the page that includes it, and it 6685 is now only included by /v2. */ 6686 .signup-errors { 6687 margin-bottom: 18px; 6688 padding: 14px 0 14px 16px; 6689 border-left: 2px solid var(--coral); 6690 font-family: var(--mono); 6691 font-size: 12px; 6692 line-height: 1.6; 6693 color: var(--paper) 6694 } 6695 6696 .was-price { 6697 font-size: .55em; 6698 color: var(--mute-2); 6699 text-decoration: line-through; 6700 text-decoration-color: var(--coral); 6701 margin-right: 4px; 6702 font-weight: 300 6703 } 6704 6705 .founding-line { 6706 margin-top: 14px; 6707 font-family: var(--sans); 6708 font-size: 12px; 6709 line-height: 1.55; 6710 color: var(--mute) 6711 } 6712 6713 .founding-line .fl-tag { 6714 font-family: var(--mono); 6715 font-size: 10px; 6716 letter-spacing: .14em; 6717 text-transform: uppercase; 6718 color: var(--signal); 6719 margin-right: 8px 6720 } 6721 </style> 6722 </section> 6723 6724 <style> 6725 /* The prices in the hero's right column. Uses the shared 6726 .ruled-figure vocabulary, so they read the same as every other price 6727 block on the site. */ 6728 .pricing-hero-figures { 6729 display: flex; 6730 flex-direction: column; 6731 gap: clamp(18px, 2.4vw, 30px) 6732 } 6733 6734 .pricing-hero-figures .ruled-figure { 6735 display: block; 6736 text-decoration: none; 6737 padding-top: clamp(18px, 2vw, 26px); 6738 transition: border-color .3s var(--ease) 6739 } 6740 6741 .pricing-hero-figures .ruled-figure:hover { 6742 border-top-color: var(--signal) 6743 } 6744 6745 .pricing-hero-figures .big { 6746 margin-top: 8px; 6747 font-size: clamp(38px, 3.6vw, 52px) 6748 } 6749 6750 .pricing-hero-figures .fig-note { 6751 display: block; 6752 margin-top: 8px; 6753 color: var(--bone); 6754 font-size: 13px; 6755 line-height: 1.5 6756 } 6757 6758 @media (max-width: 1000px) { 6759 .pricing-hero-figures { 6760 flex-direction: row; 6761 flex-wrap: wrap 6762 } 6763 6764 .pricing-hero-figures .ruled-figure { 6765 flex: 1 1 220px 6766 } 6767 } 6768
6769 .pricing-faq-grid { 6770 display: grid; 6771 grid-template-columns:repeat(2, 1fr); 6772 gap: clamp(24px, 3vw, 44px) 6773 } 6774 6775 @media (max-width: 760px) { 6776 .pricing-faq-grid { 6777 grid-template-columns:1fr 6778 } 6779 } 6780 </style> 6781 6782 6783<style> 6784 .foot-social { 6785 display: inline-flex; 6786 align-items: center; 6787 gap: 8px; 6788 padding: 6px 0; 6789 font-family: var(--mono); 6790 font-size: 11px; 6791 color: var(--mute); 6792 letter-spacing: .06em; 6793 transition: color .25s var(--ease); 6794 } 6795 6796 .foot-social:hover { color: var(--paper); } 6797 6798 /* The badges sit tighter than the marketing rows and wrap rather than 6799 squeeze, because this column is the narrowest place they appear. */ 6800 .foot-apps { 6801 margin-top: 22px; 6802 gap: 10px; 6803 } 6804</style> 6805<footer class="foot"> 6806 <div class="foot-grid"> 6807 <div class="foot-brand"> 6808 6809 <a class="logo" href="https://talkify.nz" aria-label="Talkify, home" 6810 style="display:flex;align-items:center;gap:14px;color:inherit;text-decoration:none"> 6811 <svg class="tk-logo" viewBox="-3 -3 317.81 106" 6812 width="125.92" height="42" 6813 xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Talkify" focusable="false"> 6814 <circle cx="50" cy="50" r="50" fill="var(--tk-word, #101820)"/> 6815 6816 <g fill="none" stroke="var(--tk-ground, #ffffff)" stroke-width="10" stroke-linecap="round"> 6817 <path d="M34 26 V54 C34 74 62 80 76 62"/> 6818 <path d="M20 40 H46"/> 6819 </g> 6820 6821 <g transform="translate(56 20) scale(0.30)"> 6822 <g class="tk-eye"> 6823 <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)"/> 6824 </g> 6825 </g> 6826 <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"/> 6827 6828 <g transform="translate(231.30 6.84) scale(0.216)"> 6829 <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" 6830 fill="var(--tk-word, #101820)"/> 6831 </g> 6832 </svg> 6833 </a> 6834 <p>The voice operating system for New Zealand business. Built in Aotearoa, hosted in Aotearoa, working while 6835 you don't.</p> 6836 <div 6837 style="margin-top:20px;font-family:var(--mono);font-size:12px;color:var(--mute);letter-spacing:.06em;line-height:1.7">
6838 <span style="color:var(--mute);font-size:10px;text-transform:uppercase;letter-spacing:.18em">Sign up by phone</span><br> 6839 <a href="tel:+64800002967" style="color:var(--bone);transition:.25s">0800 002 967</a><br> 6840 <span 6841 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> 6842 <a href="tel:+6432421262" data-talkify-agent="default" style="color:var(--bone);transition:.25s">03 242 1262</a> 6843 <br> 6844 <span 6845 style="color:var(--mute);font-size:10px;text-transform:uppercase;letter-spacing:.18em;margin-top:8px;display:inline-block">Text our agent</span><br> 6846 <a href="sms:+64272048827" style="color:var(--bone);transition:.25s">027 204 8827</a> 6847 </div> 6848 <div style="margin-top:20px;display:flex;flex-wrap:wrap;gap:8px 22px;align-items:center"> 6849 <a href="https://www.facebook.com/profile.php?id=61572226258048" target="_blank" 6850 rel="noopener noreferrer" aria-label="Facebook" 6851 class="foot-social"> 6852 <svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor"> 6853 <path 6854 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"/> 6855 </svg> 6856 Facebook 6857 </a> 6858 <a href="https://www.instagram.com/talkifynz/" target="_blank" 6859 rel="noopener noreferrer" aria-label="Instagram" 6860 class="foot-social"> 6861 <svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor"> 6862 <path 6863 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"/> 6864 </svg> 6865 Instagram 6866 </a> 6867 <a href="https://www.linkedin.com/company/talkify-nz/" target="_blank" 6868 rel="noopener noreferrer" aria-label="LinkedIn" 6869 class="foot-social"> 6870 <svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor"> 6871 <path 6872 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"/> 6873 </svg> 6874 LinkedIn 6875 </a> 6876 </div> 6877 6878 6879 <div class="app-stores foot-apps" style="--app-badge-h: 38px"> 6880 <a class="app-badge" href="https://apps.apple.com/nz/app/talkify-mobile/id6766709308" 6881 target="_blank" rel="noopener"> 6882 <img src="https://talkify.nz/media/branding/apple-app-store.svg" 6883 alt="Download Talkify Mobile on the App Store" 6884 width="113.7" height="38" loading="lazy"> 6885 </a> 6886 <a class="app-badge" href="https://play.google.com/store/apps/details?id=com.talkifynz.app" 6887 target="_blank" rel="noopener"> 6888 <img src="https://talkify.nz/media/branding/google-app-store.svg" 6889 alt="Get Talkify Mobile on Google Play" 6890 width="128.3" height="38" loading="lazy"> 6891 </a> 6892</div> 6893 </div> 6894 <div> 6895 <h4>Agents</h4> 6896 <ul> 6897 <li><a href="https://talkify.nz/reception">Reception</a></li> 6898 <li><a href="https://talkify.nz/personal-assistant">Personal Assistant</a></li> 6899 <li><a href="https://talkify.nz/booking-service">Booking Service</a></li> 6900 <li><a href="https://talkify.nz/sales-agent">Sales Agent</a></li> 6901 <li><a href="https://talkify.nz/ai-phone-surveys">Campaign Agent</a></li> 6902 <li><a href="https://talkify.nz/debt-collection">Debt Collection</a></li> 6903 <li><a href="https://talkify.nz/ai-wellness-checks">Wellness Checks</a></li> 6904 <li>
6904<a href="https://talkify.nz/outbound-calls">Outbound Calls</a></li> 6905 <li><a href="https://talkify.nz/ai-marketing-campaigns">Marketing Campaigns</a></li> 6906 <li><a href="https://talkify.nz/website-chat">Website Chat</a></li> 6907 <li><a href="https://talkify.nz/calendar">Team Calendar</a></li> 6908 <li><a href="https://talkify.nz/dialler">Dialler</a></li> 6909 <li><a href="https://talkify.nz/agents">All agents →</a></li> 6910 </ul> 6911 </div> 6912 6913 <div> 6914 <h4>Trades</h4> 6915 <ul> 6916 <li><a href="https://talkify.nz/plumber">Plumbing</a></li> 6917 <li><a href="https://talkify.nz/electrician">Electricians</a></li> 6918 <li><a href="https://talkify.nz/builder">Builders</a></li> 6919 <li><a href="https://talkify.nz/hvac">Heat Pump & HVAC</a></li> 6920 <li><a href="https://talkify.nz/automotive">Mechanics & Workshops</a></li> 6921 <li><a href="https://talkify.nz/landscaping">Landscaping</a></li> 6922 <li><a href="https://talkify.nz/pest-control">Pest Control</a></li> 6923 <li><a href="https://talkify.nz/tradesman">All Trades</a></li> 6924 </ul> 6925 </div> 6926 <div> 6927 <h4>Industries</h4> 6928 <ul> 6929 <li><a href="https://talkify.nz/beauty">Beauty & Wellness</a></li> 6930 <li><a href="https://talkify.nz/real-estate">Real Estate</a></li> 6931 <li><a href="https://talkify.nz/retail">Retail</a></li> 6932 <li><a href="https://talkify.nz/professional-services">Professional Services</a></li> 6933 <li><a href="https://talkify.nz/barber">Barbers</a></li> 6934 <li><a href="https://talkify.nz/gym">Gyms & Studios</a></li> 6935 <li><a href="https://talkify.nz/personal-trainer">Personal Trainers</a></li> 6936 <li><a href="https://talkify.nz/hotel">Hotels & Motels</a></li> 6937 <li><a href="https://talkify.nz/accountant">Accountants</a></li> 6938 <li><a href="https://talkify.nz/industries">All industries →</a></li> 6939 </ul> 6940 </div> 6941 <div> 6942 6943 <h4>Call answering</h4> 6944 <ul> 6945 <li><a href="https://talkify.nz">AI receptionist NZ</a></li> 6946 <li><a href="https://talkify.nz/ai-phone-agent">AI phone agent NZ</a></li> 6947 <li><a href="https://talkify.nz/virtual-receptionist">Virtual receptionist NZ</a></li> 6948 <li><a href="https://talkify.nz/ai-answering-service">AI answering service NZ</a></li> 6949 <li><a href="https://talkify.nz/after-hours-answering">After hours answering NZ</a></li> 6950 <li><a href="https://talkify.nz/on-call-roster">On-Call Roster</a></li> 6951 <li><a href="https://talkify.nz/ai-call-centre">AI Call Centre Agents</a></li> 6952 <li><a href="https://talkify.nz/business-phone-lines">Business Phone Lines</a></li> 6953 6954 <li style="margin-top:6px;color:var(--mute);line-height:1.8"> 6955 By city: 6956 <a 6957 href="https://talkify.nz/ai-receptionist-auckland">Auckland</a><span 6958 style="color:var(--line-2)"> · </span><a 6959 href="https://talkify.nz/ai-receptionist-wellington">Wellington</a><span 6960 style="color:var(--line-2)"> · </span><a 6961 href="https://talkify.nz/ai-receptionist-christchurch">Christchurch</a><span 6962 style="color:var(--line-2)"> · </span><a 6963 href="https://talkify.nz/ai-receptionist-hamilton">Hamilton</a><span 6964 style="color:var(--line-2)"> · </span><a 6965 href="https://talkify.nz/ai-receptionist-tauranga">Tauranga</a><span 6966 style="color:var(--line-2)"> · </span><a 6967 href="https://talkify.nz/ai-receptionist-dunedin">Dunedin</a> </li> 6968 </ul> 6969 </div> 6970 <div> 6971 6972 <h4>Company</h4> 6973 <ul> 6974 <li><a href="https://talkify.nz/pricing">Pricing</a></li> 6975 <li><a href="https://talkify.nz/integrations">Integrations</a></li> 6976 6977 <li><a href="https://talkify.nz/compare">Compare Providers</a><span 6978 style="color:var(--line-2)"> · </span><a 6979 href="https://talkify.nz/alternatives">Alternatives</a></li> 6980 <li><a href="https://talkify.nz/missed-call-calculator">Missed Call Calculator</a></li> 6981 <li><a href="https://talkify.nz/blog">Journal</a></li> 6982 6983 <li><a href="https://talkify.nz/help">Help centre</a><span 6984 style="color:var(--line-2)"> · </span><a 6985 href="https://talkify.nz/contact-us">Contact us</a></li> 6986 <li><a href="https://talkify.nz/demo">Live demo</a></li> 6987 <li><a href="https://talkify.nz/signup">Get started</a></li> 6988 </ul> 6989 </div> 6990 </div> 6991 <div class="foot-bot">
6992 <span>© <span id="year">2026</span> · Talkify Limited · NZ owned and hosted</span> 6993 <span> 6994 6995 <span aria-current="page">New Zealand</span> · <a href="https://talkify.nz/au" style="color:var(--bone)">Australia</a> · 6996 <a href="https://talkify.nz/privacy" style="color:var(--bone)">Privacy</a> · 6997 <a href="https://talkify.nz/terms" style="color:var(--bone)">Terms</a> · 6998 <a href="https://talkify.nz/support" style="color:var(--bone)">Support</a> · 6999 <a href="https://talkify.nz/login" style="color:var(--bone)">Sign in</a> 7000 · <a href="https://d3v.nz" style="color:var(--bone)">Made by D3V</a> 7001 </span> 7002 </div> 7003</footer> 7004 7005 7006 7007 7008 7009 7010 7011 7012 7013
7014<script> 7015 function tick() { 7016 const d = new Date(); 7017 const f = new Intl.DateTimeFormat('en-NZ', { 7018 timeZone: 'Pacific/Auckland', 7019 hour: '2-digit', 7020 minute: '2-digit', 7021 second: '2-digit', 7022 hour12: false 7023 }); 7024 const el = document.getElementById('clock'); 7025 if (el) el.textContent = f.format(d); 7026 } 7027 7028 tick(); 7029 setInterval(tick, 1000); 7030 const yEl = document.getElementById('year'); 7031 if (yEl) yEl.textContent = new Date().getFullYear(); 7032 7033 /* Scroll reveal. Fires once per block. Anybody who has asked for less 7034 motion, and any browser without IntersectionObserver, gets the lot 7035 revealed immediately rather than a page of invisible sections. */ 7036 (function () { 7037 const blocks = document.querySelectorAll('.r'); 7038 if (!blocks.length) return; 7039 const reduce = window.matchMedia 7040 && window.matchMedia('(prefers-reduced-motion: reduce)').matches; 7041 if (reduce || !('IntersectionObserver' in window)) { 7042 blocks.forEach(el => el.classList.add('in')); 7043 return; 7044 } 7045 const io = new IntersectionObserver((entries) => { 7046 entries.forEach(e => { 7047 if (e.isIntersecting) { 7048 e.target.classList.add('in'); 7049 io.unobserve(e.target); 7050 } 7051 }); 7052 }, {rootMargin: '-8% 0px -5% 0px'}); 7053 blocks.forEach(el => io.observe(el)); 7054 })(); 7055 7056 /* Agent phones. Each opens on a plain lock screen, then the clock drops to 7057 its compact size and the notifications land on top of it, which is the 7058 order an iPhone does it in. Plays once, when the panel is on screen. 7059 7060 The clock is the VISITOR'S OWN time and every stamp is counted back from 7061 it, so a screen can never show a notification that arrived after the time 7062 printed above it. Nothing is written into the markup, so a cached page 7063 cannot go stale either. 7064 7065 The tilt and the sheen are a couple of degrees and a highlight eased 7066 across the viewport. Both are off on coarse pointers, where there is no 7067 hover to reward them and the scroll handler is pure cost, and the whole 7068 thing collapses to "already arrived" under prefers-reduced-motion. */ 7069 (function () { 7070 const phones = [...document.querySelectorAll('[data-agent-phone]')]; 7071 if (!phones.length) return; 7072 7073 const clockOf = d => d.toLocaleTimeString('en-NZ', {hour: 'numeric', minute: '2-digit', hour12: false}); 7074 const stampOf = d => d.toLocaleTimeString('en-NZ', {hour: 'numeric', minute: '2-digit', hour12: true}) 7075 .replace(/\s/g, '').toLowerCase(); 7076 const dateOf = d => d.toLocaleDateString('en-NZ', {weekday: 'long', day: 'numeric', month: 'long'}); 7077 7078 const still = matchMedia('(prefers-reduced-motion: reduce)').matches; 7079 const coarse = matchMedia('(pointer: coarse)').matches; 7080 7081 phones.forEach(phone => { 7082 // A phone may pin its own clock with data-agent-at="HH:MM". The 7083 // after-hours story is an escalation at a quarter to midnight, and 7084 // stamped 2pm on a daytime visitor's own clock it reads as 7085 // nonsense. Everything else still shows the visitor's real time, 7086 // counted back from, so nothing arrives after the clock above it. 7087 const now = new Date(); 7088 const pinned = (phone.dataset.agentAt || '').match(/^(\d{1,2}):(\d{2})$/); 7089 if (pinned) now.setHours(+pinned[1], +pinned[2], 0, 0); 7090 7091 const t = phone.querySelector('[data-agent-time]'); 7092 const dt = phone.querySelector('[data-agent-date]'); 7093 if (t) t.textContent = clockOf(now); 7094 if (dt) dt.textContent = dateOf(now); 7095 7096 phone.querySelectorAll('[data-agent-ago]').forEach(el => { 7097 const mins = parseInt(el.dataset.agentAgo, 10); 7098 if (!Number.isFinite(mins)) return; 7099 el.textContent = stampOf(new Date(now.getTime() - mins * 60000)); 7100 }); 7101 7102 const clock = phone.querySelector('[data-agent-clock]'); 7103 const notes = [...phone.querySelectorAll('.hpn')]; 7104 if (!clock || !notes.length) return; 7105 7106 if (still) { 7107 clock.classList.add('is-compact');
7108 notes.forEach(n => n.classList.add('is-in')); 7109 return; 7110 } 7111 7112 let played = false; 7113 const play = () => { 7114 if (played) return; 7115 played = true; 7116 setTimeout(() => clock.classList.add('is-compact'), 420); 7117 notes.forEach((n, i) => setTimeout(() => n.classList.add('is-in'), 780 + i * 380)); 7118 }; 7119 7120 const io = new IntersectionObserver(entries => { 7121 entries.forEach(e => { 7122 if (!e.isIntersecting) return; 7123 play(); 7124 io.unobserve(phone); 7125 }); 7126 }, {threshold: .35}); 7127 io.observe(phone); 7128 7129 if (coarse) return; 7130 7131 const lean = phone.classList.contains('agent-phone--left') ? -1 : 1; 7132 let queued = false; 7133 const tilt = () => { 7134 queued = false; 7135 const r = phone.getBoundingClientRect(); 7136 if (r.bottom < 0 || r.top > innerHeight) return; 7137 // -0.5 above the fold, +0.5 below it 7138 const p = (r.top + r.height / 2 - innerHeight / 2) / innerHeight; 7139 phone.style.setProperty('--ag-tilt', (lean * (3 - p * 4.5)).toFixed(2) + 'deg'); 7140 phone.style.setProperty('--ag-sheen', (p * -150).toFixed(1) + '%'); 7141 }; 7142 addEventListener('scroll', () => { 7143 if (queued) return; 7144 queued = true; 7145 requestAnimationFrame(tilt); 7146 }, {passive: true}); 7147 tilt(); 7148 }); 7149 })(); 7150 7151 7152 /* Hero phone. The chips are the data source, so the markup stays the one 7153 place the copy lives. Cycling pauses the moment the visitor takes over, 7154 and never starts at all under prefers-reduced-motion. */ 7155 (function () { 7156 const root = document.querySelector('[data-hp-stack]'); 7157 if (!root) return; 7158 const chips = [...document.querySelectorAll('[data-hp-chip]')]; 7159 if (!chips.length) return; 7160 7161 const reduce = window.matchMedia('(prefers-reduced-motion: reduce)').matches; 7162 const icon = document.querySelector('.hpn header img'); 7163 const iconSrc = icon ? icon.getAttribute('src') : ''; 7164 let i = 0, timer = null, taken = false; 7165 7166 // the phone shows the viewer's own clock, so it reads as their phone 7167 // rather than a screenshot taken at some other time 7168 const clock = () => { 7169 const now = new Date(); 7170 const t = document.querySelector('[data-hp-time]'); 7171 const d = document.querySelector('[data-hp-date]'); 7172 if (t) t.textContent = now.toLocaleTimeString('en-NZ', {hour: 'numeric', minute: '2-digit'}) 7173 .replace(/\s?(am|pm)$/i, ''); 7174 if (d) d.textContent = now.toLocaleDateString('en-NZ', {weekday: 'long', day: 'numeric', month: 'long'}); 7175 }; 7176 7177 const AGO = ['now', '2m ago', '8m ago']; 7178 7179 const build = (chip) => { 7180 const frag = document.createDocumentFragment(); 7181 // two or three per screen: one card at a time made the phone look 7182 // idle, and a digest is the thing being sold 7183 [['title', 'body'], ['title2', 'body2'], ['title3', 'body3']].forEach((keys, i) => { 7184 const title = chip.dataset[keys[0]], body = chip.dataset[keys[1]]; 7185 if (!title) return; 7186 const n = document.createElement('article'); 7187 n.className = 'hpn'; 7188 n.style.transitionDelay = (i * 620) + 'ms'; 7189 n.innerHTML = 7190 '<header><img src="' + iconSrc + '" alt="" width="18" height="18">' + 7191 '<span class="hpn-app">Talkify</span><span class="hpn-ago"></span></header>' + 7192 '<h4></h4><p></p>'; 7193 n.querySelector('.hpn-ago').textContent = AGO[i] || 'earlier'; 7194 n.querySelector('h4').textContent = title; 7195 n.querySelector('p').textContent = body; 7196 frag.appendChild(n); 7197 }); 7198 return frag; 7199 }; 7200 7201 const show = (idx) => { 7202 i = (idx + chips.length) % chips.length; 7203 chips.forEach((c, n) => c.classList.toggle('is-on', n === i)); 7204 chips.forEach((c, n) => c.setAttribute('aria-selected', n === i ? 'true' : 'false')); 7205 root.replaceChildren(build(chips[i])); 7206 // let the browser paint the start state before transitioning in 7207 requestAnimationFrame(() => requestAnimationFrame(() => 7208 root.querySelectorAll('.hpn').forEach(n => n.classList.add('is-in')))); 7209 }; 7210 7211 const stop = () => { if (timer) { clearInterval(timer); timer = null; } }; 7212 const start = () => { if (!reduce && !taken && !timer) timer = setInterval(() => show(i + 1), 7000); }; 7213 7214 chips.forEach((chip, n) => { 7215 const take = () => { taken = true; stop(); show(n); }; 7216 chip.addEventListener('click', take); 7217 chip.addEventListener('mouseenter', () => { stop(); show(n); }); 7218 chip.addEventListener('mouseleave', () => { if (!taken) start(); }); 7219 }); 7220 7221 // do not animate a phone nobody is looking at 7222 const vis = new IntersectionObserver((es) => {
7223 es.forEach(e => e.isIntersecting ? start() : stop()); 7224 }, {threshold: 0.2}); 7225 vis.observe(root); 7226 7227 clock(); 7228 setInterval(clock, 30000); 7229 show(0); 7230 })(); 7231 7232 (function () { 7233 const hero = document.querySelector('.hero-bg'); 7234 if (!hero) return; 7235 // Pointer parallax is a mouse affordance: a finger cannot hover, and 7236 // it is exactly the sort of movement prefers-reduced-motion is for. 7237 const mq = (q) => window.matchMedia && window.matchMedia(q).matches; 7238 if (mq('(prefers-reduced-motion: reduce)') || mq('(pointer: coarse)')) return; 7239 7240 let x = 0, y = 0, queued = false; 7241 const paint = () => { 7242 queued = false; 7243 hero.style.transform = `translate(${x}px,${y}px)`; 7244 }; 7245 document.addEventListener('mousemove', (e) => { 7246 x = (e.clientX / window.innerWidth - .5) * 24; 7247 y = (e.clientY / window.innerHeight - .5) * 24; 7248 if (!queued) { 7249 queued = true; 7250 requestAnimationFrame(paint); 7251 } 7252 }, {passive: true}); 7253 })(); 7254 7255 // âââ Live call deck, messages animate in as if the call is happening now âââ 7256 (function () { 7257 document.querySelectorAll('.deck').forEach(deck => { 7258 const rows = Array.from(deck.querySelectorAll('.deck-row')); 7259 if (!rows.length) return; 7260 7261 // Insert a typing indicator before each agent row 7262 rows.forEach(row => { 7263 if (row.classList.contains('agent')) { 7264 const ts = row.querySelector('.ts')?.textContent || ''; 7265 const typing = document.createElement('div'); 7266 typing.className = 'deck-typing'; 7267 typing.innerHTML = `<span class="ts">${ts}</span><span class="who">Talkify</span><span class="dotset"><i></i><i></i><i></i></span>`; 7268 row.parentNode.insertBefore(typing, row); 7269 } 7270 }); 7271 7272 let started = false; 7273 const start = () => { 7274 if (started) return; 7275 started = true; 7276 let t = 400; 7277 rows.forEach(row => { 7278 if (row.classList.contains('agent')) { 7279 const typing = row.previousElementSibling; 7280 if (typing && typing.classList.contains('deck-typing')) { 7281 setTimeout(() => typing.classList.add('on'), t); 7282 t += 900; 7283 setTimeout(() => typing.classList.remove('on'), t); 7284 t += 200; 7285 } 7286 } 7287 setTimeout(() => row.classList.add('in'), t); 7288 t += 1200; 7289 }); 7290 7291 // After the prepared script plays, optionally append a follow-up exchange 7292 const followup = deck.dataset.followup; 7293 if (followup === 'on') { 7294 setTimeout(() => { 7295 appendDeckExchange(deck); 7296 }, t + 1500); 7297 } 7298 }; 7299 7300 const io = new IntersectionObserver(entries => { 7301 entries.forEach(e => { 7302 if (e.isIntersecting) { 7303 start(); 7304 io.unobserve(deck); 7305 } 7306 }); 7307 }, {threshold: 0.25}); 7308 io.observe(deck); 7309 }); 7310 7311 function appendDeckExchange(deck) { 7312 // Append one extra caller + agent exchange to the home hero deck 7313 const followups = [ 7314 { 7315 caller: "One more thing, can my partner come too?", 7316 agent: "Of course. I'll add them to the appointment. Anything else?" 7317 }, 7318 { 7319 caller: "Is there parking?", 7320 agent: "Yep, two-hour free parking on Vivian Street, or paid building parking off the lobby." 7321 }, 7322 ]; 7323 const ex = followups[Math.floor(Math.random() * followups.length)]; 7324 const wave = deck.querySelector('.wave'); 7325 const insertBefore = wave || deck.querySelector('.deck-foot'); 7326 7327 const lastTs = deck.querySelectorAll('.deck-row .ts'); 7328 const baseSec = parseInt((lastTs[lastTs.length - 1]?.textContent || '00:14').split(':')[1]) + 6; 7329 const fmtTs = s => `00:${String(s).padStart(2, '0')}`; 7330 7331 const callerRow = document.createElement('div'); 7332 callerRow.className = 'deck-row caller'; 7333 callerRow.innerHTML = `<span class="ts">${fmtTs(baseSec)}</span><span class="who">Caller</span><span class="msg">${ex.caller}</span>`;
7334 deck.insertBefore(callerRow, insertBefore); 7335 7336 const typingRow = document.createElement('div'); 7337 typingRow.className = 'deck-typing'; 7338 typingRow.innerHTML = `<span class="ts">${fmtTs(baseSec + 2)}</span><span class="who">Talkify</span><span class="dotset"><i></i><i></i><i></i></span>`; 7339 deck.insertBefore(typingRow, insertBefore); 7340 7341 const agentRow = document.createElement('div'); 7342 agentRow.className = 'deck-row agent'; 7343 agentRow.innerHTML = `<span class="ts">${fmtTs(baseSec + 3)}</span><span class="who">Talkify</span><span class="msg">${ex.agent}</span>`; 7344 deck.insertBefore(agentRow, insertBefore); 7345 7346 requestAnimationFrame(() => callerRow.classList.add('in')); 7347 setTimeout(() => typingRow.classList.add('on'), 1100); 7348 setTimeout(() => typingRow.classList.remove('on'), 2400); 7349 setTimeout(() => agentRow.classList.add('in'), 2500); 7350 } 7351 })(); 7352 7353 // âââ Real conversations, bubbles type into existence as user scrolls in âââ 7354 (function () { 7355 document.querySelectorAll('.convo').forEach(convo => { 7356 const bubs = Array.from(convo.querySelectorAll('.bub')); 7357 if (!bubs.length) return; 7358 7359 let started = false; 7360 const start = () => { 7361 if (started) return; 7362 started = true; 7363 7364 let t = 200; 7365 bubs.forEach((bub) => { 7366 // Show typing indicator with the same alignment + colour, then swap to bubble 7367 const typing = document.createElement('div'); 7368 typing.className = 'convo-typing' + (bub.classList.contains('caller') ? ' caller' : ''); 7369 const who = bub.classList.contains('caller') ? 'Caller' : 'Talkify'; 7370 typing.innerHTML = `<span class="lbl">${who}</span><span class="dotset"><i></i><i></i><i></i></span>`; 7371 convo.insertBefore(typing, bub); 7372 7373 const typingMs = bub.classList.contains('caller') ? 500 : 800; 7374 setTimeout(() => typing.classList.add('on'), t); 7375 t += typingMs; 7376 setTimeout(() => { 7377 typing.classList.remove('on'); 7378 typing.remove(); 7379 }, t); 7380 setTimeout(() => bub.classList.add('in'), t + 50); 7381 t += 450; // settle time before next message 7382 }); 7383 }; 7384 7385 /* Watch the transcript's wrapper where it has one. On the home page 7386 the transcript sits inside a phone, and a clipped flex child that 7387 deep gets no intersection entries at all, so a threshold against 7388 the transcript itself never fires and the conversation never 7389 starts. The wrapper is an ordinary block in normal flow. */ 7390 const target = convo.closest('.convo-device') || convo; 7391 const io = new IntersectionObserver(entries => { 7392 entries.forEach(e => { 7393 if (e.isIntersecting) { 7394 start(); 7395 io.unobserve(target); 7396 } 7397 }); 7398 }, {threshold: 0.2}); 7399 io.observe(target); 7400 }); 7401 })(); 7402 7403 // âââ Live PA digest, notifications drop in on scroll, more arrive as you watch âââ 7404 (function () { 7405 document.querySelectorAll('.pa-floater').forEach(floater => { 7406 const initialRows = Array.from(floater.querySelectorAll('.row')); 7407 if (!initialRows.length) return; 7408 7409 const queue = [ 7410 { 7411 lbl: 'Returning client · routed', 7412 name: 'Liam, message taken for Tom', 7413 meta: '<span class="vip" style="color:var(--mute)">â Routine</span>' 7414 }, 7415 { 7416 lbl: 'New booking', 7417 name: 'Te Aroha · Saturday haircut', 7418 meta: '<span class="vip" style="color:var(--signal)">â Booked</span>' 7419 }, 7420 { 7421 lbl: 'Urgent · escalated to mobile', 7422 name: 'Maria @ Hartwell, sent to your phone', 7423 meta: '<span class="vip" style="color:var(--coral)">â VIP</span>' 7424 }, 7425 {lbl: 'Quietly handled', name: '14 vendors politely declined', meta: ''}, 7426 ]; 7427 let qIdx = 0; 7428 let started = false;
7429 7430 const start = () => { 7431 if (started) return; 7432 started = true; 7433 initialRows.forEach((row, i) => { 7434 setTimeout(() => { 7435 row.classList.add('in', 'ping'); 7436 setTimeout(() => row.classList.remove('ping'), 1400); 7437 }, i * 1200 + 400); 7438 }); 7439 7440 // After initial settle, push a new notification every 9 seconds 7441 const settled = initialRows.length * 1200 + 2000; 7442 setTimeout(() => { 7443 const interval = setInterval(() => { 7444 if (!floater.isConnected) { 7445 clearInterval(interval); 7446 return; 7447 } 7448 const item = queue[qIdx % queue.length]; 7449 qIdx++; 7450 const newRow = document.createElement('div'); 7451 newRow.className = 'row in fresh ping'; 7452 newRow.innerHTML = ` 7453 <span class="lbl">${item.lbl}</span> 7454 <span class="name">${item.name}</span> 7455 ${item.meta ? '<span>' + item.meta + '</span>' : ''} 7456 `; 7457 floater.insertBefore(newRow, floater.firstChild); 7458 7459 // Drop the oldest if we have too many, keep card from growing 7460 const all = floater.querySelectorAll('.row'); 7461 if (all.length > 4) { 7462 const oldest = all[all.length - 1]; 7463 oldest.style.transition = 'opacity .5s ease, transform .5s ease, max-height .5s ease, margin .5s ease, padding .5s ease'; 7464 oldest.style.opacity = '0'; 7465 oldest.style.transform = 'translateY(8px)'; 7466 setTimeout(() => oldest.remove(), 600); 7467 } 7468 7469 setTimeout(() => newRow.classList.remove('ping'), 1400); 7470 }, 9000); 7471 }, settled); 7472 }; 7473 7474 const io = new IntersectionObserver(entries => { 7475 entries.forEach(e => { 7476 if (e.isIntersecting) { 7477 start(); 7478 io.unobserve(floater); 7479 } 7480 }); 7481 }, {threshold: 0.3}); 7482 io.observe(floater); 7483 }); 7484 })(); 7485 7486 // âââ Conversion + engagement events â GA4 / GTM dataLayer âââ 7487 // Every tel: tap, CTA click and lead form submit lands in the dataLayer so 7488 // GTM/GA4 can build conversions without touching the templates again. 7489 (function () { 7490 const page = "pricing"; 7491 const push = (event, params) => { 7492 window.dataLayer = window.dataLayer || []; 7493 window.dataLayer.push(Object.assign({event: event, page_key: page}, params || {})); 7494 }; 7495 7496 // Phone taps: the demo line and the sign-up lines are separate conversions. 7497 // The demo lines come from App\Services\Market (they differ by country 7498 // and by how a visitor has to dial them), matched on their last eight 7499 // digits so the local and the international form are the same line. 7500 const demoTails = ["32421262","92420020"]; 7501 document.querySelectorAll('a[href^="tel:"]').forEach(a => { 7502 a.addEventListener('click', () => { 7503 const num = (a.getAttribute('href') || '').replace('tel:', ''); 7504 const digits = num.replace(/\D/g, ''); 7505 const isDemo = demoTails.some(t => t && digits.endsWith(t)); 7506 push(isDemo ? 'demo_call_click' : 'phone_signup_click', { 7507 phone_number: num, 7508 link_text: (a.textContent || '').trim().slice(0, 80), 7509 }); 7510 }); 7511 }); 7512 7513 // CTA buttons (primary/blue/ghost), which CTA, on which page 7514 document.querySelectorAll('a.btn').forEach(a => { 7515 a.addEventListener('click', () => { 7516 push('cta_click', { 7517 cta_text: (a.textContent || '').trim().slice(0, 80), 7518 cta_style: a.classList.contains('btn-primary') ? 'primary' 7519 : a.classList.contains('btn-blue') ? 'blue' : 'ghost', 7520 cta_href: a.getAttribute('href') || '', 7521 }); 7522 }); 7523 }); 7524 7525 // Lead forms: signup/contact, live demo call, support 7526 document.querySelectorAll('form').forEach(form => { 7527 const action = form.getAttribute('action') || ''; 7528 let event = null; 7529 if (action.includes('/signup/verify')) event = 'sign_up'; 7530 else if (action.includes('/signup/send-code')) event = 'sign_up_start'; 7531 else if (action.includes('/contact')) event = 'generate_lead'; 7532 else if (action.includes('/demo')) event = 'demo_call_request';
7533 else if (action.includes('/support')) event = 'support_request'; 7534 if (!event) return; 7535 form.addEventListener('submit', () => { 7536 const agent = form.querySelector('input[name="agent_type"]:checked'); 7537 push(event, { 7538 form_action: action, 7539 agent_type: agent ? agent.value : undefined, 7540 }); 7541 }); 7542 }); 7543 })(); 7544 7545 /* Agents mega-menu. Desktop opens it on hover/focus via CSS; this handles 7546 the click path, which is the only way in on touch, plus Escape and 7547 click-outside. */ 7548 (function () { 7549 const drops = document.querySelectorAll('[data-nav-drop]'); 7550 if (!drops.length) return; 7551 7552 const closeAll = (except) => drops.forEach((drop) => { 7553 if (drop === except) return; 7554 drop.classList.remove('is-open'); 7555 drop.querySelector('.nav-drop-btn')?.setAttribute('aria-expanded', 'false'); 7556 }); 7557 7558 drops.forEach((drop) => { 7559 const trigger = drop.querySelector('.nav-drop-btn'); 7560 if (!trigger) return; 7561 7562 trigger.addEventListener('click', (event) => { 7563 event.preventDefault(); 7564 event.stopPropagation(); 7565 const open = drop.classList.toggle('is-open'); 7566 trigger.setAttribute('aria-expanded', open ? 'true' : 'false'); 7567 closeAll(drop); 7568 }); 7569 }); 7570 7571 document.addEventListener('click', (event) => { 7572 if (!event.target.closest('[data-nav-drop]')) closeAll(); 7573 }); 7574 7575 document.addEventListener('keydown', (event) => { 7576 if (event.key === 'Escape') closeAll(); 7577 }); 7578 7579 window.talkifyCloseNavDrops = closeAll; 7580 })(); 7581 7582 (function () { 7583 const btn = document.querySelector('.menu-btn'); 7584 const nav = document.querySelector('.nav ul'); 7585 if (!btn || !nav) return; 7586 btn.addEventListener('click', () => { 7587 const open = nav.style.display === 'flex'; 7588 // Collapsing the menu should not leave the Agents accordion open 7589 // behind it, or it reappears expanded next time. 7590 if (open && window.talkifyCloseNavDrops) window.talkifyCloseNavDrops(); 7591 nav.style.display = open ? 'none' : 'flex'; 7592 nav.style.position = 'fixed'; 7593 nav.style.top = '92px'; 7594 nav.style.left = '20px'; 7595 nav.style.right = '20px'; 7596 nav.style.flexDirection = 'column'; 7597 nav.style.background = 'var(--ink-2)'; 7598 nav.style.border = '1px solid var(--line)'; 7599 nav.style.borderRadius = '14px'; 7600 nav.style.padding = '12px'; 7601 nav.style.zIndex = '85'; 7602 }); 7603 })(); 7604 7605 /* Theme toggle, persist choice, flip data-theme on <html> */ 7606 (function () { 7607 var toggles = document.querySelectorAll('[data-theme-toggle]'); 7608 if (!toggles.length) return; 7609 toggles.forEach(function (btn) { 7610 btn.addEventListener('click', function () { 7611 var current = document.documentElement.getAttribute('data-theme') === 'light' ? 'light' : 'dark'; 7612 var next = current === 'light' ? 'dark' : 'light'; 7613 document.documentElement.setAttribute('data-theme', next); 7614 try { 7615 localStorage.setItem('talkify-theme', next); 7616 } catch (e) { 7617 } 7618 }); 7619 }); 7620 })(); 7621</script>
vendor: 1 bytes, line 7621
7621
7622<script> 7623(function(){ 7624 document.querySelectorAll('[data-calc-grid]').forEach(grid => { 7625 const range = grid.querySelector('[data-calc-range]'); 7626 const teamEl = grid.querySelector('[data-calc-team]'); 7627 const intsEl = grid.querySelector('[data-calc-ints]'); 7628 const priceEl = grid.querySelector('[data-calc-price]'); 7629 const planEl = grid.querySelector('[data-calc-plan]'); 7630 const minsEl = grid.querySelector('[data-calc-mins]'); 7631 const concEl = grid.querySelector('[data-calc-conc]'); 7632 const numEl = grid.querySelector('[data-calc-num]'); 7633 const descEl = grid.querySelector('[data-calc-desc]'); 7634 const foundingEl = grid.querySelector('[data-calc-founding]'); 7635 const wasEl = grid.querySelector('[data-calc-was]'); 7636 const usageEl = grid.querySelector('[data-calc-usage]'); 7637 const extraEl = grid.querySelector('[data-calc-extra]'); 7638 const pills = grid.querySelectorAll('.int-pill'); 7639 let intCount = 0; 7640 7641 const TEXTS = 'Each number includes 50 texts a month, then 9c each.'; 7642 const PA_TEXTS = 'Includes 20 texts a month, then 9c each.'; 7643 const OVERAGE = " a minute (20c after your first 3 months). "; 7644 // Blank when the plan is not actually discounted: the JS hides the 7645 // crossed-out price and its founding tag whenever `was` is empty. 7646 const PA_WAS = ""; 7647 const BIZ_WAS = "$199/mo"; 7648 const BUSINESS_ONLY = false;
7649 7650 // The slider counts agents on ONE number. The Broadcast price covers up 7651 // to three of them; each agent past three adds the flat extra-agent rate. 7652 const INCLUDED_AGENTS = 3; 7653 const EXTRA_RATE = 39; 7654 const BIZ_RATE = 129; 7655 const BIZ_MINS = 200; 7656 const money = n => '$' + (Math.round(n * 100) / 100).toLocaleString('en-NZ', {minimumFractionDigits: n % 1 ? 2 : 0, maximumFractionDigits: 2}); 7657 7658 function recalc(){ 7659 const agents = parseInt(range.value); 7660 teamEl.textContent = agents; 7661 intsEl.textContent = intCount; 7662 let plan, price, was, mins, conc, num, desc, usage; 7663 num = '1'; 7664 conc = '3 calls'; 7665 if(!BUSINESS_ONLY && agents === 1){ 7666 plan='Shortwave · PA'; price='$89'; was=PA_WAS; mins='50/mo'; 7667 // The apostrophe in "person's" MUST stay escaped. Unescaped it closes 7668 // this single-quoted string, which is a syntax error that takes the 7669 // whole IIFE down with it, so no listeners bind and the agent slider 7670 // silently does nothing on all 24 pages that include this partial. 7671 desc='Shortwave is the Personal Assistant plan: one person\'s own mobile or landline, screened and answered. For a business number with reception, pick Broadcast.'; 7672 usage='Includes 50 minutes a month, then 10c'+OVERAGE+PA_TEXTS; 7673 } else if(agents <= 10){ 7674 // Up to three agents ride inside the plan price; the rest are the 7675 // flat extra-agent rate each. 7676 const extras = Math.max(0, agents - INCLUDED_AGENTS); 7677 const total = BIZ_RATE + extras * EXTRA_RATE; 7678 plan='Broadcast'; price=money(total); was = agents <= INCLUDED_AGENTS ? BIZ_WAS : ''; 7679 mins=BIZ_MINS+'/mo'; 7680 desc = agents <= INCLUDED_AGENTS 7681 ? (agents === 1 7682 ? 'Broadcast fits most growing NZ businesses. One number, up to '+INCLUDED_AGENTS+' agents on it, three callers at once.' 7683 : agents + ' agents sharing one number, all inside the one plan price ('+INCLUDED_AGENTS+' are included).') 7684 : agents + ' agents on one number: '+INCLUDED_AGENTS+' included in the plan, '+extras+' extra at '+money(EXTRA_RATE)+' a month each.'; 7685 usage='Includes '+BIZ_MINS+' minutes a month, then 10c'+OVERAGE+TEXTS; 7686 } else { 7687 plan='Fleet'; price='Custom'; was=''; mins='Unlimited'; conc='Unlimited'; num='Unlimited'; 7688 desc='Fleet is right for multi-location operators and contact centres. SLA-backed, NZ data residency, dedicated voice clone.'; 7689 usage='Minutes, calls and texts are set in your custom Fleet quote.'; 7690 } 7691 priceEl.textContent = price; 7692 planEl.textContent = plan; 7693 minsEl.textContent = mins; 7694 concEl.textContent = conc; 7695 numEl.textContent = num; 7696 descEl.textContent = desc; 7697 if(usageEl) usageEl.textContent = usage; 7698 // Fleet is quoted per account, so the extra-agent rate does not apply 7699 if(extraEl) extraEl.style.display = (plan === 'Fleet') ? 'none' : ''; 7700 if(foundingEl){ 7701 foundingEl.style.display = was ? 'flex' : 'none'; 7702 if(was && wasEl) wasEl.textContent = was; 7703 } 7704 } 7705 range.addEventListener('input', recalc); 7706 pills.forEach(p => p.addEventListener('click', ()=>{ 7707 p.classList.toggle('on'); 7708 intCount = grid.querySelectorAll('.int-pill.on').length; 7709 recalc(); 7710 })); 7711 }); 7712})(); 7713</script>
7713 7714 7715</body> 7716</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.