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>AI Phone Answering for Fish & Chip Shops NZ & AU · Talkify</title> 29 <meta name="description" 30 content="Your chippie's phone rings flat out from five o'clock and nobody can leave the fryer. Talkify answers every call, takes the order with the salt and sauces on it, and puts it on a screen by the till. From $10/month."> 31 32 33 <link rel="icon" type="image/x-icon" href="/favicon.ico"> 34 <link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png"> 35 <link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png"> 36 <link rel="apple-touch-icon" sizes="180x180" href="/media/branding/brand/app-icon-180.png"> 37 <link rel="manifest" href="/site.webmanifest"> 38 39 <meta name="theme-color" content="#318abe"> 40 41 <meta property="og:type" content="website"> 42 <meta property="og:url" content="https://talkify.nz/fish-and-chip-shop"> 43 <meta property="og:site_name" content="Talkify"> 44 <meta property="og:title" content="AI Phone Answering for Fish & Chip Shops NZ & AU · Talkify"> 45 <meta property="og:description" 46 content="Your chippie's phone rings flat out from five o'clock and nobody can leave the fryer. Talkify answers every call, takes the order with the salt and sauces on it, and puts it on a screen by the till. From $10/month."> 47 <meta property="og:image" content="https://talkify.nz/media/frontend/fish-and-chips.jpg"> 48 49 <meta property="og:image:width" content="1200"> 50 <meta property="og:image:height" content="630"> 51 <meta property="og:image:type" content="image/jpeg"> 52 <meta property="og:image:alt" 53 content="A New Zealand fish and chip shop counter at teatime while Talkify takes a phone order."> 54 55 <meta property="og:locale" content="en_NZ"> 56 57 <meta name="twitter:card" content="summary_large_image"> 58 <meta name="twitter:title" content="AI Phone Answering for Fish & Chip Shops NZ & AU · Talkify"> 59 <meta name="twitter:description" 60 content="Your chippie's phone rings flat out from five o'clock and nobody can leave the fryer. Talkify answers every call, takes the order with the salt and sauces on it, and puts it on a screen by the till. From $10/month."> 61 <meta name="twitter:image" content="https://talkify.nz/media/frontend/fish-and-chips.jpg"> 62 <meta name="facebook-domain-verification" content="ic2puw1bkz233rscxrhcl0qol7suu1"/> 63 64
64<script 65 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>
65 66 67
67<script type="application/ld+json">{"@context":"https://schema.org","@graph":[{"@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Talkify","item":"https://talkify.nz"},{"@type":"ListItem","position":2,"name":"Industries","item":"https://talkify.nz/industries"},{"@type":"ListItem","position":3,"name":"Fish & Chip Shops","item":"https://talkify.nz/fish-and-chip-shop"}]},{"@type":"Service","name":"AI Phone Answering for Fish and Chip Shops","description":"AI phone answering for fish and chip shops in New Zealand and Australia. Answers every call through the teatime rush, takes the order with the salt, sauces and changes written on each line, quotes the current wait, and puts it on a screen by the till.","url":"https://talkify.nz/fish-and-chip-shop","provider":{"@id":"https://talkify.nz#organization"},"areaServed":[{"@type":"Country","name":"New Zealand"},{"@type":"Country","name":"Australia"}],"serviceType":"AI Phone Answering Service","audience":{"@type":"BusinessAudience","audienceType":"Fish & Chip Shops"},"offers":{"@type":"Offer","price":"129","priceCurrency":"NZD","description":"Business agents from $129/month at the founding rate for your first 3 months, then $199. No setup fee, no lock-in."}},{"@type":"FAQPage","mainEntity":[{"@type":"Question","name":"Our phone goes flat out from five. Can it really keep up?","acceptedA
67nswer":{"@type":"Answer","text":"It answers every call at once, which is the part a person cannot do. Four people ringing at ten past six all get answered on the second ring rather than three of them getting a busy tone and trying the shop up the road. Each one gets its own ticket on your screen, in the order they came in."}},{"@type":"Question","name":"Will it get the order right? Chips are not simple.","acceptedAnswer":{"@type":"Answer","text":"Anything the customer asks for on a particular item is written on that line in their own words. Chicken salt on the chips, no vinegar, extra tartare, scallops well done. It reads the order back before it sends it, and if they change their mind halfway through it updates the same ticket rather than starting another."}},{"@type":"Question","name":"We do not have a menu system. Do we need one?","acceptedAnswer":{"@type":"Answer","text":"No, and that is the point. Put your menu and your prices into your agent once, in whatever form you have them, and it can tell a caller what you do and what it costs as well as taking the order. The order lands on a screen you already own: a tablet, an old laptop, a spare monitor with a browser."}},{"@type":"Question","name":"Can it tell people how long the wait is?","acceptedA
67nswer":{"@type":"Answer","text":"Yes, and this is the one your customers will notice. Tap a time on the screen and the agent quotes it to everyone who rings after that. When the fryers are backed up you change it to forty minutes and nobody is promised fifteen. It clears itself after a few hours so a busy Friday figure is never still being quoted on a quiet Tuesday."}},{"@type":"Question","name":"What if we run out of something?","acceptedAnswer":{"@type":"Answer","text":"Type it on the screen once. \"No oysters tonight.\" The agent tells the callers it actually affects and offers them something else, and says nothing about it to the ones who never asked."}},{"@type":"Question","name":"Do we have to ring people back when it is ready?","acceptedAnswer":{"@type":"Answer","text":"Only if you want to. Tap the ticket when the order is going in the bag and the customer gets a message saying it is ready, already written with their name on it. It goes by WhatsApp when they have it, which is free, and as a text when they do not."}},{"@type":"Question","name":"Does it take card payments over the phone?","acceptedA
67nswer":{"@type":"Answer","text":"No. Talkify never handles card details. Customers pay at the counter the way they do now, which is also what stops a phone order becoming a chargeback argument."}},{"@type":"Question","name":"We are in Australia. Does this work over here?","acceptedAnswer":{"@type":"Answer","text":"Yes. Talkify runs on both sides of the Tasman, with Australian numbers answered in Australian data centres and New Zealand numbers in New Zealand ones. The agent speaks the way your customers do, and the screen works the same either way."}},{"@type":"Question","name":"What does it cost?","acceptedAnswer":{"@type":"Answer","text":"Two ways. Pay as you go is $10 a month for the number plus $1 a minute, which suits a shop whose phone goes in bursts. A reception agent is $129/month at the founding rate for your first 3 months, then $199 flat. The screen is $59 a month on top of either. No setup fee and no lock in."}}]}]}</script>
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 <link rel="canonical" href="https://talkify.nz/fish-and-chip-shop"> 5169</head> 5170<body data-page="industry-fish-and-chips"> 5171<!-- Google Tag Manager (noscript) -->
vendor: 73 bytes, lines 5171-5173
5171 5172<noscript> 5173 <iframe src="https://www.googletagmanager.com/ns.html?id=
5173GTM-TTGHDLQ4
vendor: 97 bytes, lines 5173-5176
5173" 5174 height="0" width="0" style="display:none;visibility:hidden"></iframe> 5175</noscript> 5176
5177<!-- End Google Tag Manager (noscript) --> 5178<div class="grain"></div> 5179<div class="scanlines"></div> 5180<div class="vignette"></div> 5181 5182<nav class="nav"> 5183 5184 <a href="https://talkify.nz" class="logo" aria-label="Talkify, home"> 5185 <svg class="tk-logo" viewBox="-3 -3 317.81 106" 5186 width="113.93" height="38" 5187 xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Talkify" focusable="false"> 5188 <defs> 5189 <linearGradient id="tkgw8PHrf" gradientUnits="userSpaceOnUse" x1="8" y1="92" x2="92" y2="8"> 5190 <stop offset="0" stop-color="#318abe"/> 5191 <stop offset="1" stop-color="#a3d654"/> 5192 </linearGradient> 5193 </defs> 5194 <circle cx="50" cy="50" r="50" fill="url(#tkgw8PHrf)"/> 5195 5196 <g fill="none" stroke="#ffffff" stroke-width="10" stroke-linecap="round"> 5197 <path d="M34 26 V54 C34 74 62 80 76 62"/> 5198 <path d="M20 40 H46"/> 5199 </g> 5200 5201 <g transform="translate(56 20) scale(0.30)"> 5202 <g class="tk-eye"> 5203 <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"/> 5204 </g> 5205 </g> 5206 <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"/> 5207 5208 <g transform="translate(231.30 6.84) scale(0.216)"> 5209 <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" 5210 fill="#a3d654"/> 5211 </g> 5212 </svg> 5213 </a> 5214 <ul> 5215 <li class="nav-drop" data-nav-drop> 5216 <button type="button" class="nav-drop-btn " 5217 aria-expanded="false" aria-controls="nav-agents-menu" aria-haspopup="true"> 5218 <span class="dot"></span>Agents 5219 <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> 5220 </button> 5221 5222 5223 <div class="nav-drop-panel" id="nav-agents-menu"> 5224 <div class="nav-drop-col"> 5225 <span class="nav-drop-hd">Answering calls</span> 5226 <a href="https://talkify.nz/reception"><span>Reception</span><em>Answers every call, books the job</em></a> 5227 <a href="https://talkify.nz/personal-assistant"><span>Personal Assistant</span><em>Your own PA on the phone</em></a> 5228 <a href="https://talkify.nz/booking-service"><span>Booking Service</span><em>Fills the diary while you work</em></a> 5229 <a href="https://talkify.nz/front-counter"><span>Front Counter</span><em>Orders and bookings on a screen by the till</em></a> 5230 <a href="https://talkify.nz/ai-call-centre"><span>AI Call Centre</span><em>5, 10 or 15 lines at once</em></a>
5231 <span class="nav-drop-hd" style="margin-top:18px">Other channels</span> 5232 <a href="https://talkify.nz/website-chat"><span>Website Chat</span><em>The same agent, in a chat box on your site</em></a> 5233 <a href="https://talkify.nz/calendar"><span>Calendar</span><em>The diary the agent books into</em></a> 5234 <a href="https://talkify.nz/lead-management"><span>Leads</span><em>Every enquiry on one board, whatever door it came through</em></a> 5235 <a href="https://talkify.nz/agent-coach"><span>Coach</span><em>Your agent listens back to its own calls</em></a> 5236 </div> 5237 <div class="nav-drop-col"> 5238 <span class="nav-drop-hd">Ringing out</span> 5239 <a href="https://talkify.nz/sales-agent"><span>Sales Agent</span><em>Qualifies and follows up leads</em></a> 5240 <a href="https://talkify.nz/outbound-calls"><span>Outbound Calls</span><em>Campaigns, reminders, win-backs</em></a> 5241 <a href="https://talkify.nz/ai-marketing-campaigns"><span>Marketing Campaigns</span><em>Offers, launches and reviews, by phone</em></a> 5242 <a href="https://talkify.nz/ai-phone-surveys"><span>Campaign Agent</span><em>Rings your list, asks your questions, reports back</em></a> 5243 <a href="https://talkify.nz/debt-collection"><span>Debt Collection</span><em>Chases overdue invoices from Xero</em></a> 5244 <a href="https://talkify.nz/ai-wellness-checks"><span>Wellness Checks</span><em>Rings to check somebody is alright</em></a> 5245 5246 <a href="https://talkify.nz/dialler"><span>Dialler</span><em>Your own team ringing out, from the browser</em></a> 5247 <a href="https://talkify.nz/agents" class="nav-drop-all">See all agents <span class="arr">→</span></a> 5248 </div> 5249 </div> 5250 </li> 5251 5252 <li class="nav-drop" data-nav-drop> 5253 <button type="button" class="nav-drop-btn is-active" 5254 aria-expanded="false" aria-controls="nav-industries-menu" aria-haspopup="true"> 5255 <span class="dot"></span>Industries 5256 <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> 5257 </button> 5258 5259 5260 <div class="nav-drop-panel nav-drop-panel--industries" id="nav-industries-menu"> 5261 <div class="nav-drop-col"> 5262 <span class="nav-drop-hd">Trades</span> 5263 <a href="https://talkify.nz/tradesman">All Trades</a> 5264 <a href="https://talkify.nz/builder">Builders</a> 5265 <a href="https://talkify.nz/electrician">Electricians</a> 5266 <a href="https://talkify.nz/hvac">Heat Pump & HVAC</a> 5267 <a href="https://talkify.nz/landscaping">Landscaping</a> 5268 <a href="https://talkify.nz/automotive">Mechanics</a> 5269 <a href="https://talkify.nz/pest-control">Pest Control</a> 5270 <a href="https://talkify.nz/plumber">Plumbing</a> 5271 </div> 5272 <div class="nav-drop-col"> 5273 <span class="nav-drop-hd">Health & beauty</span> 5274 <a href="https://talkify.nz/barber">Barbers</a> 5275 <a href="https://talkify.nz/beauty">Beauty & Wellness</a> 5276 <a href="https://talkify.nz/gym">Gyms & Studios</a> 5277 <a href="https://talkify.nz/personal-trainer">Personal Trainers</a> 5278 <a href="https://talkify.nz/physio">Physio & Clinics</a> 5279 <span class="nav-drop-hd" style="margin-top:18px">Office & property</span> 5280 <a href="https://talkify.nz/accountant">Accountants</a> 5281 <a href="https://talkify.nz/professional-services">Professional Services</a> 5282 <a href="https://talkify.nz/real-estate">Real Estate</a> 5283 <a href="https://talkify.nz/retail">Retail</a> 5284 </div> 5285 <div class="nav-drop-col"> 5286 <span class="nav-drop-hd">Food & hospitality</span> 5287 <a href="https://talkify.nz/cafe">Cafes</a> 5288 <a href="https://talkify.nz/chinese-takeaway">Chinese Takeaways</a> 5289 <a href="https://talkify.nz/fish-and-chip-shop">Fish & Chip Shops</a> 5290 <a href="https://talkify.nz/hotel">Hotels & Motels</a> 5291 <a href="https://talkify.nz/pizza-shop">Pizza Shops</a> 5292 <a href="https://talkify.nz/restaurant-bookings">Restaurants</a> 5293 <a href="https://talkify.nz/industries" class="nav-drop-all">See all industries <span class="arr">→</span></a> 5294 </div> 5295 </div> 5296 </li> 5297 <li class="nav-drop" data-nav-drop> 5298 <button type="button" class="nav-drop-btn " 5299 aria-expanded="false" aria-controls="nav-integrations-menu" aria-haspopup="true">
5300 <span class="dot"></span>Integrations 5301 <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> 5302 </button> 5303 5304 <div class="nav-drop-panel nav-drop-panel--single" id="nav-integrations-menu"> 5305 <div class="nav-drop-col"> 5306 <span class="nav-drop-hd">Plugs into</span> 5307 <a href="https://talkify.nz/integrations"><span>All integrations</span><em>The software the agent already talks to</em></a> 5308 <a href="https://talkify.nz/business-phone-lines"><span>Phone Lines</span><em>Numbers, porting and how calls reach us</em></a> 5309 </div> 5310 </div> 5311 </li> 5312 <li><a href="https://talkify.nz/pricing" class=""><span class="dot"></span>Pricing</a></li> 5313 <li><a href="https://talkify.nz/blog" class=""><span class="dot"></span>Journal</a></li> 5314 <li><a href="https://talkify.nz/signup" class=""><span class="dot"></span>Get started</a></li> 5315 </ul> 5316 <div class="actions"> 5317 <button type="button" class="theme-toggle" data-theme-toggle aria-label="Switch between light and dark theme" title="Switch theme"> 5318 <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> 5319 <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> 5320 </button> 5321 5322 <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> 5323 <a href="tel:+64800002967" class="num num-call" title="Call us on 0800 002 967" aria-label="Call us on 0800 002 967"> 5324 <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> 5325 </a> 5326 <a href="https://talkify.nz/login" class="num" style="font-family:var(--sans);font-size:13px;color:var(--bone)">Sign in</a> 5327 <a href="https://talkify.nz/signup" class="btn btn-primary">Start free <span class="arr">â</span></a> 5328 <button class="menu-btn" aria-label="Open menu"> 5329 <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M4 7h16M4 12h16M4 17h16"/></svg> 5330 </button> 5331 </div> 5332</nav> 5333 5334 5335<section class="hero"> 5336 <div class="hero-bg"><div class="glow1"></div><div class="glow2"></div><div class="grid-lines"></div></div> 5337 5338 <div class="hero-shell"> 5339 <div> 5340 <div class="crumb"><a href="https://talkify.nz">Talkify</a> <span>/</span> <a href="https://talkify.nz/industries">Industries</a> <span>/</span> <span style="color:var(--paper)">Fish & Chip Shops</span></div> 5341 5342 <span class="eyebrow" style="margin-top:18px"><span class="pin"></span>Takeaway · Orders on a screen · NZ & AU</span> 5343 5344 <h1 class="display"> 5345 <span class="ln"><span>The phone rings</span></span> 5346 <span class="ln"><span class="out">at ten past six.</span></span> 5347 <span class="ln"><span class="it">Nobody can leave the fryer.</span></span> 5348 </h1> 5349 5350 <p class="hero-sub">So it rings out, and that order goes to the shop up the road. Talkify answers every call, takes the order, and puts it on a screen by your till.</p> 5351 5352 <div class="hero-cta"> 5353 <a href="#signup" class="btn btn-primary btn-lg">Set up your shop <span class="arr">â</span></a> 5354 <a href="#pricing" class="btn btn-ghost btn-lg">What it costs</a> 5355 </div> 5356 5357 <dl class="hero-meta"> 5358 <div><dt>Answers</dt><dd>
5358Every call</dd></div> 5359 <div><dt>Order lands</dt><dd>Mid-call</dd></div> 5360 <div><dt>From</dt><dd>$10<small>/mo</small></dd></div> 5361 <div><dt>Setup fee</dt><dd>$0</dd></div> 5362 </dl> 5363 </div> 5364 5365 <figure class="hero-photo" style="--shot-dark:url('https://talkify.nz/media/frontend/fish-and-chips.jpg')" aria-label="A New Zealand fish and chip shop counter at teatime, wrapped parcels on the bench, while an order arrives on a tablet screen"> 5366 <span class="corner">Order 0148 · 2 scoops</span> 5367 <figcaption class="caption"> 5368 <div class="title">Four calls at once.<br><span class="it">Four orders on the screen.</span></div> 5369 <div class="stat">6:10pm<b>None missed</b></div> 5370 </figcaption> 5371 </figure> 5372 </div> 5373</section> 5374 5375<div class="strip"> 5376 <div class="strip-track"> 5377 <a href="https://talkify.nz/reception" class="strip-link" > 5378 Reception <span class="pip">â</span> </a> 5379 <a href="https://talkify.nz/personal-assistant" class="strip-link it" > 5380 Personal Assistant </a> 5381 <a href="https://talkify.nz/booking-service" class="strip-link" > 5382 Booking Service <span class="pip">â</span> </a> 5383 <a href="https://talkify.nz/sales-agent" class="strip-link it" > 5384 Sales Qualification </a> 5385 <a href="https://talkify.nz/tradesman" class="strip-link it" > 5386 Tradesman Dispatcher </a> 5387 <a href="https://talkify.nz/real-estate" class="strip-link" > 5388 Real Estate Enquiry <span class="pip">â</span> </a> 5389 <a href="https://talkify.nz/beauty" class="strip-link it" > 5390 Beauty & Wellness </a> 5391 <a href="https://talkify.nz/plumber" class="strip-link" > 5392 Plumbing Dispatch <span class="pip">â</span> </a> 5393 <a href="https://talkify.nz/retail" class="strip-link it" > 5394 Retail </a> 5395 <a href="https://talkify.nz/professional-services" class="strip-link" > 5396 Professional Services <span class="pip">â</span> </a> 5397 <a href="https://talkify.nz/reception" class="strip-link" aria-hidden="true" tabindex="-1" > 5398 Reception <span class="pip">â</span> </a> 5399 <a href="https://talkify.nz/personal-assistant" class="strip-link it" aria-hidden="true" tabindex="-1" > 5400 Personal Assistant </a> 5401 <a href="https://talkify.nz/booking-service" class="strip-link" aria-hidden="true" tabindex="-1" > 5402 Booking Service <span class="pip">â</span> </a> 5403 <a href="https://talkify.nz/sales-agent" class="strip-link it" aria-hidden="true" tabindex="-1" > 5404 Sales Qualification </a> 5405 <a href="https://talkify.nz/tradesman" class="strip-link it" aria-hidden="true" tabindex="-1" > 5406 Tradesman Dispatcher </a> 5407 <a href="https://talkify.nz/real-estate" class="strip-link" aria-hidden="true" tabindex="-1" > 5408 Real Estate Enquiry <span class="pip">â</span> </a> 5409 <a href="https://talkify.nz/beauty" class="strip-link it" aria-hidden="true" tabindex="-1" > 5410 Beauty & Wellness </a> 5411 <a href="https://talkify.nz/plumber" class="strip-link" aria-hidden="true" tabindex="-1" > 5412 Plumbing Dispatch <span class="pip">â</span> </a> 5413 <a href="https://talkify.nz/retail" class="strip-link it" aria-hidden="true" tabindex="-1" > 5414 Retail </a> 5415 <a href="https://talkify.nz/professional-services" class="strip-link" aria-hidden="true" tabindex="-1" > 5416 Professional Services <span class="pip">â</span> </a> 5417 </div> 5418</div> 5419 5420<section class="shell"> 5421 <div class="section-hd"> 5422 <h2 class="r">A missed call at teatime is <span class="it">
5422a missed dinner.</span></h2> 5423 <p class="lede r r-1">Nobody rings a chippie twice. Busy tone, and they ring the next one on the list.</p> 5424 </div> 5425 5426 <div class="fcx-cards"> 5427 <article class="fcx-card"> 5428 <span class="fcx-tag" style="--k:#c4451c">Before</span> 5429 <h3>Five o'clock to seven</h3> 5430 <p>Rings out. Or somebody answers with wet hands and writes half of it on a docket that goes missing.</p> 5431 </article> 5432 5433 <article class="fcx-card"> 5434 <span class="fcx-tag" style="--k:#10695a">After</span> 5435 <h3>The same two hours</h3> 5436 <p>Every call answered. Every order legible, with the changes on the right line.</p> 5437 </article> 5438 5439 <article class="fcx-card"> 5440 <span class="fcx-tag" style="--k:#318abe">Sunday night</span> 5441 <h3>When you are shut</h3> 5442 <p>It says when you open and refuses an order nobody is there to cook.</p> 5443 </article> 5444 </div> 5445</section> 5446 5447<section class="shell tight"> 5448 <div class="section-hd"> 5449 <h2 class="r">The phone rings. <span class="it">Nobody stops.</span></h2> 5450 <p class="lede r r-1">Any tablet, laptop or spare screen with a browser on it. Nothing to install.</p> 5451 </div> 5452 5453 <div class="cap-plate mixed r"><div class="cap third"> 5454 5455 <div class="cap-hd"> 5456 <h3>Answers <span class="green">every call.</span></h3> 5457 <svg class="cap-mark" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" 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.13.96.36 1.9.7 2.81a2 2 0 01-.45 2.11L8.09 9.91a16 16 0 006 6l1.27-1.27a2 2 0 012.11-.45c.91.34 1.85.57 2.81.7A2 2 0 0122 16.92z"/></svg> 5458 </div> 5459 5460 <p>All of them at once, on the second ring, however busy you are.</p> 5461 5462 5463 </div> 5464 <div class="cap third"> 5465 5466 <div class="cap-hd"> 5467 <h3>Asks <span class="it">the right things.</span></h3> 5468 <svg class="cap-mark" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M4 4h16v12H5.2L4 17.5V4z"/><path d="M8 8h8M8 12h5"/></svg> 5469 </div> 5470 5471 <p>And writes what they asked for on the line it belongs to, in their words.</p> 5472 5473 5474 </div> 5475 <div class="cap third"> 5476 5477 <div class="cap-hd"> 5478 <h3>Lands <span class="green">mid-call.</span></h3> 5479 <svg class="cap-mark" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="4" width="18" height="14" rx="2"/><path d="M8 20h8M12 18v2"/><path d="M7 9h10M7 13h6"/></svg> 5480 </div> 5481 5482 <p>The ticket fills in while they talk, so you see a big order coming.</p> 5483 5484 5485 </div> 5486 <div class="cap half"> 5487 5488 <div class="cap-hd"> 5489 <h3>You set <span class="it">the wait.</span></h3> 5490 <svg class="cap-mark" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3.5 2"/></svg> 5491 </div> 5492 5493 <p>Tap a time and every caller after that is told it. Change it as the night goes on; it goes quiet on its own so a lunchtime figure is never quoted at nine.</p> 5494 5495 5496 </div> 5497 <div class="cap half"> 5498 5499 <div class="cap-hd"> 5500 <h3>Run out? <span class="green">One tap.</span></h3> 5501 <svg class="cap-mark" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 3l9 5v8l-9 5-9-5V8z"/><path d="M9 12l2 2 4-4"/></svg> 5502 </div> 5503 5504 <p>Tap the item on the screen and the agent stops selling it from the very next call, and takes it off any order a caller tries anyway. Everything comes back at midnight on its own.</p> 5505 5506 5507 </div></div> 5508 5509</section> 5510 5511<style>
5512 /* ---------- scenario cards: three columns, no prose ---------- */ 5513 .fcx-cards{display:grid;grid-template-columns:repeat(3,1fr);gap:clamp(18px,2.4vw,34px);margin-top:34px} 5514 .fcx-card{border-top:2px solid var(--k,var(--line-2));padding:22px 0 0} 5515 .fcx-tag{display:inline-block;font-family:var(--mono);font-size:10.5px;letter-spacing:.16em; 5516 text-transform:uppercase;color:var(--k,var(--mute))} 5517 .fcx-card h3{font-family:var(--serif);font-size:clamp(19px,1.9vw,23px);font-weight:400; 5518 margin:10px 0 6px;letter-spacing:-.02em;color:var(--paper);line-height:1.2} 5519 .fcx-card p{font-size:14px;color:var(--bone);line-height:1.6;margin:0} 5520 5521 /* ---------- the two ways to pay ---------- 5522 Two plans side by side with the number doing the talking, then the add-on 5523 as one strip underneath. The old version said all of this in sentences and 5524 nobody was going to read it standing in a kitchen. */ 5525 .fcx-plans{display:grid;grid-template-columns:repeat(2,1fr);gap:clamp(18px,2.4vw,30px);margin-top:36px} 5526 .fcx-plan{position:relative;display:flex;flex-direction:column;padding:30px 28px 28px; 5527 border:1px solid var(--line-2);border-radius:14px; 5528 background:linear-gradient(180deg,rgba(255,255,255,.035),transparent 190px)} 5529 .fcx-plan.is-pick{border-color:color-mix(in srgb,var(--signal) 55%,transparent); 5530 box-shadow:0 0 0 1px color-mix(in srgb,var(--signal) 22%,transparent)} 5531 .fcx-flag{position:absolute;top:-11px;left:28px;padding:3px 12px;border-radius:99px; 5532 font-family:var(--mono);font-size:10px;letter-spacing:.14em;text-transform:uppercase; 5533 background:var(--signal);color:#0b1219;font-weight:700} 5534 .fcx-plan-lbl{font-family:var(--mono);font-size:11px;letter-spacing:.18em;text-transform:uppercase;color:var(--mute)} 5535 .fcx-num{display:flex;align-items:baseline;gap:8px;margin:16px 0 4px; 5536 font-family:var(--serif);font-weight:300;letter-spacing:-.03em;color:var(--paper); 5537 font-size:clamp(40px,5.4vw,62px);line-height:1} 5538 .fcx-num small{font-family:var(--sans,inherit);font-size:14px;font-weight:400;color:var(--mute);letter-spacing:0} 5539 .fcx-then{margin:0 0 18px;font-size:14.5px;color:var(--bone);line-height:1.55} 5540 .fcx-then b{color:var(--paper);font-weight:600} 5541 .fcx-list{list-style:none;margin:0 0 22px;padding:0;display:grid;gap:9px} 5542 .fcx-list li{position:relative;padding-left:24px;color:var(--bone);font-size:14px;line-height:1.55} 5543 .fcx-list li::before{content:'â';position:absolute;left:0;top:-1px;color:var(--signal);font-weight:700} 5544 .fcx-suits{margin:auto 0 0;padding-top:18px;border-top:1px solid var(--line-2); 5545 font-size:13px;color:var(--mute);line-height:1.55} 5546 .fcx-suits b{color:var(--bone);font-weight:600} 5547 5548 /* ---------- the add-on strip ---------- */ 5549 .fcx-addon{display:grid;grid-template-columns:auto 1fr auto;align-items:center; 5550 gap:clamp(16px,2.6vw,34px);margin-top:20px;padding:24px 28px; 5551 border:1px dashed var(--line-2);border-radius:14px} 5552 .fcx-addon-num{font-family:var(--serif);font-weight:300;font-size:clamp(30px,3.4vw,40px); 5553 line-height:1;letter-spacing:-.03em;color:var(--paper);white-space:nowrap} 5554 .fcx-addon-num small{font-family:var(--sans,inherit);font-size:13px;color:var(--mute);letter-spacing:0} 5555 .fcx-addon p{margin:0;font-size:14px;color:var(--bone);line-height:1.6} 5556 .fcx-addon p b{color:var(--paper);font-weight:600} 5557 .fcx-addon .btn{white-space:nowrap} 5558 5559 .fcx-fine{margin:18px 0 0;font-size:13px;color:var(--mute);line-height:1.6;max-width:74ch} 5560 5561 @media (max-width:900px){ 5562 .fcx-cards{grid-template-columns:1fr} 5563 .fcx-plans{grid-template-columns:1fr} 5564 .fcx-addon{grid-template-columns:1fr;text-align:left} 5565 } 5566</style> 5567 5568<section class="shell tight" id="pricing"> 5569 <div class="section-hd"> 5570 <span class="eyebrow eb-green"><span class="pin"></span>Pricing</span> 5571 <h2 class="r">Two ways to pay. <span class="green">No setup fee either way.</span></h2> 5572 </div> 5573 5574 <div class="fcx-plans"> 5575 <article class="fcx-plan is-pick"> 5576 <span class="fcx-flag">Most shops start here</span> 5577 <span class="fcx-plan-lbl">Pay as you go</span> 5578 <span class="fcx-num">$10<small>/month</small></span> 5579 <p class="fcx-then">Then <b>$1 a minute</b>, only on calls you take.</p> 5580 <ul class="fcx-list"> 5581 <li>$10 free credit to start</li> 5582 <li>A quiet Tuesday costs almost nothing</li> 5583 <li>Cancel any time</li> 5584 </ul> 5585 <p class="fcx-suits"><b>Suits</b> a phone that goes in bursts: weekend trade, seasonal, or still working out the numbers.</p> 5586 </article> 5587 5588 <article class="fcx-plan">
5589 <span class="fcx-plan-lbl">Reception agent</span> 5590 <span class="fcx-num">$129<small>/month</small></span> 5591 <p class="fcx-then">Flat, per number. Founding rate, then $199.</p> 5592 <ul class="fcx-list"> 5593 <li>200 call minutes and 50 texts a month</li> 5594 <li>Up to 3 agents on the number</li> 5595 <li>Extra minutes 10c each</li> 5596 </ul> 5597 <p class="fcx-suits"><b>Suits</b> a phone that barely stops through service, where you would rather know the figure up front.</p> 5598 </article> 5599 </div> 5600 5601 <div class="fcx-addon"> 5602 <span class="fcx-addon-num">+$59<small>/mo</small></span> 5603 <p><b>Front Counter, the screen itself.</b> As many tablets as you like, on either plan, with sold-out taps, docket printing, daily order numbers and an end-of-day close-out included. Texts from the screen are 10c each and WhatsApp is free.</p> 5604 <a href="https://talkify.nz/front-counter" class="btn btn-ghost">How the screen works <span class="arr">→</span></a> 5605 </div> 5606 5607 <p class="fcx-fine"> 5608 The screen needs an agent answering the phone, so it is one of the two above plus Front Counter, whichever suits a chip shop. 5609 <a href="https://talkify.nz/pricing">Full price list</a>. 5610 </p> 5611</section> 5612 5613<section class="shell" id="faq"> 5614 <div class="section-hd"> 5615 <h2 class="r">Frequently <span class="it">asked.</span></h2> 5616 5617 <p class="lede r r-1">Nine of the questions we hear most. If yours isn't here, ring our live demo agent on 03 242 1262, it'll either answer or queue a callback from a human.</p> 5618 </div> 5619 5620 <div class="r faq-list" id="faq-grid"> 5621 <details class="faq-q"> 5622 <summary> 5623 <span class="faq-n" aria-hidden="true">01</span> 5624 <span class="faq-t">Our phone goes flat out from five. Can it really keep up?</span> 5625 <span class="faq-icon" aria-hidden="true">+</span> 5626 </summary> 5627 <div class="faq-a">It answers every call at once, which is the part a person cannot do. Four people ringing at ten past six all get answered on the second ring rather than three of them getting a busy tone and trying the shop up the road. Each one gets its own ticket on your screen, in the order they came in.</div> 5628 </details> 5629 <details class="faq-q"> 5630 <summary> 5631 <span class="faq-n" aria-hidden="true">02</span> 5632 <span class="faq-t">Will it get the order right? Chips are not simple.</span> 5633 <span class="faq-icon" aria-hidden="true">+</span> 5634 </summary> 5635 <div class="faq-a">Anything the customer asks for on a particular item is written on that line in their own words. Chicken salt on the chips, no vinegar, extra tartare, scallops well done. It reads the order back before it sends it, and if they change their mind halfway through it updates the same ticket rather than starting another.</div> 5636 </details> 5637 <details class="faq-q"> 5638 <summary> 5639 <span class="faq-n" aria-hidden="true">03</span> 5640 <span class="faq-t">We do not have a menu system. Do we need one?</span> 5641 <span class="faq-icon" aria-hidden="true">+</span> 5642 </summary> 5643 <div class="faq-a">No, and that is the point. Put your menu and your prices into your agent once, in whatever form you have them, and it can tell a caller what you do and what it costs as well as taking the order. The order lands on a screen you already own: a tablet, an old laptop, a spare monitor with a browser.</div> 5644 </details> 5645 <details class="faq-q"> 5646 <summary> 5647 <span class="faq-n" aria-hidden="true">04</span> 5648 <span class="faq-t">Can it tell people how long the wait is?</span> 5649 <span class="faq-icon" aria-hidden="true">+</span> 5650 </summary> 5651 <div class="faq-a">Yes, and this is the one your customers will notice. Tap a time on the screen and the agent quotes it to everyone who rings after that. When the fryers are backed up you change it to forty minutes and nobody is promised fifteen. It clears itself after a few hours so a busy Friday figure is never still being quoted on a quiet Tuesday.</div> 5652 </details> 5653 <details class="faq-q"> 5654 <summary>
5655 <span class="faq-n" aria-hidden="true">05</span> 5656 <span class="faq-t">What if we run out of something?</span> 5657 <span class="faq-icon" aria-hidden="true">+</span> 5658 </summary> 5659 <div class="faq-a">Type it on the screen once. "No oysters tonight." The agent tells the callers it actually affects and offers them something else, and says nothing about it to the ones who never asked.</div> 5660 </details> 5661 <details class="faq-q"> 5662 <summary> 5663 <span class="faq-n" aria-hidden="true">06</span> 5664 <span class="faq-t">Do we have to ring people back when it is ready?</span> 5665 <span class="faq-icon" aria-hidden="true">+</span> 5666 </summary> 5667 <div class="faq-a">Only if you want to. Tap the ticket when the order is going in the bag and the customer gets a message saying it is ready, already written with their name on it. It goes by WhatsApp when they have it, which is free, and as a text when they do not.</div> 5668 </details> 5669 <details class="faq-q"> 5670 <summary> 5671 <span class="faq-n" aria-hidden="true">07</span> 5672 <span class="faq-t">Does it take card payments over the phone?</span> 5673 <span class="faq-icon" aria-hidden="true">+</span> 5674 </summary> 5675 <div class="faq-a">No. Talkify never handles card details. Customers pay at the counter the way they do now, which is also what stops a phone order becoming a chargeback argument.</div> 5676 </details> 5677 <details class="faq-q"> 5678 <summary> 5679 <span class="faq-n" aria-hidden="true">08</span> 5680 <span class="faq-t">We are in Australia. Does this work over here?</span> 5681 <span class="faq-icon" aria-hidden="true">+</span> 5682 </summary> 5683 <div class="faq-a">Yes. Talkify runs on both sides of the Tasman, with Australian numbers answered in Australian data centres and New Zealand numbers in New Zealand ones. The agent speaks the way your customers do, and the screen works the same either way.</div> 5684 </details> 5685 <details class="faq-q"> 5686 <summary> 5687 <span class="faq-n" aria-hidden="true">09</span> 5688 <span class="faq-t">What does it cost?</span> 5689 <span class="faq-icon" aria-hidden="true">+</span> 5690 </summary> 5691 <div class="faq-a">Two ways. Pay as you go is $10 a month for the number plus $1 a minute, which suits a shop whose phone goes in bursts. A reception agent is $129/month at the founding rate for your first 3 months, then $199 flat. The screen is $59 a month on top of either. No setup fee and no lock in.</div> 5692 </details> 5693 </div> 5694 5695 <style> 5696 /* V2 design language: a ruled list, not a grid of boxed cards. Each row is 5697 a hairline, a mono index, the question in serif, and a bare + opposite. 5698 The old version was two columns of rounded, filled panels each with the 5699 + in a circular badge, which is the card furniture the V2 homepage does 5700 without. One column because a ruled list has to read down a single 5701 measure; two columns of rules would fight each other across the gutter. */ 5702 .faq-list { margin-top: 44px; border-bottom: 1px solid var(--line-2) } 5703 5704 .faq-q { border-top: 1px solid var(--line-2) } 5705 5706 .faq-q summary { 5707 display: grid; 5708 grid-template-columns: 54px 1fr auto; 5709 align-items: center; 5710 gap: clamp(12px, 2vw, 24px); 5711 padding: 24px clamp(4px, 1vw, 12px); 5712 cursor: pointer; 5713 list-style: none; 5714 transition: background .3s var(--ease) 5715 } 5716 5717 .faq-q::-webkit-details-marker, .faq-q summary::-webkit-details-marker { display: none } 5718 .faq-q summary::marker { content: "" } 5719 5720 .faq-n { 5721 font-family: var(--mono); 5722 font-size: 11px; 5723 letter-spacing: .14em; 5724 color: var(--mute-2) 5725 } 5726 5727 .faq-t { 5728 font-family: var(--serif); 5729 font-weight: 400; 5730 font-size: clamp(17px, 1.7vw, 22px); 5731 line-height: 1.28; 5732 letter-spacing: -.01em; 5733 color: var(--paper); 5734 transition: color .3s var(--ease) 5735 } 5736 5737 .faq-icon { 5738 font-family: var(--mono); 5739 font-size: 17px; 5740 line-height: 1; 5741 color: var(--mute);
5742 transition: transform .3s var(--ease-out), color .3s var(--ease) 5743 } 5744 5745 .faq-q:hover summary { background: var(--surface-2) } 5746 .faq-q:hover .faq-t { color: var(--signal) } 5747 .faq-q:hover .faq-icon { color: var(--signal) } 5748 5749 .faq-q[open] .faq-icon { transform: rotate(45deg); color: var(--signal) } 5750 .faq-q[open] .faq-n { color: var(--signal) } 5751 5752 .faq-a { 5753 padding: 0 clamp(4px, 1vw, 12px) 28px calc(54px + clamp(12px, 2vw, 24px)); 5754 max-width: 76ch; 5755 color: var(--bone); 5756 font-size: 14.5px; 5757 line-height: 1.68 5758 } 5759 5760 .faq-q summary:focus { outline: none } 5761 .faq-q summary:focus-visible { outline: 2px solid var(--signal); outline-offset: -2px } 5762 5763 @media (prefers-reduced-motion: reduce) { 5764 .faq-q summary, .faq-t, .faq-icon { transition: none } 5765 } 5766 5767 @media (max-width: 640px) { 5768 .faq-q summary { grid-template-columns: 34px 1fr auto } 5769 .faq-a { padding-left: calc(34px + 12px) } 5770 } 5771 </style> 5772</section> 5773 5774<section class="shell" id="related"> 5775 <div class="section-hd"> 5776 <h2 class="r">The rest of <span class="it">the counter.</span></h2> 5777 <p class="lede r r-1">An agent answering the phone is half of it. The same setup can pick the phone up and ring out when that is what the job needs.</p> 5778 </div> 5779 5780 <div class="trade-plate r"> 5781 <a class="trade row" href="https://talkify.nz/front-counter"> 5782 <svg class="mark" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> 5783 <path d="M4 5.5a2 2 0 0 1 2-2h2.2l1.6 3.9-1.9 1.4a12 12 0 0 0 5.3 5.3l1.4-1.9 3.9 1.6V16a2 2 0 0 1-2 2A13.5 13.5 0 0 1 4 5.5z"/> 5784 </svg> 5785 <h3>Front Counter</h3> 5786 <p>How the tablet by the till works, what a ticket looks like, and what happens when a call drops halfway through.</p> 5787 <span class="go"><span>The screen</span> <em>→</em></span> 5788 </a> 5789 <a class="trade row" href="https://talkify.nz/chinese-takeaway"> 5790 <svg class="mark" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"> 5791 <path d="M4 5.5a2 2 0 0 1 2-2h2.2l1.6 3.9-1.9 1.4a12 12 0 0 0 5.3 5.3l1.4-1.9 3.9 1.6V16a2 2 0 0 1-2 2A13.5 13.5 0 0 1 4 5.5z"/> 5792 </svg> 5793 <h3>Chinese takeaways</h3> 5794 <p>The same phone problem with longer orders and more questions about what is in a dish.</p> 5795 <span class="go"><span>Next door</span> <em>→</em></span> 5796 </a> 5797 </div> 5798</section> 5799 5800<section class="endcta endcta-has-form" id="endcta"> 5801 <div class="endcta-photo" aria-hidden="true"></div> 5802 5803 5804 <div class="endcta-wrap" id="signup"> 5805 <div class="endcta-pitch"> 5806 <div class="stamp">TWO WAYS TO HEAR THE AGENT</div> 5807 <h2>Ring it like a customer.<br><span class="it">Order two scoops.</span></h2> 5808 5809 <div class="endcta-numbers"> 5810 <a href="tel:+6432421262" class="num-big" data-talkify-agent="default" 5811 title="Hear the agent yourself"> 5812 <span class="ic ic-demo"> 5813 <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" 5814 stroke-linecap="round"><path 5815 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> 5816 </span> 5817 <span> 5818 <small>Hear it yourself · our AI agent, 24/7 · ask it anything</small> 5819 03 242 1262 5820 </span> 5821 </a> 5822 5823 <a href="tel:+64800002967" class="num-big num-blue" title="Sign up, sales and support"> 5824 <span class="ic ic-signup"> 5825 <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" 5826 stroke-linecap="round"><path 5827 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> 5828 </span>
5829 <span> 5830 <small>Sign up, sales & support · we'll set you up</small> 5831 0800 002 967 5832 </span> 5833 </a> 5834 </div> 5835 5836 <div class="endcta-meta"> 5837 <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> 5838 5839 5840 <div class="endcta-alt"> 5841 <a href="sms:+64272048827" class="btn btn-ghost btn-lg" 5842 title="Text us instead of ringing"> 5843 <svg width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" 5844 stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" style="flex:none"> 5845 <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"/> 5846 </svg> 5847 Text our agent · 027 204 8827 </a> 5848 </div> 5849 5850 5851 <p class="endcta-app-line">Or run it from your pocket</p> 5852 <div class="app-stores" style="--app-badge-h: 46px"> 5853 <a class="app-badge" href="https://apps.apple.com/nz/app/talkify-mobile/id6766709308" 5854 target="_blank" rel="noopener"> 5855 <img src="https://talkify.nz/media/branding/apple-app-store.svg" 5856 alt="Download Talkify Mobile on the App Store" 5857 width="137.6" height="46" loading="lazy"> 5858 </a> 5859 <a class="app-badge" href="https://play.google.com/store/apps/details?id=com.talkifynz.app" 5860 target="_blank" rel="noopener"> 5861 <img src="https://talkify.nz/media/branding/google-app-store.svg" 5862 alt="Get Talkify Mobile on Google Play" 5863 width="155.3" height="46" loading="lazy"> 5864 </a> 5865</div> 5866 </div> 5867 5868 <div class="endcta-form"> 5869 5870 <span class="eyebrow"><span class="pin"></span>Get your first agent · No card needed </span> 5871 5872 <form method="POST" action="https://talkify.nz/contact" class="form"> 5873 <input type="hidden" name="_token" value="5MGekG5aEnJLziD1RYXq2wNDu47KXOfVE2QXDqz4" autocomplete="off"> <div class="row"> 5874 <div class="field"> 5875 <label>Your name</label> 5876 <input type="text" name="name" required placeholder="Your full name" autocomplete="name" value=""> 5877 </div> 5878 <div class="field"> 5879 <label>Company</label> 5880 <input type="text" name="company" required placeholder="Your company" autocomplete="organization" value=""> 5881 </div> 5882 </div> 5883 <div class="row"> 5884 <div class="field"> 5885 <label>Email</label> 5886 <input type="email" name="email" required placeholder="Your email" autocomplete="email" value=""> 5887 </div> 5888 <div class="field"> 5889 <label>Mobile (NZ)</label> 5890 <input type="tel" name="phone" required placeholder="Your mobile" autocomplete="tel" value=""> 5891 </div> 5892 </div> 5893 <div class="field"> 5894 <label for="country-signup">Country</label> 5895 <select name="country" id="country-signup" required data-country-select autocomplete="country"> 5896 <option value="" disabled selected>Select your country</option> 5897 <option value="NZ" >New Zealand</option> 5898 <option value="AU" >Australia</option> 5899 </select> 5900 <p style="margin-top:8px;font-family:var(--mono);font-size:11px;letter-spacing:.04em;color:var(--mute)"> 5901 Talkify is currently available to businesses in New Zealand & Australia only. 5902 </p> 5903</div> 5904 5905 5906<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"> 5907 <input type="text" name="company_reference" tabindex="-1" autocomplete="off" value="" aria-hidden="true"> 5908</div> 5909
5910<script> 5911(function () { 5912 var script = document.currentScript; 5913 var form = script && script.closest('form'); 5914 if (!form) return; 5915 var select = form.querySelector('select[name="country"]'); 5916 if (!select || select.value) return; // respect old() / a choice already made 5917 5918 try { 5919 var tz = (Intl.DateTimeFormat().resolvedOptions().timeZone || '').toLowerCase(); 5920 var lang = (navigator.language || '').toLowerCase(); 5921 var code = null; 5922 5923 if (tz.indexOf('auckland') >= 0 || tz.indexOf('chatham') >= 0 || lang === 'en-nz' || lang === 'mi') { 5924 code = 'NZ'; 5925 } else if (tz.indexOf('australia/') >= 0 || lang === 'en-au') { 5926 code = 'AU'; 5927 } 5928 5929 if (code) select.value = code; 5930 } catch (e) { /* detection is best-effort */ } 5931})(); 5932</script>
5932 5933 <div class="field"> 5934 <label>Pick your agent</label> 5935 <div class="radios"> 5936 <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> 5937 <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> 5938 <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> 5939 <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> 5940 <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> 5941 <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> 5942 <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> 5943 </div> 5944 <p class="plan-recommend" data-plan-recommend style="display:none"> 5945 We recommend running an incoming agent alongside an outgoing or campaign agent. People you ring will often ring you 5946 back, and an incoming agent makes sure those return calls are answered rather than missed. If you would 5947 rather not add one, we can clone your business caller ID so return calls come straight back to your 5948 existing phone. 5949 </p> 5950 </div> 5951 5952 <div class="field"> 5953 <label>How you want to pay</label> 5954 <div class="radios"> 5955 <label class="radio"> 5956 <input type="radio" name="plan" value="broadcast" checked> 5957 <span class="dot"></span> 5958 <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> 5959 </label> 5960 <label class="radio"> 5961 <input type="radio" name="plan" value="payg" > 5962 <span class="dot"></span> 5963 <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> 5964 </label> 5965 </div> 5966 </div> 5967 5968 <div class="plan-display" data-plan-display> 5969 <div class="plan-display-left"> 5970 <div class="plan-display-label" data-plan-label>Personal Assistant</div> 5971 <div class="plan-display-sub" data-plan-sub>Single mobile or landline. Built for one person, not a business.</div> 5972 </div> 5973 <div class="plan-display-right"> 5974 <div class="plan-display-price" data-plan-price>$89<small>/mo</small></div> 5975 <div class="plan-display-tier" data-plan-tier>Shortwave plan</div> 5976 <div class="plan-display-note" data-plan-note style="display:none" ></div> 5977 </div> 5978 </div> 5979 <p class="founding-line">
5980 <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. 5981 Plans include 50 to 200 minutes a month, then 10c a minute. The first 20 texts each month are free, then 9c each. 5982 </p> 5983 <p class="plan-asterisk" data-plan-asterisk style="display:none"> 5984 <span>*</span> Subject to your CRM or booking system. Additional implementation cost may apply for non-standard integrations. 5985 </p> 5986 5987 <div class="actions"> 5988 <span class="note">â Your data stays in NZ.</span> 5989 <button type="submit" class="btn btn-primary btn-lg">Create your first agent <span class="arr">â</span></button> 5990 </div> 5991 </form> 5992 5993
5993<script> 5994 (function () { 5995 // A plan only carries a crossed-out "was" price and a founding note while 5996 // its intro price is genuinely below its standard price; when the two 5997 // match in the pricing table both come through blank and the picker 5998 // shows a plain price. Per-call plans never have a founding step. 5999 const PA_NOTE = ""; 6000 const BIZ_NOTE = "Founding rate for your first 3 months, then $199/mo"; 6001 const PA_WAS = ""; 6002 const BIZ_WAS = "$199"; 6003 6004 const PLANS = { 6005 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 }, 6006 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 }, 6007 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 }, 6008 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 }, 6009 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 }, 6010 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 }, 6011 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 }, 6012 }; 6013 // The pay-as-you-go face of the same picker: whatever agent they chose, 6014 // the money side is the per-minute wallet, so the price panel follows 6015 // the payment choice rather than quoting a monthly plan. 6016 const PAYG = { 6017 price: '$1', 6018 suffix: '/min', 6019 tier: 'Pay as you go · $10/month covers your phone number', 6020 note: '$10 free credit to start, on top of the number. Calls and texts come off your prepaid balance.', 6021 }; 6022 const form = document.currentScript.closest('.endcta-form') || document; 6023 const radios = form.querySelectorAll('input[name="agent_type"]'); 6024 const payRadios = form.querySelectorAll('input[name="plan"]'); 6025 const labelEl = form.querySelector('[data-plan-label]'); 6026 const subEl = form.querySelector('[data-plan-sub]'); 6027 const priceEl = form.querySelector('[data-plan-price]'); 6028 const tierEl = form.querySelector('[data-plan-tier]'); 6029 const noteEl = form.querySelector('[data-plan-note]'); 6030 const astEl = form.querySelector('[data-plan-asterisk]'); 6031 const recEl = form.querySelector('[data-plan-rec
6031ommend]'); 6032 6033 function update(){ 6034 const checked = form.querySelector('input[name="agent_type"]:checked'); 6035 if (!checked) return; 6036 const plan = PLANS[checked.value]; 6037 if (!plan) return; 6038 const pay = form.querySelector('input[name="plan"]:checked'); 6039 const payg = pay && pay.value === 'payg'; 6040 labelEl.textContent = plan.label; 6041 subEl.textContent = plan.sub; 6042 priceEl.innerHTML = payg 6043 ? PAYG.price + '<small>' + PAYG.suffix + '</small>' 6044 : (plan.was ? '<s class="was-price">'+plan.was+'</s> ' : '') + plan.price + (plan.suffix ? '<small>'+plan.suffix+'</small>' : ''); 6045 tierEl.textContent = payg ? PAYG.tier : plan.tier; 6046 if (noteEl) { 6047 const note = payg ? PAYG.note : (plan.note || ''); 6048 noteEl.textContent = note; 6049 noteEl.style.display = note ? 'block' : 'none'; 6050 } 6051 astEl.style.display = (!payg && plan.asterisk) ? 'block' : 'none'; 6052 if (recEl) recEl.style.display = plan.recommend ? 'block' : 'none'; 6053 } 6054 radios.forEach(r => r.addEventListener('change', update)); 6055 payRadios.forEach(r => r.addEventListener('change', update)); 6056 update(); 6057 })(); 6058 </script>
6058 6059 </div> 6060 </div> 6061 6062 <style> 6063 /* Two top-ruled columns rather than two pills side by side. The pair is 6064 held to a readable measure and centred under the headline, so the 6065 block still reads as the close of the page even though the section 6066 itself is centred and these two are ruled and left-aligned. */ 6067 .endcta-numbers { 6068 display: grid; 6069 grid-template-columns: 1fr 1fr; 6070 gap: clamp(24px, 4vw, 56px); 6071 margin: 56px auto 0; 6072 max-width: 780px; 6073 text-align: left 6074 } 6075 6076 @media (max-width: 800px) { 6077 .endcta-numbers { 6078 grid-template-columns: 1fr; 6079 gap: 30px; 6080 max-width: 460px 6081 } 6082 } 6083 6084 .endcta-alt { 6085 margin-top: 36px; 6086 display: flex; 6087 flex-wrap: wrap; 6088 gap: 12px; 6089 justify-content: center 6090 } 6091 6092 /* The app line sits under the two ways to reach us and quieter than 6093 either, because it is aimed at people who have already signed up. */ 6094 .endcta-app-line { 6095 margin-top: 40px; 6096 font-family: var(--mono); 6097 font-size: 10px; 6098 letter-spacing: .18em; 6099 text-transform: uppercase; 6100 color: var(--mute) 6101 } 6102 6103 .endcta .app-stores { 6104 margin-top: 14px; 6105 justify-content: center 6106 } 6107 6108 /* ââ With the form in it âââââââââââââââââââââââââââââââââââââââââââ 6109 The pitch stops being a centred banner and becomes the left half 6110 of one closing block, with the get-started form on the right. No 6111 panel and no rounding: the two columns simply share the page. */ 6112 .endcta-has-form .endcta-wrap { 6113 display: grid; 6114 grid-template-columns: 1fr 1.05fr; 6115 gap: clamp(40px, 5vw, 76px); 6116 align-items: start; 6117 max-width: 1240px; 6118 margin: 0 auto; 6119 text-align: left 6120 } 6121 6122 /* The skyline sits behind a short centred banner comfortably. Behind 6123 a block three times as tall it runs up under the form fields and 6124 the price panel, where a photograph is just noise, so it is held 6125 well back and the scrim is carried the whole way down instead of 6126 fading out in the middle. */ 6127 .endcta.endcta-has-form .endcta-photo { 6128 opacity: .12; 6129 background-position: center bottom 6130 } 6131 6132 html[data-theme="light"] .endcta.endcta-has-form .endcta-photo { 6133 opacity: .16 6134 } 6135 6136 .endcta.endcta-has-form .endcta-photo::after { 6137 background: linear-gradient(180deg, var(--scrim-mid) 0%, var(--scrim-strong) 30%, var(--scrim-strong) 100%) 6138 } 6139 6140 .endcta-has-form .endcta-numbers { 6141 grid-template-columns: 1fr; 6142 gap: 26px; 6143 margin: 44px 0 0; 6144 max-width: none 6145 } 6146 6147 .endcta-has-form .endcta-meta { 6148 justify-content: flex-start; 6149 gap: 22px 6150 } 6151 6152 .endcta-has-form .endcta-alt, 6153 .endcta-has-form .app-stores { 6154 justify-content: flex-start 6155 } 6156 6157 .endcta-form .eyebrow { 6158 display: inline-flex; 6159 margin-bottom: 20px 6160 } 6161 6162 @media (max-width: 1000px) { 6163 .endcta-has-form .endcta-wrap { 6164 grid-template-columns: 1fr; 6165 gap: 48px 6166 } 6167 6168 .endcta-has-form .endcta-numbers { 6169 max-width: 460px 6170 } 6171 } 6172 6173 /* Carried over from the signup section this block absorbed: that 6174 partial's styles only ship on the page that includes it, and it 6175 is now only included by /v2. */ 6176 .signup-errors { 6177 margin-bottom: 18px; 6178 padding: 14px 0 14px 16px; 6179 border-left: 2px solid var(--coral); 6180 font-family: var(--mono); 6181 font-size: 12px; 6182 line-height: 1.6; 6183 color: var(--paper) 6184 } 6185 6186 .was-price { 6187 font-size: .55em; 6188 color: var(--mute-2); 6189 text-decoration: line-through; 6190 text-decoration-color: var(--coral); 6191 margin-right: 4px; 6192 font-weight: 300 6193 } 6194 6195 .founding-line { 6196 margin-top: 14px; 6197 font-family: var(--sans); 6198 font-size: 12px; 6199 line-height: 1.55; 6200 color: var(--mute) 6201 } 6202 6203 .founding-line .fl-tag { 6204 font-family: var(--mono); 6205 font-size: 10px; 6206 letter-spacing: .14em; 6207 text-transform: uppercase; 6208 color: var(--signal); 6209 margin-right: 8px 6210 } 6211 </style> 6212 </section> 6213 6214<style> 6215 .foot-social { 6216 display: inline-flex; 6217 align-items: center; 6218 gap: 8px; 6219 padding: 6px 0; 6220 font-family: var(--mono); 6221 font-size: 11px; 6222 color: var(--mute); 6223 letter-spacing: .06em; 6224 transition: color .25s var(--ease); 6225 } 6226 6227 .foot-social:hover { color: var(--paper); } 6228 6229 /* The badges sit tighter than the marketing rows and wrap rather than 6230 squeeze, because this column is the narrowest place they appear. */ 6231 .foot-apps { 6232 margin-top: 22px; 6233 gap: 10px; 6234 } 6235</style> 6236<footer class="foot"> 6237 <div class="foot-grid"> 6238 <div class="foot-brand"> 6239 6240 <a class="logo" href="https://talkify.nz" aria-label="Talkify, home" 6241 style="display:flex;align-items:center;gap:14px;color:inherit;text-decoration:none">
6242 <svg class="tk-logo" viewBox="-3 -3 317.81 106" 6243 width="125.92" height="42" 6244 xmlns="http://www.w3.org/2000/svg" role="img" aria-label="Talkify" focusable="false"> 6245 <circle cx="50" cy="50" r="50" fill="var(--tk-word, #101820)"/> 6246 6247 <g fill="none" stroke="var(--tk-ground, #ffffff)" stroke-width="10" stroke-linecap="round"> 6248 <path d="M34 26 V54 C34 74 62 80 76 62"/> 6249 <path d="M20 40 H46"/> 6250 </g> 6251 6252 <g transform="translate(56 20) scale(0.30)"> 6253 <g class="tk-eye"> 6254 <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)"/> 6255 </g> 6256 </g> 6257 <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"/> 6258 6259 <g transform="translate(231.30 6.84) scale(0.216)"> 6260 <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" 6261 fill="var(--tk-word, #101820)"/> 6262 </g> 6263 </svg> 6264 </a> 6265 <p>The voice operating system for New Zealand business. Built in Aotearoa, hosted in Aotearoa, working while 6266 you don't.</p> 6267 <div 6268 style="margin-top:20px;font-family:var(--mono);font-size:12px;color:var(--mute);letter-spacing:.06em;line-height:1.7"> 6269 <span style="color:var(--mute);font-size:10px;text-transform:uppercase;letter-spacing:.18em">Sign up by phone</span><br> 6270 <a href="tel:+64800002967" style="color:var(--bone);transition:.25s">0800 002 967</a><br> 6271 <span 6272 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> 6273 <a href="tel:+6432421262" data-talkify-agent="default" style="color:var(--bone);transition:.25s">03 242 1262</a> 6274 <br> 6275 <span 6276 style="color:var(--mute);font-size:10px;text-transform:uppercase;letter-spacing:.18em;margin-top:8px;display:inline-block">Text our agent</span><br> 6277 <a href="sms:+64272048827" style="color:var(--bone);transition:.25s">027 204 8827</a> 6278 </div> 6279 <div style="margin-top:20px;
6279display:flex;flex-wrap:wrap;gap:8px 22px;align-items:center"> 6280 <a href="https://www.facebook.com/profile.php?id=61572226258048" target="_blank" 6281 rel="noopener noreferrer" aria-label="Facebook" 6282 class="foot-social"> 6283 <svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor"> 6284 <path 6285 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"/> 6286 </svg> 6287 Facebook 6288 </a> 6289 <a href="https://www.instagram.com/talkifynz/" target="_blank" 6290 rel="noopener noreferrer" aria-label="Instagram" 6291 class="foot-social"> 6292 <svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor"> 6293 <path 6294 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"/> 6295 </svg> 6296 Instagram 6297 </a> 6298 <a href="https://www.linkedin.com/company/talkify-nz/" target="_blank" 6299 rel="noopener noreferrer" aria-label="LinkedIn" 6300 class="foot-social"> 6301 <svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor"> 6302 <path 6303 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"/> 6304 </svg> 6305 LinkedIn 6306 </a> 6307 </div> 6308 6309 6310 <div class="app-stores foot-apps" style="--app-badge-h: 38px"> 6311 <a class="app-badge" href="https://apps.apple.com/nz/app/talkify-mobile/id6766709308" 6312 target="_blank" rel="noopener"> 6313 <img src="https://talkify.nz/media/branding/apple-app-store.svg" 6314 alt="Download Talkify Mobile on the App Store" 6315 width="113.7" height="38" loading="lazy"> 6316 </a> 6317 <a class="app-badge" href="https://play.google.com/store/apps/details?id=com.talkifynz.app" 6318 target="_blank" rel="noopener"> 6319 <img src="https://talkify.nz/media/branding/google-app-store.svg" 6320 alt="Get Talkify Mobile on Google Play" 6321 width="128.3" height="38" loading="lazy"> 6322 </a> 6323</div> 6324 </div> 6325 <div> 6326 <h4>Agents</h4> 6327 <ul> 6328 <li><a href="https://talkify.nz/reception">Reception</a></li> 6329 <li><a href="https://talkify.nz/personal-assistant">Personal Assistant</a></li> 6330 <li><a href="https://talkify.nz/booking-service">Booking Service</a></li> 6331 <li><a href="https://talkify.nz/sales-agent">Sales Agent</a></li> 6332 <li><a href="https://talkify.nz/ai-phone-surveys">Campaign Agent</a></li> 6333 <li><a href="https://talkify.nz/debt-collection">Debt Collection</a></li> 6334 <li><a href="https://talkify.nz/ai-wellness-checks">Wellness Checks</a></li> 6335 <li>
6335<a href="https://talkify.nz/outbound-calls">Outbound Calls</a></li> 6336 <li><a href="https://talkify.nz/ai-marketing-campaigns">Marketing Campaigns</a></li> 6337 <li><a href="https://talkify.nz/website-chat">Website Chat</a></li> 6338 <li><a href="https://talkify.nz/calendar">Team Calendar</a></li> 6339 <li><a href="https://talkify.nz/dialler">Dialler</a></li> 6340 <li><a href="https://talkify.nz/agents">All agents →</a></li> 6341 </ul> 6342 </div> 6343 6344 <div> 6345 <h4>Trades</h4> 6346 <ul> 6347 <li><a href="https://talkify.nz/plumber">Plumbing</a></li> 6348 <li><a href="https://talkify.nz/electrician">Electricians</a></li> 6349 <li><a href="https://talkify.nz/builder">Builders</a></li> 6350 <li><a href="https://talkify.nz/hvac">Heat Pump & HVAC</a></li> 6351 <li><a href="https://talkify.nz/automotive">Mechanics & Workshops</a></li> 6352 <li><a href="https://talkify.nz/landscaping">Landscaping</a></li> 6353 <li><a href="https://talkify.nz/pest-control">Pest Control</a></li> 6354 <li><a href="https://talkify.nz/tradesman">All Trades</a></li> 6355 </ul> 6356 </div> 6357 <div> 6358 <h4>Industries</h4> 6359 <ul> 6360 <li><a href="https://talkify.nz/beauty">Beauty & Wellness</a></li> 6361 <li><a href="https://talkify.nz/real-estate">Real Estate</a></li> 6362 <li><a href="https://talkify.nz/retail">Retail</a></li> 6363 <li><a href="https://talkify.nz/professional-services">Professional Services</a></li> 6364 <li><a href="https://talkify.nz/barber">Barbers</a></li> 6365 <li><a href="https://talkify.nz/gym">Gyms & Studios</a></li> 6366 <li><a href="https://talkify.nz/personal-trainer">Personal Trainers</a></li> 6367 <li><a href="https://talkify.nz/hotel">Hotels & Motels</a></li> 6368 <li><a href="https://talkify.nz/accountant">Accountants</a></li> 6369 <li><a href="https://talkify.nz/industries">All industries →</a></li> 6370 </ul> 6371 </div> 6372 <div> 6373 6374 <h4>Call answering</h4> 6375 <ul> 6376 <li><a href="https://talkify.nz">AI receptionist NZ</a></li> 6377 <li><a href="https://talkify.nz/ai-phone-agent">AI phone agent NZ</a></li> 6378 <li><a href="https://talkify.nz/virtual-receptionist">Virtual receptionist NZ</a></li> 6379 <li><a href="https://talkify.nz/ai-answering-service">AI answering service NZ</a></li> 6380 <li><a href="https://talkify.nz/after-hours-answering">After hours answering NZ</a></li> 6381 <li><a href="https://talkify.nz/on-call-roster">On-Call Roster</a></li> 6382 <li><a href="https://talkify.nz/ai-call-centre">AI Call Centre Agents</a></li> 6383 <li><a href="https://talkify.nz/business-phone-lines">Business Phone Lines</a></li> 6384 6385 <li style="margin-top:6px;color:var(--mute);line-height:1.8"> 6386 By city: 6387 <a 6388 href="https://talkify.nz/ai-receptionist-auckland">Auckland</a><span 6389 style="color:var(--line-2)"> · </span><a 6390 href="https://talkify.nz/ai-receptionist-wellington">Wellington</a><span 6391 style="color:var(--line-2)"> · </span><a 6392 href="https://talkify.nz/ai-receptionist-christchurch">Christchurch</a><span 6393 style="color:var(--line-2)"> · </span><a 6394 href="https://talkify.nz/ai-receptionist-hamilton">Hamilton</a><span 6395 style="color:var(--line-2)"> · </span><a 6396 href="https://talkify.nz/ai-receptionist-tauranga">Tauranga</a><span 6397 style="color:var(--line-2)"> · </span><a 6398 href="https://talkify.nz/ai-receptionist-dunedin">Dunedin</a> </li> 6399 </ul> 6400 </div> 6401 <div> 6402 6403 <h4>Company</h4> 6404 <ul> 6405 <li><a href="https://talkify.nz/pricing">Pricing</a></li> 6406 <li><a href="https://talkify.nz/integrations">Integrations</a></li> 6407 6408 <li><a href="https://talkify.nz/compare">Compare Providers</a><span 6409 style="color:var(--line-2)"> · </span><a 6410 href="https://talkify.nz/alternatives">Alternatives</a></li> 6411 <li><a href="https://talkify.nz/missed-call-calculator">Missed Call Calculator</a></li> 6412 <li><a href="https://talkify.nz/blog">Journal</a></li> 6413 6414 <li><a href="https://talkify.nz/help">Help centre</a><span 6415 style="color:var(--line-2)"> · </span><a 6416 href="https://talkify.nz/contact-us">Contact us</a></li> 6417 <li><a href="https://talkify.nz/demo">Live demo</a></li> 6418 <li><a href="https://talkify.nz/signup">Get started</a></li> 6419 </ul> 6420 </div> 6421 </div> 6422 <div class="foot-bot">
6423 <span>© <span id="year">2026</span> · Talkify Limited · NZ owned and hosted</span> 6424 <span> 6425 6426 <span aria-current="page">New Zealand</span> · <a href="https://talkify.nz/au" style="color:var(--bone)">Australia</a> · 6427 <a href="https://talkify.nz/privacy" style="color:var(--bone)">Privacy</a> · 6428 <a href="https://talkify.nz/terms" style="color:var(--bone)">Terms</a> · 6429 <a href="https://talkify.nz/support" style="color:var(--bone)">Support</a> · 6430 <a href="https://talkify.nz/login" style="color:var(--bone)">Sign in</a> 6431 · <a href="https://d3v.nz" style="color:var(--bone)">Made by D3V</a> 6432 </span> 6433 </div> 6434</footer> 6435 6436 6437 6438 6439 6440 6441 6442 6443 6444
6445<script> 6446 function tick() { 6447 const d = new Date(); 6448 const f = new Intl.DateTimeFormat('en-NZ', { 6449 timeZone: 'Pacific/Auckland', 6450 hour: '2-digit', 6451 minute: '2-digit', 6452 second: '2-digit', 6453 hour12: false 6454 }); 6455 const el = document.getElementById('clock'); 6456 if (el) el.textContent = f.format(d); 6457 } 6458 6459 tick(); 6460 setInterval(tick, 1000); 6461 const yEl = document.getElementById('year'); 6462 if (yEl) yEl.textContent = new Date().getFullYear(); 6463 6464 /* Scroll reveal. Fires once per block. Anybody who has asked for less 6465 motion, and any browser without IntersectionObserver, gets the lot 6466 revealed immediately rather than a page of invisible sections. */ 6467 (function () { 6468 const blocks = document.querySelectorAll('.r'); 6469 if (!blocks.length) return; 6470 const reduce = window.matchMedia 6471 && window.matchMedia('(prefers-reduced-motion: reduce)').matches; 6472 if (reduce || !('IntersectionObserver' in window)) { 6473 blocks.forEach(el => el.classList.add('in')); 6474 return; 6475 } 6476 const io = new IntersectionObserver((entries) => { 6477 entries.forEach(e => { 6478 if (e.isIntersecting) { 6479 e.target.classList.add('in'); 6480 io.unobserve(e.target); 6481 } 6482 }); 6483 }, {rootMargin: '-8% 0px -5% 0px'}); 6484 blocks.forEach(el => io.observe(el)); 6485 })(); 6486 6487 /* Agent phones. Each opens on a plain lock screen, then the clock drops to 6488 its compact size and the notifications land on top of it, which is the 6489 order an iPhone does it in. Plays once, when the panel is on screen. 6490 6491 The clock is the VISITOR'S OWN time and every stamp is counted back from 6492 it, so a screen can never show a notification that arrived after the time 6493 printed above it. Nothing is written into the markup, so a cached page 6494 cannot go stale either. 6495 6496 The tilt and the sheen are a couple of degrees and a highlight eased 6497 across the viewport. Both are off on coarse pointers, where there is no 6498 hover to reward them and the scroll handler is pure cost, and the whole 6499 thing collapses to "already arrived" under prefers-reduced-motion. */ 6500 (function () { 6501 const phones = [...document.querySelectorAll('[data-agent-phone]')]; 6502 if (!phones.length) return; 6503 6504 const clockOf = d => d.toLocaleTimeString('en-NZ', {hour: 'numeric', minute: '2-digit', hour12: false}); 6505 const stampOf = d => d.toLocaleTimeString('en-NZ', {hour: 'numeric', minute: '2-digit', hour12: true}) 6506 .replace(/\s/g, '').toLowerCase(); 6507 const dateOf = d => d.toLocaleDateString('en-NZ', {weekday: 'long', day: 'numeric', month: 'long'}); 6508 6509 const still = matchMedia('(prefers-reduced-motion: reduce)').matches; 6510 const coarse = matchMedia('(pointer: coarse)').matches; 6511 6512 phones.forEach(phone => { 6513 // A phone may pin its own clock with data-agent-at="HH:MM". The 6514 // after-hours story is an escalation at a quarter to midnight, and 6515 // stamped 2pm on a daytime visitor's own clock it reads as 6516 // nonsense. Everything else still shows the visitor's real time, 6517 // counted back from, so nothing arrives after the clock above it. 6518 const now = new Date(); 6519 const pinned = (phone.dataset.agentAt || '').match(/^(\d{1,2}):(\d{2})$/); 6520 if (pinned) now.setHours(+pinned[1], +pinned[2], 0, 0); 6521 6522 const t = phone.querySelector('[data-agent-time]'); 6523 const dt = phone.querySelector('[data-agent-date]'); 6524 if (t) t.textContent = clockOf(now); 6525 if (dt) dt.textContent = dateOf(now); 6526 6527 phone.querySelectorAll('[data-agent-ago]').forEach(el => { 6528 const mins = parseInt(el.dataset.agentAgo, 10); 6529 if (!Number.isFinite(mins)) return; 6530 el.textContent = stampOf(new Date(now.getTime() - mins * 60000)); 6531 }); 6532 6533 const clock = phone.querySelector('[data-agent-clock]'); 6534 const notes = [...phone.querySelectorAll('.hpn')]; 6535 if (!clock || !notes.length) return; 6536 6537 if (still) { 6538 clock.classList.add('is-compact');
6539 notes.forEach(n => n.classList.add('is-in')); 6540 return; 6541 } 6542 6543 let played = false; 6544 const play = () => { 6545 if (played) return; 6546 played = true; 6547 setTimeout(() => clock.classList.add('is-compact'), 420); 6548 notes.forEach((n, i) => setTimeout(() => n.classList.add('is-in'), 780 + i * 380)); 6549 }; 6550 6551 const io = new IntersectionObserver(entries => { 6552 entries.forEach(e => { 6553 if (!e.isIntersecting) return; 6554 play(); 6555 io.unobserve(phone); 6556 }); 6557 }, {threshold: .35}); 6558 io.observe(phone); 6559 6560 if (coarse) return; 6561 6562 const lean = phone.classList.contains('agent-phone--left') ? -1 : 1; 6563 let queued = false; 6564 const tilt = () => { 6565 queued = false; 6566 const r = phone.getBoundingClientRect(); 6567 if (r.bottom < 0 || r.top > innerHeight) return; 6568 // -0.5 above the fold, +0.5 below it 6569 const p = (r.top + r.height / 2 - innerHeight / 2) / innerHeight; 6570 phone.style.setProperty('--ag-tilt', (lean * (3 - p * 4.5)).toFixed(2) + 'deg'); 6571 phone.style.setProperty('--ag-sheen', (p * -150).toFixed(1) + '%'); 6572 }; 6573 addEventListener('scroll', () => { 6574 if (queued) return; 6575 queued = true; 6576 requestAnimationFrame(tilt); 6577 }, {passive: true}); 6578 tilt(); 6579 }); 6580 })(); 6581 6582 6583 /* Hero phone. The chips are the data source, so the markup stays the one 6584 place the copy lives. Cycling pauses the moment the visitor takes over, 6585 and never starts at all under prefers-reduced-motion. */ 6586 (function () { 6587 const root = document.querySelector('[data-hp-stack]'); 6588 if (!root) return; 6589 const chips = [...document.querySelectorAll('[data-hp-chip]')]; 6590 if (!chips.length) return; 6591 6592 const reduce = window.matchMedia('(prefers-reduced-motion: reduce)').matches; 6593 const icon = document.querySelector('.hpn header img'); 6594 const iconSrc = icon ? icon.getAttribute('src') : ''; 6595 let i = 0, timer = null, taken = false; 6596 6597 // the phone shows the viewer's own clock, so it reads as their phone 6598 // rather than a screenshot taken at some other time 6599 const clock = () => { 6600 const now = new Date(); 6601 const t = document.querySelector('[data-hp-time]'); 6602 const d = document.querySelector('[data-hp-date]'); 6603 if (t) t.textContent = now.toLocaleTimeString('en-NZ', {hour: 'numeric', minute: '2-digit'}) 6604 .replace(/\s?(am|pm)$/i, ''); 6605 if (d) d.textContent = now.toLocaleDateString('en-NZ', {weekday: 'long', day: 'numeric', month: 'long'}); 6606 }; 6607 6608 const AGO = ['now', '2m ago', '8m ago']; 6609 6610 const build = (chip) => { 6611 const frag = document.createDocumentFragment(); 6612 // two or three per screen: one card at a time made the phone look 6613 // idle, and a digest is the thing being sold 6614 [['title', 'body'], ['title2', 'body2'], ['title3', 'body3']].forEach((keys, i) => { 6615 const title = chip.dataset[keys[0]], body = chip.dataset[keys[1]]; 6616 if (!title) return; 6617 const n = document.createElement('article'); 6618 n.className = 'hpn'; 6619 n.style.transitionDelay = (i * 620) + 'ms'; 6620 n.innerHTML = 6621 '<header><img src="' + iconSrc + '" alt="" width="18" height="18">' + 6622 '<span class="hpn-app">Talkify</span><span class="hpn-ago"></span></header>' + 6623 '<h4></h4><p></p>'; 6624 n.querySelector('.hpn-ago').textContent = AGO[i] || 'earlier'; 6625 n.querySelector('h4').textContent = title; 6626 n.querySelector('p').textContent = body; 6627 frag.appendChild(n); 6628 }); 6629 return frag; 6630 }; 6631 6632 const show = (idx) => { 6633 i = (idx + chips.length) % chips.length; 6634 chips.forEach((c, n) => c.classList.toggle('is-on', n === i)); 6635 chips.forEach((c, n) => c.setAttribute('aria-selected', n === i ? 'true' : 'false')); 6636 root.replaceChildren(build(chips[i])); 6637 // let the browser paint the start state before transitioning in 6638 requestAnimationFrame(() => requestAnimationFrame(() => 6639 root.querySelectorAll('.hpn').forEach(n => n.classList.add('is-in')))); 6640 }; 6641 6642 const stop = () => { if (timer) { clearInterval(timer); timer = null; } }; 6643 const start = () => { if (!reduce && !taken && !timer) timer = setInterval(() => show(i + 1), 7000); }; 6644 6645 chips.forEach((chip, n) => { 6646 const take = () => { taken = true; stop(); show(n); }; 6647 chip.addEventListener('click', take); 6648 chip.addEventListener('mouseenter', () => { stop(); show(n); }); 6649 chip.addEventListener('mouseleave', () => { if (!taken) start(); }); 6650 }); 6651 6652 // do not animate a phone nobody is looking at 6653 const vis = new IntersectionObserver((es) => {
6654 es.forEach(e => e.isIntersecting ? start() : stop()); 6655 }, {threshold: 0.2}); 6656 vis.observe(root); 6657 6658 clock(); 6659 setInterval(clock, 30000); 6660 show(0); 6661 })(); 6662 6663 (function () { 6664 const hero = document.querySelector('.hero-bg'); 6665 if (!hero) return; 6666 // Pointer parallax is a mouse affordance: a finger cannot hover, and 6667 // it is exactly the sort of movement prefers-reduced-motion is for. 6668 const mq = (q) => window.matchMedia && window.matchMedia(q).matches; 6669 if (mq('(prefers-reduced-motion: reduce)') || mq('(pointer: coarse)')) return; 6670 6671 let x = 0, y = 0, queued = false; 6672 const paint = () => { 6673 queued = false; 6674 hero.style.transform = `translate(${x}px,${y}px)`; 6675 }; 6676 document.addEventListener('mousemove', (e) => { 6677 x = (e.clientX / window.innerWidth - .5) * 24; 6678 y = (e.clientY / window.innerHeight - .5) * 24; 6679 if (!queued) { 6680 queued = true; 6681 requestAnimationFrame(paint); 6682 } 6683 }, {passive: true}); 6684 })(); 6685 6686 // âââ Live call deck, messages animate in as if the call is happening now âââ 6687 (function () { 6688 document.querySelectorAll('.deck').forEach(deck => { 6689 const rows = Array.from(deck.querySelectorAll('.deck-row')); 6690 if (!rows.length) return; 6691 6692 // Insert a typing indicator before each agent row 6693 rows.forEach(row => { 6694 if (row.classList.contains('agent')) { 6695 const ts = row.querySelector('.ts')?.textContent || ''; 6696 const typing = document.createElement('div'); 6697 typing.className = 'deck-typing'; 6698 typing.innerHTML = `<span class="ts">${ts}</span><span class="who">Talkify</span><span class="dotset"><i></i><i></i><i></i></span>`; 6699 row.parentNode.insertBefore(typing, row); 6700 } 6701 }); 6702 6703 let started = false; 6704 const start = () => { 6705 if (started) return; 6706 started = true; 6707 let t = 400; 6708 rows.forEach(row => { 6709 if (row.classList.contains('agent')) { 6710 const typing = row.previousElementSibling; 6711 if (typing && typing.classList.contains('deck-typing')) { 6712 setTimeout(() => typing.classList.add('on'), t); 6713 t += 900; 6714 setTimeout(() => typing.classList.remove('on'), t); 6715 t += 200; 6716 } 6717 } 6718 setTimeout(() => row.classList.add('in'), t); 6719 t += 1200; 6720 }); 6721 6722 // After the prepared script plays, optionally append a follow-up exchange 6723 const followup = deck.dataset.followup; 6724 if (followup === 'on') { 6725 setTimeout(() => { 6726 appendDeckExchange(deck); 6727 }, t + 1500); 6728 } 6729 }; 6730 6731 const io = new IntersectionObserver(entries => { 6732 entries.forEach(e => { 6733 if (e.isIntersecting) { 6734 start(); 6735 io.unobserve(deck); 6736 } 6737 }); 6738 }, {threshold: 0.25}); 6739 io.observe(deck); 6740 }); 6741 6742 function appendDeckExchange(deck) { 6743 // Append one extra caller + agent exchange to the home hero deck 6744 const followups = [ 6745 { 6746 caller: "One more thing, can my partner come too?", 6747 agent: "Of course. I'll add them to the appointment. Anything else?" 6748 }, 6749 { 6750 caller: "Is there parking?", 6751 agent: "Yep, two-hour free parking on Vivian Street, or paid building parking off the lobby." 6752 }, 6753 ]; 6754 const ex = followups[Math.floor(Math.random() * followups.length)]; 6755 const wave = deck.querySelector('.wave'); 6756 const insertBefore = wave || deck.querySelector('.deck-foot'); 6757 6758 const lastTs = deck.querySelectorAll('.deck-row .ts'); 6759 const baseSec = parseInt((lastTs[lastTs.length - 1]?.textContent || '00:14').split(':')[1]) + 6; 6760 const fmtTs = s => `00:${String(s).padStart(2, '0')}`; 6761 6762 const callerRow = document.createElement('div'); 6763 callerRow.className = 'deck-row caller'; 6764 callerRow.innerHTML = `<span class="ts">${fmtTs(baseSec)}</span><span class="who">Caller</span><span class="msg">${ex.caller}</span>`;
6765 deck.insertBefore(callerRow, insertBefore); 6766 6767 const typingRow = document.createElement('div'); 6768 typingRow.className = 'deck-typing'; 6769 typingRow.innerHTML = `<span class="ts">${fmtTs(baseSec + 2)}</span><span class="who">Talkify</span><span class="dotset"><i></i><i></i><i></i></span>`; 6770 deck.insertBefore(typingRow, insertBefore); 6771 6772 const agentRow = document.createElement('div'); 6773 agentRow.className = 'deck-row agent'; 6774 agentRow.innerHTML = `<span class="ts">${fmtTs(baseSec + 3)}</span><span class="who">Talkify</span><span class="msg">${ex.agent}</span>`; 6775 deck.insertBefore(agentRow, insertBefore); 6776 6777 requestAnimationFrame(() => callerRow.classList.add('in')); 6778 setTimeout(() => typingRow.classList.add('on'), 1100); 6779 setTimeout(() => typingRow.classList.remove('on'), 2400); 6780 setTimeout(() => agentRow.classList.add('in'), 2500); 6781 } 6782 })(); 6783 6784 // âââ Real conversations, bubbles type into existence as user scrolls in âââ 6785 (function () { 6786 document.querySelectorAll('.convo').forEach(convo => { 6787 const bubs = Array.from(convo.querySelectorAll('.bub')); 6788 if (!bubs.length) return; 6789 6790 let started = false; 6791 const start = () => { 6792 if (started) return; 6793 started = true; 6794 6795 let t = 200; 6796 bubs.forEach((bub) => { 6797 // Show typing indicator with the same alignment + colour, then swap to bubble 6798 const typing = document.createElement('div'); 6799 typing.className = 'convo-typing' + (bub.classList.contains('caller') ? ' caller' : ''); 6800 const who = bub.classList.contains('caller') ? 'Caller' : 'Talkify'; 6801 typing.innerHTML = `<span class="lbl">${who}</span><span class="dotset"><i></i><i></i><i></i></span>`; 6802 convo.insertBefore(typing, bub); 6803 6804 const typingMs = bub.classList.contains('caller') ? 500 : 800; 6805 setTimeout(() => typing.classList.add('on'), t); 6806 t += typingMs; 6807 setTimeout(() => { 6808 typing.classList.remove('on'); 6809 typing.remove(); 6810 }, t); 6811 setTimeout(() => bub.classList.add('in'), t + 50); 6812 t += 450; // settle time before next message 6813 }); 6814 }; 6815 6816 /* Watch the transcript's wrapper where it has one. On the home page 6817 the transcript sits inside a phone, and a clipped flex child that 6818 deep gets no intersection entries at all, so a threshold against 6819 the transcript itself never fires and the conversation never 6820 starts. The wrapper is an ordinary block in normal flow. */ 6821 const target = convo.closest('.convo-device') || convo; 6822 const io = new IntersectionObserver(entries => { 6823 entries.forEach(e => { 6824 if (e.isIntersecting) { 6825 start(); 6826 io.unobserve(target); 6827 } 6828 }); 6829 }, {threshold: 0.2}); 6830 io.observe(target); 6831 }); 6832 })(); 6833 6834 // âââ Live PA digest, notifications drop in on scroll, more arrive as you watch âââ 6835 (function () { 6836 document.querySelectorAll('.pa-floater').forEach(floater => { 6837 const initialRows = Array.from(floater.querySelectorAll('.row')); 6838 if (!initialRows.length) return; 6839 6840 const queue = [ 6841 { 6842 lbl: 'Returning client · routed', 6843 name: 'Liam, message taken for Tom', 6844 meta: '<span class="vip" style="color:var(--mute)">â Routine</span>' 6845 }, 6846 { 6847 lbl: 'New booking', 6848 name: 'Te Aroha · Saturday haircut', 6849 meta: '<span class="vip" style="color:var(--signal)">â Booked</span>' 6850 }, 6851 { 6852 lbl: 'Urgent · escalated to mobile', 6853 name: 'Maria @ Hartwell, sent to your phone', 6854 meta: '<span class="vip" style="color:var(--coral)">â VIP</span>' 6855 }, 6856 {lbl: 'Quietly handled', name: '14 vendors politely declined', meta: ''}, 6857 ]; 6858 let qIdx = 0; 6859 let started = false;
6860 6861 const start = () => { 6862 if (started) return; 6863 started = true; 6864 initialRows.forEach((row, i) => { 6865 setTimeout(() => { 6866 row.classList.add('in', 'ping'); 6867 setTimeout(() => row.classList.remove('ping'), 1400); 6868 }, i * 1200 + 400); 6869 }); 6870 6871 // After initial settle, push a new notification every 9 seconds 6872 const settled = initialRows.length * 1200 + 2000; 6873 setTimeout(() => { 6874 const interval = setInterval(() => { 6875 if (!floater.isConnected) { 6876 clearInterval(interval); 6877 return; 6878 } 6879 const item = queue[qIdx % queue.length]; 6880 qIdx++; 6881 const newRow = document.createElement('div'); 6882 newRow.className = 'row in fresh ping'; 6883 newRow.innerHTML = ` 6884 <span class="lbl">${item.lbl}</span> 6885 <span class="name">${item.name}</span> 6886 ${item.meta ? '<span>' + item.meta + '</span>' : ''} 6887 `; 6888 floater.insertBefore(newRow, floater.firstChild); 6889 6890 // Drop the oldest if we have too many, keep card from growing 6891 const all = floater.querySelectorAll('.row'); 6892 if (all.length > 4) { 6893 const oldest = all[all.length - 1]; 6894 oldest.style.transition = 'opacity .5s ease, transform .5s ease, max-height .5s ease, margin .5s ease, padding .5s ease'; 6895 oldest.style.opacity = '0'; 6896 oldest.style.transform = 'translateY(8px)'; 6897 setTimeout(() => oldest.remove(), 600); 6898 } 6899 6900 setTimeout(() => newRow.classList.remove('ping'), 1400); 6901 }, 9000); 6902 }, settled); 6903 }; 6904 6905 const io = new IntersectionObserver(entries => { 6906 entries.forEach(e => { 6907 if (e.isIntersecting) { 6908 start(); 6909 io.unobserve(floater); 6910 } 6911 }); 6912 }, {threshold: 0.3}); 6913 io.observe(floater); 6914 }); 6915 })(); 6916 6917 // âââ Conversion + engagement events â GA4 / GTM dataLayer âââ 6918 // Every tel: tap, CTA click and lead form submit lands in the dataLayer so 6919 // GTM/GA4 can build conversions without touching the templates again. 6920 (function () { 6921 const page = "industry-fish-and-chips"; 6922 const push = (event, params) => { 6923 window.dataLayer = window.dataLayer || []; 6924 window.dataLayer.push(Object.assign({event: event, page_key: page}, params || {})); 6925 }; 6926 6927 // Phone taps: the demo line and the sign-up lines are separate conversions. 6928 // The demo lines come from App\Services\Market (they differ by country 6929 // and by how a visitor has to dial them), matched on their last eight 6930 // digits so the local and the international form are the same line. 6931 const demoTails = ["32421262","92420020"]; 6932 document.querySelectorAll('a[href^="tel:"]').forEach(a => { 6933 a.addEventListener('click', () => { 6934 const num = (a.getAttribute('href') || '').replace('tel:', ''); 6935 const digits = num.replace(/\D/g, ''); 6936 const isDemo = demoTails.some(t => t && digits.endsWith(t)); 6937 push(isDemo ? 'demo_call_click' : 'phone_signup_click', { 6938 phone_number: num, 6939 link_text: (a.textContent || '').trim().slice(0, 80), 6940 }); 6941 }); 6942 }); 6943 6944 // CTA buttons (primary/blue/ghost), which CTA, on which page 6945 document.querySelectorAll('a.btn').forEach(a => { 6946 a.addEventListener('click', () => { 6947 push('cta_click', { 6948 cta_text: (a.textContent || '').trim().slice(0, 80), 6949 cta_style: a.classList.contains('btn-primary') ? 'primary' 6950 : a.classList.contains('btn-blue') ? 'blue' : 'ghost', 6951 cta_href: a.getAttribute('href') || '', 6952 }); 6953 }); 6954 }); 6955 6956 // Lead forms: signup/contact, live demo call, support 6957 document.querySelectorAll('form').forEach(form => { 6958 const action = form.getAttribute('action') || ''; 6959 let event = null; 6960 if (action.includes('/signup/verify')) event = 'sign_up'; 6961 else if (action.includes('/signup/send-code')) event = 'sign_up_start'; 6962 else if (action.includes('/contact')) event = 'generate_lead'; 6963 else if (action.includes('/demo')) event = 'demo_call_request';
6964 else if (action.includes('/support')) event = 'support_request'; 6965 if (!event) return; 6966 form.addEventListener('submit', () => { 6967 const agent = form.querySelector('input[name="agent_type"]:checked'); 6968 push(event, { 6969 form_action: action, 6970 agent_type: agent ? agent.value : undefined, 6971 }); 6972 }); 6973 }); 6974 })(); 6975 6976 /* Agents mega-menu. Desktop opens it on hover/focus via CSS; this handles 6977 the click path, which is the only way in on touch, plus Escape and 6978 click-outside. */ 6979 (function () { 6980 const drops = document.querySelectorAll('[data-nav-drop]'); 6981 if (!drops.length) return; 6982 6983 const closeAll = (except) => drops.forEach((drop) => { 6984 if (drop === except) return; 6985 drop.classList.remove('is-open'); 6986 drop.querySelector('.nav-drop-btn')?.setAttribute('aria-expanded', 'false'); 6987 }); 6988 6989 drops.forEach((drop) => { 6990 const trigger = drop.querySelector('.nav-drop-btn'); 6991 if (!trigger) return; 6992 6993 trigger.addEventListener('click', (event) => { 6994 event.preventDefault(); 6995 event.stopPropagation(); 6996 const open = drop.classList.toggle('is-open'); 6997 trigger.setAttribute('aria-expanded', open ? 'true' : 'false'); 6998 closeAll(drop); 6999 }); 7000 }); 7001 7002 document.addEventListener('click', (event) => { 7003 if (!event.target.closest('[data-nav-drop]')) closeAll(); 7004 }); 7005 7006 document.addEventListener('keydown', (event) => { 7007 if (event.key === 'Escape') closeAll(); 7008 }); 7009 7010 window.talkifyCloseNavDrops = closeAll; 7011 })(); 7012 7013 (function () { 7014 const btn = document.querySelector('.menu-btn'); 7015 const nav = document.querySelector('.nav ul'); 7016 if (!btn || !nav) return; 7017 btn.addEventListener('click', () => { 7018 const open = nav.style.display === 'flex'; 7019 // Collapsing the menu should not leave the Agents accordion open 7020 // behind it, or it reappears expanded next time. 7021 if (open && window.talkifyCloseNavDrops) window.talkifyCloseNavDrops(); 7022 nav.style.display = open ? 'none' : 'flex'; 7023 nav.style.position = 'fixed'; 7024 nav.style.top = '92px'; 7025 nav.style.left = '20px'; 7026 nav.style.right = '20px'; 7027 nav.style.flexDirection = 'column'; 7028 nav.style.background = 'var(--ink-2)'; 7029 nav.style.border = '1px solid var(--line)'; 7030 nav.style.borderRadius = '14px'; 7031 nav.style.padding = '12px'; 7032 nav.style.zIndex = '85'; 7033 }); 7034 })(); 7035 7036 /* Theme toggle, persist choice, flip data-theme on <html> */ 7037 (function () { 7038 var toggles = document.querySelectorAll('[data-theme-toggle]'); 7039 if (!toggles.length) return; 7040 toggles.forEach(function (btn) { 7041 btn.addEventListener('click', function () { 7042 var current = document.documentElement.getAttribute('data-theme') === 'light' ? 'light' : 'dark'; 7043 var next = current === 'light' ? 'dark' : 'light'; 7044 document.documentElement.setAttribute('data-theme', next); 7045 try { 7046 localStorage.setItem('talkify-theme', next); 7047 } catch (e) { 7048 } 7049 }); 7050 }); 7051 })(); 7052</script>
7052 7053 7054</body> 7055</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.