/*
Theme Name: Talkzyo
Theme URI: https://talkzyo.com
Author: Kainelabs
Description: The marketing site for Talkzyo. Pricing is read from Digizeo, which reads it from Stripe, so the page cannot advertise a price the checkout will not honour.
Version: 1.1.0
Requires at least: 6.0
Requires PHP: 7.4
License: GPL-2.0-or-later
Text Domain: talkzyo
*/

/* ---------------------------------------------------------------- tokens --
 *
 * Taken from the supplied design. Every visual decision is here, so the site
 * can be reskinned by editing this block alone.
 */

:root {
	/* The brand blue, matching the logo. 5.55:1 on white, so it is safe for links
	   in body copy as well as for buttons - a brand colour that fails contrast
	   forces you to keep a second one just for text. */
	--brand: #2356fa;
	--brand-deep: #0536d6;
	--brand-wash: #f0f3ff;
	--on-brand: #ffffff;

	--ink: #141827;
	--ink-soft: #4f5567;
	--ink-faint: #646b7d;

	--line: #e6e8ef;
	--surface: #ffffff;
	--surface-2: #f6f7fb;
	--surface-3: #eceef5;

	--ok: #22c55e;

	/* The accent on the featured pricing card: yellow on dark grey. A button has
	   to clear 3:1 against what it sits on - this reaches 3.62:1 on the brand
	   blue, and the grey reads at 8.7:1 on the yellow, so the label is far
	   clearer than the black-on-yellow that usually gets reached for. */
	--accent: #facc15;
	--accent-ink: #2b2f3a;

	--radius: 16px;
	--shadow: 0 1px 2px rgba( 20, 24, 39, .05 ), 0 1px 0 rgba( 20, 24, 39, .02 );
	--shadow-lg: 0 24px 60px -24px rgba( 20, 24, 39, .25 ), 0 6px 16px -8px rgba( 20, 24, 39, .08 );

	--t-xs: .78rem;
	--t-sm: .92rem;
	--t-base: 1.02rem;
	--t-lg: clamp( 1.1rem, 1.02rem + .35vw, 1.25rem );
	--t-xl: clamp( 1.28rem, 1.15rem + .6vw, 1.5rem );
	--t-2xl: clamp( 1.6rem, 1.35rem + 1.1vw, 2.1rem );
	--t-3xl: clamp( 1.95rem, 1.5rem + 2vw, 2.9rem );
	--t-4xl: clamp( 2.5rem, 1.7rem + 3.4vw, 4.2rem );

	--font: "DM Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, sans-serif;
	--mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}

/* Light is the default, full stop.
 *
 * The system preference deliberately does not decide this. A marketing page
 * that arrives dark because someone's laptop switched at sunset is showing them
 * a version of the brand nobody signed off, and the logo, the screenshots and
 * the gradients were all chosen against white. Dark is available on request -
 * the toggle - and is not imposed.
 */

/* ------------------------------------------------------------------ base -- */

* { box-sizing: border-box; }
html {
	scroll-behavior: smooth;
	/* The header is 68px and sticky, so an anchor that scrolls to exactly the
	   section top puts its heading behind the header. */
	scroll-padding-top: calc( 84px + var( --digizeo-banner-height, 0px ) );
}

/* :has() lets the root element see a class on <body>. Where it is unsupported
   this simply does not apply, which is the behaviour before this rule. */
html:has( body.admin-bar ) { scroll-padding-top: calc( 116px + var( --digizeo-banner-height, 0px ) ); }

@media screen and ( max-width: 782px ) {
	html:has( body.admin-bar ) { scroll-padding-top: calc( 130px + var( --digizeo-banner-height, 0px ) ); }
}

@media screen and ( max-width: 600px ) {
	html:has( body.admin-bar ) { scroll-padding-top: calc( 84px + var( --digizeo-banner-height, 0px ) ); }
}

body {
	margin: 0;
	background: var( --surface );
	color: var( --ink );
	font-family: var( --font );
	font-size: var( --t-base );
	-webkit-font-smoothing: antialiased;
}

img, svg { max-width: 100%; }
a { color: var( --brand ); text-decoration: none; }
a:hover { color: var( --brand-deep ); text-decoration: underline; }
:focus-visible { outline: 2px solid var( --brand ); outline-offset: 3px; border-radius: 6px; }
summary::-webkit-details-marker { display: none; }

.screen-reader-text {
	position: absolute !important;
	width: 1px; height: 1px; overflow: hidden;
	clip: rect( 1px, 1px, 1px, 1px ); white-space: nowrap;
}

.skip-link:focus {
	position: fixed; top: 12px; left: 12px; z-index: 100;
	width: auto; height: auto; clip: auto;
	padding: 10px 16px; background: var( --ink ); color: var( --surface ); border-radius: 8px;
}

/* --------------------------------------------------------------- motion -- */

@keyframes tz-in { from { opacity: 0; transform: translateY( 12px ); } to { opacity: 1; transform: none; } }
@keyframes tz-pop { 0% { opacity: 0; transform: translateY( 8px ) scale( .98 ); } 6% { opacity: 1; transform: none; } 95% { opacity: 1; transform: none; } 100% { opacity: 0; transform: none; } }
@keyframes tz-blink { 0%, 60%, 100% { opacity: .3; transform: translateY( 0 ); } 30% { opacity: 1; transform: translateY( -2px ); } }
@keyframes tz-live { 0%, 100% { box-shadow: 0 0 0 0 color-mix( in srgb, var( --ok ) 50%, transparent ); } 70% { box-shadow: 0 0 0 6px transparent; } }
@keyframes tz-flow { from { stroke-dashoffset: 24; } to { stroke-dashoffset: 0; } }

@media ( prefers-reduced-motion: reduce ) {
	* { animation: none !important; transition: none !important; }
	html { scroll-behavior: auto; }
}

/* --------------------------------------------------------------- hovers --
 *
 * The source used a style-hover attribute, which browsers ignore. These are
 * the same declarations as real rules.
 */

.tz-btn-primary:hover { background: var( --brand-deep ); text-decoration: none; }
.tz-btn-ghost:hover { background: var( --surface-2 ); text-decoration: none; color: var( --ink ); }
.tz-btn-oncolour:hover { text-decoration: none; background: color-mix( in srgb, var( --on-brand ) 12%, transparent ); }
.tz-btn-bright:hover { text-decoration: none; filter: brightness( .96 ); }
.tz-nav-link:hover { background: var( --surface-2 ); text-decoration: none; color: var( --ink ); }

.tz-lift { transition: box-shadow .18s ease, border-color .18s ease, transform .18s ease; }
.tz-lift:hover {
	box-shadow: var( --shadow-lg );
	border-color: color-mix( in srgb, var( --brand ) 35%, var( --line ) );
}

/* ----------------------------------------------------------------- hero -- */

.tz-hero__grid {
	max-width: 1240px; margin: 0 auto;
	padding: clamp( 56px, 7vw, 104px ) 24px clamp( 48px, 6vw, 88px );
	display: grid; gap: clamp( 36px, 5vw, 64px ); align-items: center;
}

/*
 * One column, and the mockup gets the whole of it.
 *
 * This was a two-column split with the copy on the left and the chat beside
 * it, which gave the chat about 60% of 1240px - and the product it is
 * depicting has a sidebar, a thread and a composer side by side, so at that
 * width everything in it was fighting for room. Stacked, the same markup gets
 * the full measure and reads as the application rather than a thumbnail of
 * one.
 *
 * Centred copy over a full-width screenshot is the ordinary shape for this
 * kind of page for the same reason: the headline is the claim and the picture
 * is the evidence, and putting them side by side makes the reader choose.
 */
.tz-hero__copy {
	text-align: center;
	/* Wide enough for the headline to break where it wants, narrow enough that
	   the eye does not have to travel the full 1240px between lines. */
	max-width: 54rem;
	margin: 0 auto;
}

/*
 * Timestamps appear on hover, which is what the chat does.
 *
 * .talkzyo-date-time is opacity:0 with a half-second fade and comes back on
 * hover, so a stamp under every bubble is a state the product is never in.
 * Same transition, same trigger.
 */
.tz-chat-mock__time {
	opacity: 0;
	transition: opacity .5s ease-out;
}

.tz-chat-mock__row:hover .tz-chat-mock__time { opacity: 1; }

/* Nothing to hover with, so the stamps stay put rather than never showing. */
@media ( hover: none ) {
	.tz-chat-mock__time { opacity: 1; }
}

/*
 * The mockup is two panes, until there is not room for two.
 *
 * The columns were an inline style of minmax(0,320px) minmax(0,1fr), which no
 * media query can reach - so on a phone the sidebar kept its 320px and the
 * thread, the half that carries the actual messages, was squeezed into
 * whatever was left. Below 720px the list goes and the thread takes the width.
 */
.tz-chat-mock {
	display: grid;
	grid-template-columns: minmax( 0, 320px ) minmax( 0, 1fr );
	/*
	 * A window, not a transcript.
	 *
	 * The thread grew with every message added to it, so a mockup of a chat
	 * with ten messages in it was a column a page and a half tall - which is
	 * not what the product looks like and pushed everything below the hero off
	 * the screen. The chat is a fixed frame with the conversation scrolling
	 * inside it, so this is too.
	 */
	height: clamp( 500px, 72vh, 700px );
}

/*
 * min-height:0 on both, or the grid refuses to let them shrink below their
 * content and the inner overflow never engages - the usual way a nested
 * scroller silently does nothing.
 */
.tz-chat-mock__list,
.tz-chat-mock__thread { min-height: 0; }

.tz-chat-mock__rows,
.tz-chat-mock__body {
	min-height: 0;
	overflow-y: auto;
	overscroll-behavior: contain;
}

/* The chat's own bar: 10px, and a track that only shows on hover. */
.tz-chat-mock__rows::-webkit-scrollbar,
.tz-chat-mock__body::-webkit-scrollbar { width: 10px; }

.tz-chat-mock__rows::-webkit-scrollbar-thumb,
.tz-chat-mock__body::-webkit-scrollbar-thumb {
	border-radius: 8px;
	background: transparent;
}

.tz-chat-mock__rows:hover::-webkit-scrollbar-thumb,
.tz-chat-mock__body:hover::-webkit-scrollbar-thumb { background: #c9ced6; }

/*
 * The hero's voice note, which actually plays.
 *
 * Every value here is copied from assets/css/talkzyo-features.css in the
 * plugin, not chosen: this is meant to be the product's player, so the plate's
 * padding, the 30px disc, the 26px track, the 2px bars and their .45 grey, the
 * 11px handle and the speed chip's shadow are the plugin's numbers. What could
 * not be inlined on the markup is here because it is state - is-playing swaps
 * the icon, has-progress reveals the handle and the chip - and a style
 * attribute cannot hold a state.
 */
.tz-voice {
	/* Block, not flex: the transport row and the time stack. */
	display: block;
	box-sizing: border-box;
	/*
	 * A definite width, because the wave is absolutely positioned and the
	 * track would otherwise fall back to its 80px basis.
	 *
	 * 245, not the plugin's 300. The 300 is a ceiling, not a fixed size - the
	 * player carries max-width: 100% and a chat window's bubble is narrower
	 * than that, so in the product the track is usually around 145px. The bars
	 * are flex: 1 with a 2px floor, so a wider track makes them thicker: at the
	 * full 300 they came out 5.5px each and read as blocks, where the ones
	 * people actually see are closer to 3px. Same 28 bars, same 2px gaps -
	 * only the plate is sized to the width it is normally seen at.
	 */
	width: 245px;
	max-width: 100%;
	min-width: 0;
	/* More on the right than the left: the play button is a circle, so its
	   own curve holds it off the edge, while the time is flat text. */
	padding: 8px 14px 8px 10px;
	border-radius: 12px;
	background: rgba( 120, 130, 150, .12 );
}

.tz-voice audio { display: none; }

.tz-voice__main {
	display: flex;
	align-items: center;
	gap: 8px;
	min-width: 0;
}

.tz-voice__play {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	flex: 0 0 auto;
	width: 30px;
	height: 30px;
	padding: 0;
	border: 0;
	border-radius: 50%;
	background: #2356fa;
	color: #fff;
	cursor: pointer;
}

/*
 * One icon at a time - which one depends on whether the clip is running.
 *
 * Written first as `.tz-voice__play span { display: flex }` plus a bare
 * `.tz-voice__icon-pause { display: none }`, and the button came out with both
 * glyphs in it: class-plus-element beats a lone class, so the blanket rule won
 * every time. Each state now carries the class twice and the order decides.
 */
.tz-voice__icon-play,
.tz-voice__icon-pause { display: flex; }

.tz-voice .tz-voice__icon-pause,
.tz-voice.is-playing .tz-voice__icon-play { display: none; }

.tz-voice.is-playing .tz-voice__icon-pause { display: flex; }

.tz-voice__track {
	position: relative;
	flex: 1 1 80px;
	/* A floor, because the bars are absolutely positioned and give the track
	   no width of its own - at 0 it collapses and the waveform vanishes. */
	min-width: 34px;
	height: 26px;
	cursor: pointer;
	overflow: hidden;
}

/* The bars, drawn twice. The second copy is clipped to the progress, which is
   one width change per tick instead of restyling 28 elements. */
.tz-voice__wave {
	position: absolute;
	inset: 0;
	display: flex;
	align-items: center;
	gap: 2px;
}

.tz-voice__wave i {
	flex: 1 1 auto;
	min-width: 2px;
	border-radius: 2px;
	background: rgba( 120, 130, 150, .45 );
}

.tz-voice__wave--played {
	width: 0;
	overflow: hidden;
}

/* The inner copy keeps its full width so the bars do not squash as the clip
   narrows - the wrapper crops it instead. */
.tz-voice__wave-inner {
	display: flex;
	align-items: center;
	gap: 2px;
	width: 100%;
	height: 100%;
}

.tz-voice__wave--played .tz-voice__wave-inner i { background: #2356fa; }

.tz-voice__handle {
	position: absolute;
	top: 50%;
	left: 0;
	display: none;
	width: 11px;
	height: 11px;
	margin-left: -5px;
	border-radius: 50%;
	background: #2356fa;
	transform: translateY( -50% );
	pointer-events: none;
}

/* The handle marks a position, so it earns its place once there is one - and
   keyed on progress rather than on playing, or it vanishes on pause, the
   moment you most want to see where you stopped. */
.tz-voice.has-progress .tz-voice__handle { display: block; }

.tz-voice__meta {
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: 3px;
	flex: 0 0 auto;
	min-width: 0;
	/* Fixed, so the player keeps its height whether or not the chip is there -
	   time ( 13 ) + gap ( 3 ) + chip ( 19 ). */
	height: 35px;
}

.tz-voice__length {
	color: #8b93a5;
	font-size: 11px;
	font-variant-numeric: tabular-nums;
	line-height: 1.2;
}

.tz-voice__speed {
	/* Out of the flow until there is something to apply a speed to. The
	   column's fixed height absorbs the difference. */
	display: none;
	flex: 0 0 auto;
	padding: 3px 8px;
	/* White chip, grey label, a soft shadow rather than a border so it lifts
	   off the plate without drawing a ring around itself. */
	border: 0;
	border-radius: 999px;
	background: #fff;
	color: #6b7280;
	box-shadow: 0 1px 2px rgba( 28, 34, 51, .12 );
	font: inherit;
	font-size: 10px;
	font-weight: 700;
	line-height: 1.3;
	cursor: pointer;
}

.tz-voice__speed:hover { color: #39404e; }

.tz-voice.is-playing .tz-voice__speed,
.tz-voice.has-progress .tz-voice__speed { display: block; }

/* ------------------------------------------------------------- trust strip -- */
/*
 * Three facts under the hero. They were three spans in a centred wrap, which
 * read as one long grey sentence and broke in arbitrary places; this gives each
 * one a glyph, a hairline and a column it keeps.
 */
.tz-trust {
	border-block: 1px solid var( --line );
	background: var( --surface-2 );
}

/*
 * A grid, not a flex row, now that there are four facts.
 *
 * Flex wrapping gave 3 + 1: three facts on one line and a lone one centred
 * underneath with the dividers hanging off the ends. A grid can only break
 * into whole columns, so the strip goes 4 across, then 2 x 2, then stacked -
 * and never lands on a ragged row.
 */
.tz-trust__inner {
	max-width: 1440px;
	margin: 0 auto;
	padding: 0 24px;
	display: grid;
	grid-template-columns: repeat( 4, auto );
	/* stretch, not center: the hairlines between items are their own edges, so
	   they have to run the full height of the strip to read as dividers. */
	align-items: stretch;
	justify-content: center;
}

.tz-trust__item {
	display: flex;
	align-items: center;
	gap: 10px;
	margin: 0;
	padding: 15px 16px;
	font-size: var( --t-sm );
	line-height: 1.35;
	color: var( --ink-faint );
	white-space: nowrap;
}

/* Hairlines between, not around: it is one statement in three parts. */
.tz-trust__item + .tz-trust__item {
	border-inline-start: 1px solid var( --line );
}

/*
 * The leading slot. 26px either way, whether it holds a vector mark or an app
 * icon, so the three rows line up on the same left edge.
 */
.tz-trust__icon {
	display: grid;
	place-items: center;
	flex: 0 0 auto;
	width: 26px;
	height: 26px;
	border-radius: 8px;
	/* The palest brand tint there is - enough to seat a single-colour mark,
	   not enough to compete with the hero directly above it. No tile behind
	   the bitmap logos: they are full-colour squares already, and a wash
	   around one reads as a mistake. */
	background: var( --brand-wash );
}

.tz-trust__logo {
	flex: 0 0 auto;
	width: 26px;
	height: 26px;
	border-radius: 8px;
	object-fit: contain;
}

.tz-trust__strong {
	font-weight: 700;
	color: var( --ink );
}

/* A name and its mark travel together: inline-flex so the pair wraps as one
   unit, and baseline-ish alignment so the glyph sits on the line of text
   rather than above it. */
/*
 * A logo and its name, on the sentence's own line.
 *
 * This was an inline-flex box, and a flex box takes its baseline from its
 * first item - an image, which has no baseline, so the browser used its bottom
 * edge and sat that on the text baseline. The word inside then rode a third of
 * a line high, and "Works with BuddyPress, BuddyBoss & any WordPress theme"
 * came out on three different levels. vertical-align: middle fixed the worst
 * of it and still left the names 1.3px low.
 *
 * So: no flex. The name is ordinary inline text, which puts it on the same
 * baseline as every other word by definition, and only the glyph is shifted -
 * by .22em, which drops a 16px mark to sit centred against lowercase letters.
 * nowrap keeps the pair from breaking across lines.
 */
.tz-trust__brand {
	font-weight: 700;
	color: var( --ink );
	white-space: nowrap;
}

.tz-trust__brand img,
.tz-trust__brand svg {
	display: inline-block;
	vertical-align: -.22em;
	margin-right: 5px;
}

/* The leading slot is a grid cell, where a block mark centres cleanly. */
.tz-trust__icon svg { display: block; }

/* An artwork mark inside a sentence: 18px, which is where a round white-on-
   colour disc stops reading as a smudge, and no radius - it is already a
   circle. */
.tz-trust__brandmark {
	width: 18px;
	height: 18px;
	object-fit: contain;
}

/* The sentence holds three inline-flex children, which stops it wrapping on
   spaces the way plain text does - this lets the line break between them. */
.tz-trust__works {
	display: inline;
	line-height: 1.7;
}

.tz-trust__link {
	font-weight: 700;
	color: var( --ink );
	text-decoration: underline;
	text-underline-offset: 3px;
}

.tz-trust__link:hover { color: var( --brand ); }

/*
 * Two by two below 1400px, where four facts stop fitting on one line. The
 * vertical rule stays between the pair; a horizontal one separates the rows.
 */
@media ( max-width: 1400px ) {

	.tz-trust__inner { grid-template-columns: repeat( 2, auto ); }

	/* The rule belongs between columns, so the left-hand cell of each row
	   loses the one the blanket rule gave it. */
	.tz-trust__item:nth-child( odd ) { border-inline-start: 0; }

	.tz-trust__item:nth-child( n+3 ) { border-top: 1px solid var( --line ); }
}

/*
 * Stacked below 760px. Rules turn horizontal with them, and each row keeps the
 * icon on the left so the lines share an edge instead of each centring on its
 * own length.
 */
@media ( max-width: 760px ) {

	.tz-trust__inner {
		grid-template-columns: minmax( 0, 420px );
		justify-content: center;
		padding: 2px 24px;
	}

	.tz-trust__item {
		width: 100%;
		max-width: 420px;
		padding: 13px 0;
		/* Back to normal wrapping: a stacked row has a column to wrap into. */
		white-space: normal;
	}

	.tz-trust__item + .tz-trust__item,
	.tz-trust__item:nth-child( n+2 ) {
		border-inline-start: 0;
		border-top: 1px solid var( --line );
	}
}

@media ( max-width: 720px ) {

	.tz-chat-mock { grid-template-columns: minmax( 0, 1fr ); }

	.tz-chat-mock__list { display: none; }
}

.tz-hero__grid > :last-child {
	max-width: 1120px;
	width: 100%;
	margin: 0 auto;
}

/* ----------------------------------------------------------------- head -- */

.tz-head {
	position: sticky;
	/* Digizeo's offer banner is sticky too and publishes its own height. Both
	   offsets stack and either can be absent, so each defaults to zero rather
	   than needing a rule per combination. */
	top: var( --digizeo-banner-height, 0px );
	z-index: 50;
	background: color-mix( in srgb, var( --surface ) 86%, transparent );
	backdrop-filter: saturate( 180% ) blur( 12px );
	border-bottom: 1px solid var( --line );
}

/* ------------------------------------------------------- wp admin bar ----
 *
 * When you are logged in, WordPress fixes its toolbar over the top of the
 * viewport and pushes the page down with a margin on <html>. A sticky header
 * ignores that margin - top: 0 means the top of the viewport, which is behind
 * the toolbar - so the header slides underneath it and loses its first rows.
 *
 * The three sizes are WordPress's own, not guesses: 32px on desktop, 46px on
 * the narrower toolbar, and nothing below 600px, where core switches the bar to
 * position: absolute and it scrolls away with the page.
 */
body.admin-bar .tz-head { top: calc( 32px + var( --digizeo-banner-height, 0px ) ); }

@media screen and ( max-width: 782px ) {
	body.admin-bar .tz-head { top: calc( 46px + var( --digizeo-banner-height, 0px ) ); }
}

@media screen and ( max-width: 600px ) {
	body.admin-bar .tz-head { top: var( --digizeo-banner-height, 0px ); }
}

/* Same problem, same fix: the skip link is the first thing a keyboard user
   reaches, and it was landing behind the toolbar. */
body.admin-bar .skip-link:focus { top: 44px; }

@media screen and ( max-width: 782px ) {
	body.admin-bar .skip-link:focus { top: 58px; }
}

@media screen and ( max-width: 600px ) {
	body.admin-bar .skip-link:focus { top: 12px; }
}

.tz-head__in {
	max-width: 1200px; margin: 0 auto; padding: 0 24px;
	height: 68px; align-items: center; gap: 20px;
	/* Three columns rather than a flex row: the menu is genuinely centred on the
	   page, not centred in whatever is left over after the logo. A flex row with
	   margin:auto shifts the menu whenever the logo or the buttons change width,
	   and "Log in" becoming "Your account" is exactly such a change. */
	display: grid;
	grid-template-columns: 1fr auto 1fr;
}

.tz-logo { display: block; line-height: 0; flex: 0 0 auto; }
.tz-logo img { width: 142px; height: auto; }

.tz-nav { display: flex; align-items: center; gap: 2px; justify-self: center; }

.tz-actions { display: flex; align-items: center; gap: 8px; justify-self: end; }

/* Set apart from the section links: it goes to your own account rather than
   further down this page, and reads as the pair to Get Talkzyo beside it. */
/*
 * The nav's sizing lived only on `.tz-nav a` - a descendant selector. The
 * account link sits in .tz-actions, so it matched none of it and rendered at
 * body size with no padding, which is why it never lined up with the nav or
 * with Get Talkzyo. Same declarations, bound to the class, so they hold
 * wherever the link is used.
 */
.tz-nav-link {
	padding: 8px 12px; border-radius: 9px;
	color: var( --ink-soft ); font-size: var( --t-sm ); font-weight: 550;
}

/*
 * Scoped to the header. The hero and CTA buttons carry their own inline
 * sizing but never set font-size, so an unscoped rule here would silently
 * shrink the page's two main calls to action from 1rem to .92rem.
 */
.tz-actions .tz-btn-primary,
.tz-actions .tz-btn-ghost {
	display: inline-flex; align-items: center; gap: 7px;
	padding: 10px 16px; border-radius: 11px;
	font-size: var( --t-sm ); font-weight: 600; line-height: 1.2;
	white-space: nowrap;
}

.tz-actions .tz-btn-primary { color: var( --on-brand ); background: var( --brand ); }

/*
 * Outlined, not filled: two solid buttons side by side compete, and the
 * primary action here is Get Talkzyo.
 */
.tz-actions .tz-btn-ghost {
	color: var( --ink ); background: transparent;
	border: 1px solid var( --line );
}

.tz-actions .tz-btn-ghost svg { width: 16px; height: 16px; flex: 0 0 auto; opacity: .75; }

.tz-nav a {
	padding: 8px 12px; border-radius: 9px;
	color: var( --ink-soft ); font-size: var( --t-sm ); font-weight: 550;
}

.tz-burger { display: none; }

@media ( max-width: 900px ) {
	.tz-burger {
		display: grid; place-items: center; width: 36px; height: 36px; margin-left: auto;
		border: 1px solid var( --line ); border-radius: 10px;
		background: transparent; color: var( --ink ); cursor: pointer;
	}
	/* The open menu is two sibling blocks, so let them sit in normal flow and
	   stack by themselves. Absolutely positioning both would mean measuring the
	   first to offset the second - a height to keep in sync for no gain. */
	.tz-head__in {
		grid-template-columns: auto 1fr;
		height: auto; min-height: 68px;
		row-gap: 0;
	}

	.tz-nav,
	.tz-actions {
		grid-column: 1 / -1;
		display: none;
		flex-direction: column; align-items: stretch; gap: 0;
		justify-self: stretch;
	}

	.tz-nav[data-open="true"],
	.tz-actions[data-open="true"] { display: flex; }

	.tz-nav { padding-top: 4px; }
	.tz-nav a { padding: 12px 0; }

	.tz-actions {
		gap: 10px; padding: 4px 0 18px;
		border-bottom: 1px solid var( --line );
	}

	.tz-actions .tz-btn-primary,
	.tz-actions .tz-btn-ghost { justify-content: center; }
}

/* -------------------------------------------------------------- pricing -- */

/* ------------------------------------------------------- guarantee block -- */
/*
 * Sits directly under the pricing grid and replaces two things that used to be
 * separate: the Stripe/refund line and the asterisk footnote carrying the
 * renewal prices.
 *
 * Logical properties throughout - margin-inline, text-align: start - because
 * the plugin ships an Arabic build and this section mirrors with it.
 */
.tz-guarantee {
	/* A clear gap, not a seam: the block used to sit close enough to the cards
	   to read as a fourth row of the table rather than as a separate statement
	   about all three. */
	margin-block-start: clamp( 40px, 5vw, 64px );
	border: 1px solid var( --line );
	border-radius: var( --radius );
	background: var( --surface-2 );
}

.tz-guarantee__main {
	display: flex;
	align-items: center;
	gap: clamp( 20px, 3vw, 34px );
	padding: clamp( 24px, 3vw, 32px );
}

.tz-guarantee__seal { flex: 0 0 auto; }

/* The seal's type. Set here rather than on the SVG so it follows the page's
   font rather than the browser's default serif. */
.tz-guarantee__seal text { font-family: var( --font ); font-weight: 700; }
.tz-guarantee__seal-num { font-size: 30px; letter-spacing: -.03em; }
.tz-guarantee__seal-unit { font-size: 10px; letter-spacing: .22em; }
/* 7.6px, because the two arcs have to clear the stars at each side - at 9 the
   words met them. */
.tz-guarantee__seal-arc { font-size: 7.6px; letter-spacing: .2em; }

.tz-guarantee__body { min-width: 0; }

.tz-guarantee__title {
	margin: 0 0 6px;
	font-size: var( --t-xl );
	font-weight: 700;
	letter-spacing: -.02em;
	color: var( --ink );
}

.tz-guarantee__lead {
	margin: 0 0 18px;
	max-width: 62ch;
	color: var( --ink-soft );
	font-size: var( --t-sm );
	line-height: 1.6;
}

/* Three boxes, each sized to its own content rather than a third of the row,
   so the captions do not wrap into two lines at the first breakpoint. */
.tz-guarantee__stats {
	display: grid;
	grid-template-columns: repeat( 3, minmax( 0, 1fr ) );
	gap: 10px;
	margin: 0;
	padding: 0;
	list-style: none;
}

.tz-guarantee__stats li {
	padding: 12px 14px;
	border: 1px solid var( --line );
	border-radius: 12px;
	background: var( --surface );
	text-align: start;
}

.tz-guarantee__value {
	display: block;
	font-size: var( --t-lg );
	font-weight: 700;
	letter-spacing: -.02em;
	color: var( --ink );
}

.tz-guarantee__caption {
	display: block;
	margin-block-start: 3px;
	color: var( --ink-faint );
	font-size: var( --t-xs );
	line-height: 1.45;
}

.tz-guarantee__foot {
	display: flex;
	align-items: flex-start;
	justify-content: space-between;
	gap: 18px;
	padding: 16px clamp( 24px, 3vw, 32px );
	border-block-start: 1px solid var( --line );
}

.tz-guarantee__terms { min-width: 0; }

.tz-guarantee__terms p {
	margin: 0;
	color: var( --ink-faint );
	font-size: var( --t-xs );
	line-height: 1.6;
	text-align: start;
}

.tz-guarantee__terms p + p { margin-block-start: 4px; }

.tz-guarantee__terms a {
	color: var( --ink-soft );
	text-decoration: underline;
	text-underline-offset: 3px;
}

.tz-guarantee__pay {
	display: flex;
	flex-direction: column;
	align-items: flex-end;
	gap: 7px;
	flex: 0 0 auto;
}

.tz-guarantee__cards { display: flex; gap: 6px; }

/*
 * In their own colours, because a grey row of card marks reads as disabled -
 * which is the opposite of the reassurance it is there to give.
 *
 * These are the networks' colours on our own type, not their artwork: Visa's
 * navy, Mastercard's red and amber discs with the overlap that makes the mark
 * recognisable at 26px, and Amex's blue card with the name reversed out.
 * Nominative use - saying which cards the checkout takes - which is what the
 * row is for.
 */
.tz-pay {
	display: grid;
	place-items: center;
	width: 40px;
	height: 26px;
	border: 1px solid var( --line );
	border-radius: 5px;
	background: var( --surface );
}

.tz-pay__word { font-size: 9px; font-weight: 700; letter-spacing: .04em; }

.tz-pay--visa { color: #1434cb; }

.tz-pay--amex {
	border-color: #006fcf;
	background: #006fcf;
	color: #fff;
}

/* Mastercard's two discs. The second is multiplied over the first so the
   overlap comes out the darker amber the real mark has, rather than one disc
   simply covering the other. */
.tz-pay__mc-a { fill: #eb001b; }

.tz-pay__mc-b {
	fill: #f79e1b;
	mix-blend-mode: multiply;
}

.tz-guarantee__stripe {
	display: inline-flex;
	align-items: center;
	gap: 5px;
	color: var( --ink-faint );
	font-size: var( --t-xs );
	white-space: nowrap;
}

/* Stacked and centred below 760, where the seal and the three boxes stop
   fitting beside each other. The boxes stay in one column rather than three
   40px-wide ones: at 360px, three captions of this length are four lines each. */
@media ( max-width: 760px ) {

	.tz-guarantee__main {
		flex-direction: column;
		text-align: center;
	}

	.tz-guarantee__lead { margin-inline: auto; }

	.tz-guarantee__stats { grid-template-columns: minmax( 0, 1fr ); }

	.tz-guarantee__stats li { text-align: center; }

	.tz-guarantee__foot {
		flex-direction: column;
		align-items: center;
	}

	.tz-guarantee__terms p { text-align: center; }

	.tz-guarantee__pay { align-items: center; }
}

.tz-price-grid {
	display: grid; gap: 18px;
	grid-template-columns: repeat( auto-fit, minmax( 260px, 1fr ) );
	/* stretch, not start: the featured card lifts out of the row by growing
	   past it at both ends, which only works if the others are not sized to
	   their content. */
	align-items: stretch;
}

.tz-price {
	position: relative; display: flex; flex-direction: column;
	border: 1px solid var( --line ); border-radius: var( --radius );
	background: var( --surface ); padding: 30px 26px;
	box-shadow: var( --shadow );
	transition: transform .18s ease, box-shadow .18s ease;
}

.tz-price:hover { transform: translateY( -3px ); box-shadow: var( --shadow-lg ); }

/* The chosen one. Taller at both ends so the eye lands on it before it has
   read a word, which is the whole job of a recommended tier. */
.tz-price--on {
	background: var( --brand ); border-color: var( --brand );
	box-shadow: 0 18px 40px rgba( 35, 86, 250, .28 );
	padding: 42px 26px;
}

@media ( min-width: 860px ) {
	.tz-price--on { margin: -22px 0; }
}

.tz-price__flag {
	position: absolute; top: -13px; left: 50%; transform: translateX( -50% );
	background: var( --accent ); color: var( --accent-ink );
	font-size: 11px; font-weight: 800; letter-spacing: .07em; text-transform: uppercase;
	padding: 6px 16px; border-radius: 999px; white-space: nowrap;
	box-shadow: 0 2px 8px rgba( 8, 49, 42, .18 );
}

/*
 * The old price, struck corner to corner rather than through the middle.
 *
 * text-decoration can only draw a horizontal rule, so the line is a rotated
 * pseudo-element. currentColor means it follows the text, which matters here:
 * the same markup renders grey on the white cards and translucent white on the
 * blue one.
 */
.tz-was {
	position: relative;
	display: inline-block;
	text-decoration: none;
}

.tz-was::after {
	content: "";
	position: absolute;
	left: -3px;
	right: -3px;
	top: 50%;
	height: 1.5px;
	background: currentColor;
	/* Shallow enough to read as a strike rather than a slash, steep enough to
	   be obviously deliberate. */
	transform: translateY( -50% ) rotate( -11deg );
	transform-origin: center;
	pointer-events: none;
}

.tz-price__cta {
	margin-top: auto;
	display: flex; align-items: center; justify-content: center; gap: 8px;
	padding: 14px 20px; border-radius: 13px;
	font-weight: 700; font-size: var( --t-sm ); text-decoration: none;
	background: var( --surface ); color: var( --brand );
	border: 1.5px solid color-mix( in srgb, var( --brand ) 35%, transparent );
	transition: background .15s ease, border-color .15s ease, color .15s ease;
}

.tz-price__cta:hover {
	text-decoration: none; color: var( --brand-deep );
	background: var( --brand-wash ); border-color: var( --brand );
}

.tz-price__cta--on {
	background: var( --accent ); color: var( --accent-ink ); border-color: var( --accent );
}

.tz-price__cta--on:hover {
	color: var( --accent-ink );
	background: color-mix( in srgb, var( --accent ) 82%, #fff );
	border-color: color-mix( in srgb, var( --accent ) 82%, #fff );
}

@media ( prefers-reduced-motion: reduce ) {
	.tz-price:hover { transform: none; }
}

/* ----------------------------------------------------------------- page -- */

/*
 * page.php has always used .wrap, .page-head and .entry, and none of them had
 * a single rule - so every standalone page rendered flush against the left
 * edge with no space above or below. It went unnoticed because the front page
 * is built from parts that carry their own containers.
 */
.wrap {
	max-width: 1200px;
	margin: 0 auto;
	padding: 0 24px;
}

.wrap--narrow { max-width: 46rem; }

.page-head {
	padding-top: clamp( 40px, 6vw, 72px );
	padding-bottom: clamp( 14px, 2vw, 22px );
}

.page-head h1 {
	font-size: var( --t-3xl );
	line-height: 1.12;
	letter-spacing: -.03em;
	margin: 0;
	text-wrap: balance;
}

.entry { padding-bottom: clamp( 48px, 8vw, 96px ); }

.entry > :first-child { margin-top: 0; }
.entry > :last-child { margin-bottom: 0; }

.entry p { margin: 0 0 1.1em; }

.entry h2 {
	font-size: var( --t-xl );
	letter-spacing: -.02em;
	margin: 1.8em 0 .6em;
}

.entry h3 {
	font-size: var( --t-lg );
	margin: 1.5em 0 .5em;
}

.entry ul,
.entry ol { margin: 0 0 1.1em; padding-left: 1.3em; }

.entry li { margin-bottom: .4em; }

/* ----------------------------------------------------------------- foot -- */

.tz-foot { border-top: 1px solid var( --line ); background: var( --surface-2 ); }
.tz-foot__in { max-width: 1200px; margin: 0 auto; padding: 48px 24px 36px; }
.tz-foot__grid { display: grid; gap: 32px; grid-template-columns: 1.5fr repeat( 3, 1fr ); }
/* The column headings. h2 rather than h4 - the page went from the section
   headings straight to h4 here, which is a jump a screen reader announces as
   two missing levels - so they need their own size rather than the browser's
   idea of an h2. */
.tz-foot__head { margin: 0 0 12px; font-size: var( --t-sm ); font-weight: 700; line-height: 1.3; color: var( --ink ); }
.tz-foot ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
.tz-foot a { color: var( --ink-soft ); font-size: var( --t-sm ); }
.tz-foot a:hover { color: var( --ink ); }

.tz-foot__base {
	margin-top: 36px; padding-top: 22px; border-top: 1px solid var( --line );
	display: flex; justify-content: space-between; gap: 16px; flex-wrap: wrap;
	color: var( --ink-faint ); font-size: var( --t-xs );
}

@media ( max-width: 760px ) { .tz-foot__grid { grid-template-columns: 1fr 1fr; } }

/* ---------------------------------------------------------------- pages -- */

.tz-page { max-width: 760px; margin: 0 auto; padding: clamp( 48px, 6vw, 84px ) 24px; }
.tz-page h1 { font-size: var( --t-3xl ); line-height: 1.1; letter-spacing: -.03em; margin: 0 0 20px; }
.tz-page h2 { font-size: var( --t-2xl ); margin: 1.6em 0 .5em; }
.tz-page p, .tz-page li { color: var( --ink-soft ); line-height: 1.65; }
.tz-page code { font-family: var( --mono ); font-size: .9em; background: var( --surface-3 ); padding: 2px 6px; border-radius: 5px; }
