/**
 * Centry Engine - front-end styles.
 *
 * Load order and intent:
 *   1. Design tokens  - custom properties only, no rules
 *   2. Base           - element-level defaults GeneratePress does not cover
 *   3. Components     - reusable pieces
 *   4. Utilities      - single-purpose overrides, last so they win
 *
 * Anything you can set in GeneratePress Customizer or Elementor Global Styles,
 * set there instead. This file is for what the UI cannot express.
 */

/* ------------------------------------------------------------------------- */
/* 1. Design tokens                                                          */
/* ------------------------------------------------------------------------- */

:root {
	/*
	 * Colour - dark scheme
	 *
	 * The site is dark, matching centry-secure.io, whose page background is
	 * #0b0e14. Every ratio below is measured against that, not assumed.
	 *
	 * The important consequence: on this background the brand orange is 7.77:1
	 * and is a perfectly good text and link colour. On white it is 2.49:1 and
	 * fails outright. The darkened #a34e00 that light backgrounds need drops to
	 * 3.35:1 here and fails for body copy - so the two schemes need opposite
	 * treatments of the same colour, and mixing them up is the easy mistake.
	 *
	 * The supplied wordmark SVG is #f57c00 rather than #ff8200 - a small drift
	 * in the artwork, not a second brand colour. Tokens follow the 151 spec.
	 */
	--ce-color-brand: #ff8200; /* 7.77:1 on surface - valid for text here */
	--ce-color-brand-hover: #ffa04d; /* 10.4:1 - lifts rather than darkens */

	/* Surfaces. Adjacent dark shades differ by ~1.05:1, which is invisible -
	 * sections separate with --ce-color-border, never with a fill alone. */
	--ce-color-surface: #0b0e14;
	--ce-color-surface-raised: #131822;
	--ce-color-border: #272a3b;

	/*
	 * Two surfaces below the page rather than above it, from the pricing section on
	 * centry-secure.io: a card darker than its background, and a control one step
	 * back up. Named at the top with everything else so the section reads from
	 * tokens like the rest of the site rather than carrying its own hexes.
	 */
	--ce-color-surface-sunken: #070915;
	--ce-color-surface-control: #141729;

	/* Text */
	--ce-color-heading: #fffefe; /* 19.19:1 */
	--ce-color-text: #f2f4f6; /* 17.52:1 */
	--ce-color-muted: #b8bcc4; /* 10.14:1 */

	/*
	 * Pairings that are known to pass. Text on a brand-orange fill has to be
	 * near-black: white on #ff8200 is 2.49:1 and fails on any background.
	 */
	--ce-color-on-brand: #0b0e14; /* 7.77:1 on brand */

	/* Spacing scale */
	--ce-space-xs: 0.5rem;
	--ce-space-sm: 1rem;
	--ce-space-md: 2rem;
	--ce-space-lg: 4rem;
	--ce-space-xl: 6rem;

	/*
	 * The gap between major page sections. One token rather than each block
	 * choosing its own margin - the sections were drifting between 2rem and
	 * 4rem depending on which was written when, which reads as sloppy rather
	 * than as rhythm.
	 */
	--ce-section-gap: 80px;

	/*
	 * The gap after a section built in the builder. 50px, and separate from
	 * --ce-section-gap because that one spaces the theme's own full-bleed
	 * placeholders, which sit further apart than sections inside a page.
	 */
	--ce-section-space: 50px;

	/*
	 * Top offset for the article and the sidebar. Owned here rather than left to
	 * GeneratePress, whose article padding comes from its own stylesheet and
	 * whose widget padding comes from Customizer - two different numbers, so the
	 * two columns started at different heights.
	 */
	--ce-column-pad: var(--ce-space-md);

	/*
	 * Typography
	 *
	 * Families are declared here rather than in GeneratePress Customizer,
	 * because the fonts are self-hosted (assets/css/fonts.css) and the
	 * @font-face declarations already live in code. A Customizer font setting
	 * would either duplicate these or silently load a second copy from Google.
	 *
	 * Instrument Sans for headings, DM Sans for everything else. The pairing
	 * comes from centry-secure.io; how it is sized and tracked does not, and
	 * belongs in Elementor Global Fonts.
	 */
	--ce-font-heading: 'Instrument Sans', system-ui, -apple-system, 'Segoe UI', sans-serif;
	--ce-font-body: 'DM Sans', system-ui, -apple-system, 'Segoe UI', sans-serif;
	--ce-text-sm: 0.875rem;
	--ce-text-base: 1rem;
	--ce-text-lg: 1.125rem;
	--ce-text-xl: clamp(1.25rem, 1.1rem + 0.6vw, 1.5rem);
	--ce-text-2xl: clamp(1.5rem, 1.25rem + 1.2vw, 2.125rem);
	--ce-text-3xl: clamp(2rem, 1.5rem + 2.2vw, 3rem);

	--ce-leading-tight: 1.15;
	--ce-leading-normal: 1.6;
	--ce-tracking-tight: -0.015em;

	--ce-weight-regular: 400;
	--ce-weight-medium: 500;
	--ce-weight-semibold: 600;
	--ce-weight-bold: 700;

	/* Layout */
	--ce-container-max: 1200px;

	/*
	 * The page measure, and the gutter either side of it. The hero's inner and every
	 * section share it, so a section's content starts on the same left edge as the
	 * hero's heading and ends the same distance from the right.
	 *
	 * 1200px rather than the header's 1340: at the header measure the margin was 50px
	 * at 1440, which reads as no margin at all. The consequence, accepted: the hero's
	 * text no longer starts under the logo, because the header keeps its own wider
	 * measure - the nav needs the room and the page does not.
	 */
	--ce-page-max: var(--ce-container-max);
	--ce-page-gutter: var(--ce-space-md);
	--ce-radius: 6px;

	/*
	 * Form field geometry, measured from the contact form on
	 * centry-secure.io/contact-us - Elementor element 752409d5, whose fields are
	 * 13px/14px padding, a 10px radius, a 1px border, 15px type and a
	 * transparent fill.
	 *
	 * The earlier values here were 12px/20px and a 12px radius, sampled from a
	 * different input on that site: one with an icon, whose real padding is
	 * `12px 20px 12px 43px` - the 43px being the space for the icon. Copying the
	 * shorthand without the left value produced a field that was too wide, too
	 * round and slightly too large, which is why the form never matched.
	 *
	 * Softer than the 6px used on cards and buttons. Its own token because that
	 * is a deliberate difference, not a mistake.
	 */
	--ce-field-radius: 10px;
	--ce-field-padding: 13px 14px;
	--ce-field-size: 15px;

	/*
	 * Field borders are much lighter than card borders, and that is copied from
	 * centry-secure.io rather than invented.
	 *
	 * Its Elementor kit carries two palettes. The dark one is what this site's
	 * tokens already match exactly - alt_bd_color #272A3B, alt_title #FFFEFE,
	 * alt_text #F2F4F6, alt_meta #B8BCC4. The contact form's fields do not use it:
	 * they are set to bd_color #E3E9EB, the *light* palette's border, on a dark
	 * page. Deliberate or not, that near-white edge is what makes those fields
	 * read as inputs.
	 *
	 * Ours used --ce-color-border, which is 1.36:1 against the page - invisible,
	 * so the fields rendered as flat dark rectangles with no boundary. Which is
	 * exactly what "the form looks vanilla" means.
	 *
	 * Fields only. Cards keep the quieter border: a card is a container, a field
	 * is something you are meant to click into.
	 */
	--ce-color-field-border: #e3e9eb;

	/* 6.96:1 on the page surface. Plain #f00 is 4.83:1 - passing, but only. */
	--ce-color-danger: #ff6b6b;

	/*
	 * Header geometry, matched to cmhworks.com: a 135px bar inside a 1340px
	 * container, shrinking to 70px in the compact state. The scroll distance
	 * that triggers it is in assets/js/main.js, which owns the class flip.
	 */
	--ce-header-max: 1340px;
	--ce-header-height: 135px;
	--ce-header-height-compact: 70px;

	/*
	 * cmhworks.com does not shrink its logo at all - only the bar - because its
	 * mark is small enough to sit in a 70px bar untouched. This wordmark at
	 * 86px is not, so it steps down just enough to clear the compact bar with
	 * breathing room. Anything nearer 44px reads as mush at this aspect.
	 */
	--ce-logo-height-compact: 60px;
	/*
	 * Header logo height, matched to centry-secure.io so the two Centry sites
	 * read as one family. That site sets max-height 86px on desktop and 30px on
	 * mobile; 30px is very small against this wordmark's flatter 2.18:1 aspect,
	 * so the mobile step here is 44px. Change if the family should match exactly.
	 */
	--ce-logo-height: 86px;

	/* Motion */
	--ce-transition: 200ms ease;

	/*
	 * GeneratePress palette remap.
	 *
	 * GeneratePress paints articles, widgets, navigation, the footer widget
	 * area and the site info bar from its own custom properties, which default
	 * to white and near-white. Overriding the palette is one block; overriding
	 * the twenty-odd selectors that consume it is a losing game that breaks
	 * every time the parent theme adds another.
	 *
	 * These are database state - Customizer > Colours writes them - so they
	 * would otherwise differ per environment. Setting them here means the dark
	 * scheme is code, consistent with ADR 0002.
	 *
	 * This works because main.css is enqueued after generate-style, so these
	 * :root declarations come later in the cascade. Do not reorder the enqueue.
	 */
	--base-3: var(--ce-color-surface); /* article, widget, nav backgrounds */
	--base-2: var(--ce-color-surface); /* body background */
	--base: var(--ce-color-surface-raised); /* raised fills, form fields */
	--contrast: var(--ce-color-text);
	--contrast-2: var(--ce-color-muted);
	--contrast-3: var(--ce-color-border);
	--accent: var(--ce-color-brand);
}

/* ------------------------------------------------------------------------- */
/* 2. Base                                                                   */
/* ------------------------------------------------------------------------- */

/*
 * In-page CTAs scroll rather than jump. The Get a Demo buttons target a form
 * near the foot of the same page, and an instant jump gives no sense of having
 * moved - people lose their place and scroll back up to check.
 *
 * The prefers-reduced-motion block below already forces scroll-behavior back to
 * auto, so this needs no separate guard: anyone who has asked for less movement
 * still gets the instant jump.
 */
html {
	scroll-behavior: smooth;
}

body {
	background-color: var(--ce-color-surface);
	color: var(--ce-color-text);
	font-family: var(--ce-font-body);
	line-height: var(--ce-leading-normal);
}

/*
 * Family and colour only. Size, weight, tracking and line-height are design
 * decisions and belong in Elementor Global Fonts, not here - an earlier version
 * copied centry-secure.io's heading treatment, which was carrying over that
 * site's design rather than making one.
 */
h1,
h2,
h3,
h4,
h5,
h6 {
	color: var(--ce-color-heading);
	font-family: var(--ce-font-heading);
}

a {
	color: var(--ce-color-brand);
}

a:hover,
a:focus {
	color: var(--ce-color-brand-hover);
}

:focus-visible {
	outline: 2px solid currentColor;
	outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
	*,
	*::before,
	*::after {
		animation-duration: 0.01ms !important;
		animation-iteration-count: 1 !important;
		transition-duration: 0.01ms !important;
		scroll-behavior: auto !important;
	}
}

/* ------------------------------------------------------------------------- */
/* 3. Components                                                             */
/* ------------------------------------------------------------------------- */

/* Add component styles below, one block per component, alphabetically. */

/* Brand logo - inline SVG from centry_engine_inline_svg(). */
.ce-logo {
	display: inline-block;
	line-height: 0;
}

.ce-logo svg {
	display: block;
	width: auto;
	height: var(--ce-logo-height);
}

/* Button ----------------------------------------------------------------- */

/*
 * Sizing carried over from centry-secure.io's header button: 15px text,
 * 15px/30px padding. Colour is not carried over - that site puts white on the
 * brand orange, which is 2.49:1 and fails WCAG AA. Near-black on orange is
 * 7.77:1.
 */
.ce-button {
	display: inline-block;
	padding: 15px 30px;
	border: 1px solid transparent;
	border-radius: var(--ce-radius);
	font-size: 15px;
	font-weight: var(--ce-weight-medium);
	line-height: 1;
	text-decoration: none;
	white-space: nowrap;
	transition:
		background-color var(--ce-transition),
		color var(--ce-transition);
}

.ce-button--primary {
	background: var(--ce-color-brand);
	color: var(--ce-color-on-brand);
}

.ce-button--primary:hover,
.ce-button--primary:focus {
	background: var(--ce-color-brand-hover);
	color: var(--ce-color-on-brand);
}

.ce-button--secondary {
	border-color: currentColor;
	background: transparent;
	color: var(--ce-color-brand);
}

.ce-button--secondary:hover,
.ce-button--secondary:focus {
	background: var(--ce-color-surface-raised);
	color: var(--ce-color-brand);
}

/*
 * Elementor's Button widget wraps its anchor in a div, and a class added in the
 * builder's Advanced tab lands on that wrapper - not on the anchor. So
 * `ce-button` on the widget paints a full-width bar and leaves the real button
 * grey, which is what the first imported template did.
 *
 * These two rules make the widget work without anyone remembering that: the
 * anchor is styled by descent, and the variant is chosen with a wrapper class.
 * Two classes deep beats Elementor's own `.elementor-button`, which is enqueued
 * after this stylesheet in per-post CSS.
 */
.elementor-widget-button .elementor-button {
	background: var(--ce-color-brand);
	color: var(--ce-color-on-brand);
}

.elementor-widget-button .elementor-button:hover,
.elementor-widget-button .elementor-button:focus {
	background: var(--ce-color-brand-hover);
	color: var(--ce-color-on-brand);
}

.ce-button-wrap--secondary .elementor-button {
	border-color: currentColor;
	background: transparent;
	color: var(--ce-color-brand);
}

.ce-button-wrap--secondary .elementor-button:hover,
.ce-button-wrap--secondary .elementor-button:focus {
	background: var(--ce-color-surface-raised);
	color: var(--ce-color-brand);
}

/*
 * Elementor containers default to flex-direction: column, so a row of actions
 * stacks - which put See Pricing on its own line under Get a Demo. The templates
 * set the direction explicitly too; this is here so an action row built by hand
 * in the builder behaves without anyone having to know that default.
 *
 * Set through Elementor's own custom property rather than flex-direction, because
 * that is what its container rule reads - overriding the property loses to it.
 */
.ce-hero__actions,
.ce-post-cta__actions,
.ce-solution__cta-actions {
	--flex-direction: row;
	--flex-wrap: wrap;
}

/*
 * Every button on the site defaults to the header's Become a Partner style.
 *
 * WordPress, GeneratePress and Elementor each ship their own button defaults -
 * grey, blue and Elementor-global respectively - so without this a page ends up
 * with three different primary buttons depending on which tool drew them. One
 * default is a brand decision, and the exceptions can opt out with
 * .ce-button--secondary.
 *
 * Elementor is included deliberately, but only its unstyled default: anything
 * given an explicit colour in the builder still carries a higher-specificity
 * inline rule and wins.
 */
button,
input[type='submit'],
input[type='button'],
input[type='reset'],
a.button,
.wp-block-button__link,
.wp-element-button,
.elementor-button {
	padding: 15px 30px;
	border: 1px solid transparent;
	border-radius: var(--ce-radius);
	background-color: var(--ce-color-brand);
	color: var(--ce-color-on-brand);
	font-family: var(--ce-font-body);
	font-size: 15px;
	font-weight: var(--ce-weight-medium);
	line-height: 1;
	text-decoration: none;
	transition:
		background-color var(--ce-transition),
		color var(--ce-transition);
}

button:hover,
button:focus,
input[type='submit']:hover,
input[type='submit']:focus,
input[type='button']:hover,
input[type='button']:focus,
input[type='reset']:hover,
input[type='reset']:focus,
a.button:hover,
a.button:focus,
.wp-block-button__link:hover,
.wp-block-button__link:focus,
.wp-element-button:hover,
.wp-element-button:focus,
.elementor-button:hover,
.elementor-button:focus {
	background-color: var(--ce-color-brand-hover);
	color: var(--ce-color-on-brand);
}

/* Header ------------------------------------------------------------------ */

/*
 * Sticky glass header, matching cmhworks.com: translucent dark with a backdrop
 * blur at every scroll position, shrinking from 135px to 70px once the page has
 * scrolled 100px.
 *
 * The background is not conditional on being scrolled - that site keeps the
 * glass on throughout, which is what lets the header sit over a hero without a
 * second, opaque state to design.
 */
.ce-header {
	position: sticky;
	z-index: 10;
	top: 0;

	/*
	 * A 40% black wash over a #0b0e14 page is all but invisible, so unlike
	 * cmhworks.com - whose header sits over imagery - this needs a hairline to
	 * exist at all when the content behind it is plain background. The wash
	 * still does its job over a hero.
	 */
	border-bottom: 1px solid var(--ce-color-border);
	background-color: rgb(0 0 0 / 40%);
	backdrop-filter: saturate(180%) blur(20px);
	-webkit-backdrop-filter: saturate(180%) blur(20px);
	transition: background-color 1s ease;
}

/*
 * No backdrop-filter support means the glass reads as a flat 40% black wash
 * over whatever is behind it, which is illegible against a busy hero. Fall back
 * to something solid enough to read.
 */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
	.ce-header {
		background-color: rgb(16 16 17 / 92%);
	}
}

.ce-header__inner {
	display: flex;
	align-items: center;
	gap: var(--ce-space-md);
	min-height: var(--ce-header-height);
	max-width: var(--ce-header-max);
	margin: 0 auto;
	padding: 0 var(--ce-space-md);
	transition: min-height 1s ease;
}

.ce-header.is-compact .ce-header__inner {
	min-height: var(--ce-header-height-compact);
}

/*
 * The logo steps down with the bar, because an 86px mark does not fit a 70px
 * header. Kept to a small step - see --ce-logo-height-compact - and on the
 * same one-second curve as the container so the two move together rather than
 * the logo snapping inside a still-animating bar.
 */
.ce-header__logo {
	flex: 0 0 auto;
	line-height: 0;
}

.ce-header__logo svg {
	display: block;
	width: auto;
	height: var(--ce-logo-height);
	transition: height 1s ease;
}

.ce-header.is-compact .ce-header__logo svg {
	height: var(--ce-logo-height-compact);
}

/* Dark glass means light type. */
.ce-header .ce-nav a,
.ce-header .ce-nav__heading {
	color: var(--ce-color-text);
}

.ce-header .ce-nav a:hover,
.ce-header .ce-nav a:focus {
	color: var(--ce-color-brand);
}

/*
 * Overlay mode: the header sits on top of the page rather than above it, so a
 * full-bleed hero shows through the glass. Pulled up by exactly its own height.
 *
 * Opt-in per page via the body class, because it only works where the first
 * section is designed to start underneath a 135px bar. Applied to the front
 * page by default - see centry_engine_header_overlay_body_class().
 */
.ce-header-overlay .ce-header {
	margin-bottom: calc(var(--ce-header-height) * -1);
}

@media (prefers-reduced-motion: reduce) {
	.ce-header,
	.ce-header__inner,
	.ce-header__logo svg {
		transition: none;
	}
}

.ce-header__nav {
	display: flex;
	flex: 1 1 auto;
	align-items: center;
	justify-content: flex-end;
	gap: var(--ce-space-md);
}

.ce-header__actions {
	display: flex;
	flex: 0 0 auto;
	gap: var(--ce-space-xs);
}

/*
 * The toggle is a <button>, so it would otherwise pick up the brand-orange
 * button defaults above. Later in the file, so these win.
 */
.ce-header__toggle {
	display: none;
	padding: var(--ce-space-xs);
	border: 0;
	background: none;
	color: var(--ce-color-text);
	cursor: pointer;
}

.ce-header__toggle:hover,
.ce-header__toggle:focus {
	background: none;
	color: var(--ce-color-brand);
}

.ce-header__toggle-bars,
.ce-header__toggle-bars::before,
.ce-header__toggle-bars::after {
	display: block;
	width: 24px;
	height: 2px;
	background: currentColor;
}

.ce-header__toggle-bars::before,
.ce-header__toggle-bars::after {
	content: '';
	position: relative;
}

.ce-header__toggle-bars::before {
	top: -7px;
}

.ce-header__toggle-bars::after {
	top: 5px;
}

/* Primary navigation ------------------------------------------------------ */

.ce-nav {
	display: flex;
	align-items: center;
	gap: var(--ce-space-md);
	margin: 0;
	padding: 0;
	list-style: none;
}

.ce-nav__item {
	position: relative;
}

.ce-nav a,
.ce-nav__heading {
	display: block;
	color: var(--ce-color-text);
	font-weight: var(--ce-weight-medium);
	text-decoration: none;
}

.ce-nav a:hover,
.ce-nav a:focus {
	color: var(--ce-color-brand);
}

/*
 * A group heading has no page behind it, so it is not a link. Cursor and
 * colour say "this opens something" without promising navigation.
 */
.ce-nav__heading {
	cursor: default;
}

.ce-nav__submenu {
	position: absolute;
	z-index: 20;
	top: 100%;
	left: 0;
	display: none;
	min-width: 220px;
	margin: 0;
	padding: var(--ce-space-xs) 0;
	border: 1px solid var(--ce-color-border);
	border-radius: var(--ce-radius);
	background: var(--ce-color-surface-raised);
	box-shadow: 0 8px 24px rgb(0 0 0 / 45%);
	list-style: none;
}

/*
 * A caret on any item that has a submenu, so the affordance is visible rather than
 * discovered by hovering. Drawn with a border rather than a glyph: no icon font, no
 * extra request, and it inherits the link's colour on hover with everything else.
 *
 * Decorative - the submenu is reachable by keyboard regardless, and a screen reader
 * announces the list itself - so it is a pseudo-element with no text.
 */
.ce-nav__item--has-children > a,
.ce-nav__item--has-children > .ce-nav__heading {
	display: inline-flex;
	gap: 0.4em;
	align-items: center;
}

.ce-nav__item--has-children > a::after,
.ce-nav__item--has-children > .ce-nav__heading::after {
	content: '';
	display: block;
	width: 0.4em;
	height: 0.4em;
	border-right: 2px solid currentColor;
	border-bottom: 2px solid currentColor;

	/* Points down, and lifted slightly so it reads as centred against the cap height. */
	transform: translateY(-0.15em) rotate(45deg);
	transition: transform var(--ce-transition);
}

.ce-nav__item--has-children:hover > a::after,
.ce-nav__item--has-children:focus-within > a::after,
.ce-nav__item--has-children:hover > .ce-nav__heading::after,
.ce-nav__item--has-children:focus-within > .ce-nav__heading::after {
	transform: translateY(0.05em) rotate(-135deg);
}

.ce-nav__item--has-children:hover > .ce-nav__submenu,
.ce-nav__item--has-children:focus-within > .ce-nav__submenu {
	display: block;
}

.ce-nav__submenu a {
	padding: var(--ce-space-xs) var(--ce-space-sm);
	font-weight: var(--ce-weight-regular);
	white-space: nowrap;
}

@media (max-width: 768px) {
	.ce-header__toggle {
		display: block;
		margin-left: auto;
	}

	.ce-header__nav {
		display: none;
		flex-basis: 100%;
		flex-direction: column;
		align-items: stretch;
		gap: var(--ce-space-sm);
	}

	.ce-header__nav.is-open {
		display: flex;
	}

	.ce-header__inner {
		flex-wrap: wrap;
	}

	.ce-nav {
		flex-direction: column;
		align-items: stretch;
		gap: var(--ce-space-xs);
	}

	.ce-nav__submenu {
		position: static;
		display: block;
		border: 0;
		box-shadow: none;
		padding-left: var(--ce-space-sm);
	}
}

/* Solution page sections (placeholder) ------------------------------------- */

/*
 * Section rhythm, top to bottom. The gap between sections is set here and nowhere else, so
 * --ce-section-gap is the one number that moves it.
 *
 * Margin, not padding. Padding sits inside the box and cannot change the space between two
 * of them - measured on the live page, raising it to 25px left the gap at 50px. The margins
 * collapse against each other, so the gap equals the value rather than twice it: 80 gives
 * 80, verified at 40 and 80 before this was written.
 *
 * .elementor prefixes it because Elementor's container output otherwise wins.
 */
.elementor .ce-solution__inner,
.ce-solution__inner {
	max-width: var(--ce-header-max);
	margin: var(--ce-section-gap) auto;
	padding: 0 var(--ce-space-md);
}

/*
 * The form follows the closing CTA directly, so the section's own bottom
 * padding would stack with it and leave a hole between the two.
 *
 * :has() rather than a negative margin, so the rule states the actual
 * condition - this section is followed by the form. Where :has() is
 * unsupported the padding simply stays, which is the old spacing rather than a
 * broken layout.
 */
.ce-solution:has(+ .ce-contact) .ce-solution__inner {
	padding-bottom: var(--ce-space-md);
}

.ce-solution__lede {
	margin: 0 auto var(--ce-section-gap);
	max-width: 30ch;
	color: var(--ce-color-heading);
	font-family: var(--ce-font-heading);
	font-size: var(--ce-text-2xl);
	text-align: center;
}

/*
 * Positioning uses the homepage's row-of-cards arrangement rather than a two-column
 * grid: centred, each card the same 260px ceiling the solution grid and the statistics
 * use. One card idiom across the site, and a product page that reads like the home page
 * it came from.
 */
.ce-solution__grid {
	display: flex;
	flex-wrap: wrap;
	gap: var(--ce-space-md);
	justify-content: center;
}

.ce-solution__block {
	flex: 1 1 200px;
	max-width: 260px;
	padding: var(--ce-space-sm);
	border: 1px solid var(--ce-color-border);
	border-radius: var(--ce-radius);
	background: var(--ce-color-surface-raised);
	text-align: center;
	transition: border-color var(--ce-transition);
}

.ce-solution__block:hover,
.ce-solution__block:focus-within {
	border-color: var(--ce-color-brand);
}

/* The card's own heading, in brand orange like every other card's. */
.ce-solution__block h2 {
	margin: 0 0 var(--ce-space-xs);
	color: var(--ce-color-brand);
	font-size: var(--ce-text-sm);
	font-weight: var(--ce-weight-medium);
	letter-spacing: 0.06em;
	text-transform: uppercase;
}

.ce-solution__block p {
	margin: 0;
	color: var(--ce-color-muted);
}

/* The same card, when the builder renders it as a container of widgets. */
.e-con.e-flex.ce-solution__grid {
	--flex-direction: row;
	--flex-wrap: wrap;
	--justify-content: center;
}

.e-con.ce-solution__block {
	--width: auto;
	--text-align: center;

	flex: 1 1 200px;
	max-width: 260px;
}

/* Cross-sell, required on every product section by the marketing plan §9. */
.ce-solution__cross {
	margin-top: var(--ce-section-gap);
	padding-top: var(--ce-space-md);
	border-top: 1px solid var(--ce-color-border);
}

.ce-solution__cross-title {
	margin: 0 0 var(--ce-space-sm);
	font-size: var(--ce-text-xl);
}

/*
 * Flex rather than grid, because the joiners between tiles must not take a
 * column of their own - they sit in the gap. auto-basis with wrap keeps the
 * tiles even and lets a narrow screen stack them.
 */
.ce-solution__cross-list {
	display: flex;
	flex-wrap: wrap;
	align-items: stretch;
	gap: var(--ce-space-sm);
	margin: 0;
	padding: 0;
	list-style: none;
}

.ce-solution__cross-list > li:not(.ce-solution__cross-join) {
	flex: 1 1 220px;
}

/* The two-way arrow between tiles. */
.ce-solution__cross-join {
	display: flex;
	flex: 0 0 auto;
	align-items: center;
	color: var(--ce-color-brand);
}

.ce-solution__cross-join svg {
	width: 22px;
	height: 22px;
}

/*
 * Once the tiles wrap to their own rows the arrow would sit sideways between
 * stacked cards, so it turns to point down the column instead.
 */
@media (max-width: 720px) {
	.ce-solution__cross-list {
		flex-direction: column;
	}

	.ce-solution__cross-join {
		justify-content: center;
	}

	.ce-solution__cross-join svg {
		transform: rotate(90deg);
	}
}

.ce-solution__cross-list a {
	display: block;
	height: 100%;
	padding: var(--ce-space-sm);
	border: 1px solid var(--ce-color-border);
	border-radius: var(--ce-radius);
	background: var(--ce-color-surface-raised);
	text-decoration: none;
	transition: border-color var(--ce-transition);
}

.ce-solution__cross-list a:hover,
.ce-solution__cross-list a:focus {
	border-color: var(--ce-color-brand);
}

.ce-solution__cross-name {
	display: block;
	color: var(--ce-color-heading);
	font-family: var(--ce-font-heading);
	font-weight: var(--ce-weight-medium);
}

.ce-solution__cross-line {
	display: block;
	margin-top: 0.15rem;
	color: var(--ce-color-muted);
	font-size: var(--ce-text-sm);
}

/* Sidebar ------------------------------------------------------------------ */

/*
 * Pin the two columns rather than leaving them to GeneratePress.
 *
 * It sets width:30% from Customizer and width:auto from its own stylesheet,
 * which wins on specificity - so the flex row ends up sized from content, and
 * the sidebar takes whatever its widest card demands.
 *
 * min-width:0 on the content column matters separately: a grid inside a flex
 * item will not shrink below its min-content width unless the item is allowed
 * to, and the card grid's 320px column floor makes that width large.
 */
.site-content .content-area {
	flex: 1 1 auto;
	min-width: 0;
}

.site-content .is-right-sidebar,
.site-content .is-left-sidebar {
	flex: 0 0 320px;
	width: auto;
	max-width: 100%;
}

/* GeneratePress stacks the columns here; let the sidebar span when it does. */
@media (max-width: 768px) {
	.site-content .is-right-sidebar,
	.site-content .is-left-sidebar {
		flex: 1 1 auto;
	}
}

/*
 * Both columns start at the same height. GeneratePress pads the article from its
 * stylesheet and the widgets from Customizer, so the tops were out by the
 * difference between the two.
 */
.inside-article,
.inside-right-sidebar,
.inside-left-sidebar {
	padding-top: var(--ce-column-pad);
}

/* GeneratePress' own widget padding goes; the cards below own their spacing. */
.widget-area .widget.inner-padding {
	padding: 0;
}

/*
 * A list panel is a heading plus a stack of cards, so the panel itself is not a
 * card - nesting one inside the other doubles the border and reads as a mistake.
 */
.sidebar .widget,
.widget-area .widget,
.ce-related {
	margin-bottom: var(--ce-space-md);
}

.sidebar .widget:last-child,
.widget-area .widget:last-child,
.ce-related:last-child {
	margin-bottom: 0;
}

/* Kimo is a single unit, so it stays one card. */
.ce-kimo {
	margin-bottom: var(--ce-space-md);
	padding: var(--ce-space-md) var(--ce-space-sm);
	border: 1px solid var(--ce-color-border);
	border-radius: var(--ce-radius);
	background: var(--ce-color-surface-raised);
	text-align: center;
}

.ce-kimo:last-child {
	margin-bottom: 0;
}

/*
 * One card per entry, in both lists. The search field is left alone - it is a
 * control, not an item in a list.
 */
/*
 * The section is the card, not each row. A card per row makes a list of four look like four
 * offers; one card with four rows in it looks like the list it is - and the sidebar reads as
 * three panels rather than eleven boxes.
 */
.ce-related {
	padding: var(--ce-space-sm);
	border: 1px solid var(--ce-color-border);
	border-radius: var(--ce-radius);
	background: var(--ce-color-surface-raised);
}

.ce-related__item + .ce-related__item,
.wp-block-latest-posts__list li + li {
	margin-top: var(--ce-space-xs);
	border-top: 1px solid var(--ce-color-border);
	padding-top: var(--ce-space-xs);
}

/*
 * One heading treatment across the sidebar, so a core widget title and the
 * theme's own panel title are the same thing. The uppercase, letter-spaced
 * version used before did not match any other heading on the site.
 */
.sidebar .widget .wp-block-heading,
.widget-area .widget .wp-block-heading,
.sidebar .widget .widget-title,
.widget-area .widget .widget-title,
.ce-related__title {
	margin: 0 0 var(--ce-space-sm);
	color: var(--ce-color-heading);
	font-family: var(--ce-font-heading);
	font-size: var(--ce-text-lg);
	font-weight: var(--ce-weight-medium);
	letter-spacing: normal;
	text-transform: none;
}

.sidebar .widget ul,
.widget-area .widget ul {
	margin: 0;
	padding: 0;
	list-style: none;
}

.sidebar .widget a,
.widget-area .widget a {
	text-decoration: none;
}

.sidebar .widget a:hover,
.widget-area .widget a:hover,
.sidebar .widget a:focus,
.widget-area .widget a:focus {
	text-decoration: underline;
}

/* Feature list ------------------------------------------------------------- */

.ce-features {
	margin-top: var(--ce-section-gap);
	padding-top: var(--ce-space-md);
	border-top: 1px solid var(--ce-color-border);
}

/*
 * Section titles centre over their row. The rows are centred as a group, so a title on
 * the section's left edge left everything below it starting a couple of hundred pixels
 * further in with nothing lined up.
 */
.ce-features__title,
.ce-showcase__title,
.ce-faq__title,
.ce-addons__title,
.ce-pricing__title,
.ce-stats__title,
.ce-solution__cross-title,
.ce-post-cta__title,
.ce-solution__cta-title {
	text-align: center;
}

.ce-features__title {
	margin: 0 0 var(--ce-space-md);
	font-size: var(--ce-text-xl);
}

/*
 * A centred row of 260px cards, the homepage's arrangement - not a grid that stretches
 * each card to a share of the full measure. Four features on a product page and four
 * solutions on the home page now sit in the same shape.
 */
.ce-features__list,
.e-con.ce-features__list {
	display: flex;
	flex-wrap: wrap;
	align-items: stretch;
	gap: var(--ce-space-md);
	justify-content: center;
	margin: 0;
	padding: 0;
	list-style: none;
}

.ce-features__list > .ce-features__item {
	flex: 1 1 200px;
	max-width: 260px;
}

.ce-features__list > .ce-features__item,
.ce-solution__grid > .ce-solution__block,
.ce-stats__row > .ce-stat,
.ce-solutions__row > .ce-solutions__card {
	--align-self: stretch;

	align-self: stretch;
}

/*
 * Flip-in on entry.
 *
 * ce-flip--ready is added by script, so without JavaScript none of this
 * applies and the cards are simply visible - the hidden state never outlives
 * the thing that undoes it.
 *
 * perspective sits on the list so the cards turn about a shared vanishing
 * point rather than each in its own flat space, which is what makes them read
 * as one panel turning instead of four unrelated ones.
 */
.ce-features__list {
	perspective: 1200px;
}

.ce-flip--ready .ce-features__item {
	opacity: 0;
	transform: rotateY(90deg);
	transform-origin: center left;
	transition:
		transform 900ms cubic-bezier(0.2, 0.7, 0.3, 1),
		opacity 600ms ease;
}

.ce-flip--ready.is-flipped-in .ce-features__item {
	opacity: 1;
	transform: none;
}

/* backface-visibility keeps the edge clean mid-turn on WebKit. */
.ce-features__item {
	backface-visibility: hidden;
}

/*
 * Each feature is a card, matching the treatment used for post cards and the
 * cross-sell tiles - one card idiom across the site rather than three.
 */
/*
 * No `height: 100%`. It reads as a definite height, which takes the card out of the row's
 * `align-items: stretch` and leaves each one as tall as its own text - measured on /smart
 * as 172, 145, 145 and 200 in one row. `align-self: stretch` is the thing that actually
 * equalises them, and it is set explicitly rather than inherited so it survives a card
 * being placed in a container that sets its own alignment.
 */
.ce-features__item {
	display: flex;
	flex-direction: column;
	align-self: stretch;
	padding: var(--ce-space-sm);
	border: 1px solid var(--ce-color-border);
	border-radius: var(--ce-radius);
	background: var(--ce-color-surface-raised);

	/* Centred, as the homepage's cards are. */
	text-align: center;
	transition: border-color var(--ce-transition);
}

.ce-features__item:hover,
.ce-features__item:focus-within {
	border-color: var(--ce-color-brand);
}

/* Brand orange, 7.15:1 on the raised surface. */
.ce-features__name {
	margin: 0 0 var(--ce-space-xs);
	color: var(--ce-color-brand);
	font-size: var(--ce-text-lg);
}

.ce-features__text {
	margin: 0;
	color: var(--ce-color-muted);
}

/* FAQ ---------------------------------------------------------------------- */

.ce-faq {
	margin-top: var(--ce-section-gap);
	padding-top: var(--ce-space-md);
	border-top: 1px solid var(--ce-color-border);
}

.ce-faq__title {
	margin: 0 0 var(--ce-space-md);
	font-size: var(--ce-text-xl);
}

/*
 * The line naming the document the answers summarise. Muted and small because it is
 * provenance rather than an answer, but --ce-color-muted at 10.14:1 so "small print"
 * stays a visual weight rather than something a reader has to work at.
 */
/*
 * Underlined, not just coloured. A link sitting inside a paragraph has to be
 * distinguishable without colour - axe flags this one as link-in-text-block, and it is
 * WCAG 1.4.1 rather than a preference.
 */
.ce-faq__source a,
.ce-legal-note a {
	color: inherit;
	text-decoration: underline;
	text-underline-offset: 0.2em;
}

.ce-faq__source a:hover,
.ce-faq__source a:focus-visible,
.ce-legal-note a:hover,
.ce-legal-note a:focus-visible {
	color: var(--ce-color-text);
}

.ce-faq__source {
	max-width: 70ch;
	margin: calc(var(--ce-space-md) * -1) 0 var(--ce-space-md);
	color: var(--ce-color-muted);
	font-size: var(--ce-text-sm);
}

/*
 * The accordion rows run the full width of the section - a 70ch cap left the
 * chevron floating in the middle of the page with dead space beside it. The
 * answer prose still keeps a reading measure; that is a line-length concern,
 * not a container one.
 */
.ce-faq__list {
	width: 100%;
}

.ce-faq__item {
	border-bottom: 1px solid var(--ce-color-border);
}

.ce-faq__item:first-child {
	border-top: 1px solid var(--ce-color-border);
}

/*
 * The default disclosure triangle is replaced with a chevron drawn from a
 * pseudo-element, so it can sit at the end of the row and rotate on open.
 */
.ce-faq__q {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--ce-space-sm);
	padding: var(--ce-space-sm) 0;
	color: var(--ce-color-heading);
	cursor: pointer;
	font-family: var(--ce-font-heading);
	font-size: var(--ce-text-lg);
	font-weight: var(--ce-weight-medium);
	list-style: none;
}

/* Safari still paints the marker without this. */
.ce-faq__q::-webkit-details-marker {
	display: none;
}

.ce-faq__q::after {
	content: '';
	flex: 0 0 auto;
	width: 0.6em;
	height: 0.6em;
	border-right: 2px solid var(--ce-color-brand);
	border-bottom: 2px solid var(--ce-color-brand);
	transform: rotate(45deg) translate(-0.1em, -0.1em);
	transition: transform var(--ce-transition);
}

.ce-faq__item[open] .ce-faq__q::after {
	transform: rotate(-135deg) translate(-0.15em, -0.15em);
}

.ce-faq__q:hover,
.ce-faq__q:focus-visible {
	color: var(--ce-color-brand);
}

.ce-faq__a {
	padding: 0 0 var(--ce-space-sm);
	color: var(--ce-color-muted);
}

.ce-faq__a p {
	max-width: 80ch;
	margin: 0;
}

/* Pricing ----------------------------------------------------------------- */

/*
 * Every value below is read from the rendered CSS of the pricing widgets on
 * centry-secure.io/#pricing - element 1fb133bc for a standard tier and 2dfab640
 * for the highlighted one - with their global colour variables resolved. Not
 * approximated, and not adjusted.
 *
 * Geometry is theirs; colour is ours. Every value here reads from a --ce-* token, so
 * the section stays consistent with the rest of the site and follows a token change
 * - which a copied hex would not. Their palette happens to match ours on border,
 * heading, text and muted; the brand is #ff8200 where theirs is #FF6000, and the two
 * darker surfaces are now tokens of their own.
 *
 * Note the card carries no padding of its own. Each block inside it does, at four
 * different values, which is what produces the spacing rhythm - and is impossible
 * to get right by putting padding on the card.
 */
.e-con.ce-pricing {
	--text-align: center;

	/*
	 * The section carries id="pricing", as Secure's does, so #pricing works both
	 * in-page and from another page. scroll-margin keeps the heading clear of the
	 * sticky header on arrival - keyed to the compact height, because by the time a
	 * link is followed the bar has already shrunk.
	 */
	scroll-margin-top: calc(var(--ce-header-height-compact) + var(--ce-space-md));
}

.ce-pricing__eyebrow {
	margin: 0 0 var(--ce-space-sm);
	color: var(--ce-color-heading);
	font-family: var(--ce-font-heading);
	font-size: 16px;
	font-weight: var(--ce-weight-medium);
	line-height: 1;
	letter-spacing: 0.08em;
	text-align: center;
	text-transform: uppercase;
}

.ce-pricing__title {
	margin: 0 0 var(--ce-space-md);
	font-size: clamp(2rem, 1.4rem + 2.4vw, 50px);
	font-weight: 600;
	text-align: center;
}

/* ---- Monthly / annual ---------------------------------------------------- */

/* Their switcher pads each half 12px 33px and squares the corners. */
.ce-pricing__switch {
	margin-bottom: var(--ce-space-lg);
	text-align: center;
}

.ce-billing {
	display: inline-flex;
	background: var(--ce-color-surface-control);
}

.ce-billing__input {
	position: absolute;
	width: 1px;
	height: 1px;
	opacity: 0;
}

.ce-billing__tab {
	padding: 12px 33px;
	color: var(--ce-color-muted);
	font-family: var(--ce-font-heading);
	font-size: 14px;
	font-weight: var(--ce-weight-medium);
	line-height: 20px;
	text-transform: uppercase;
	cursor: pointer;
	transition:
		background-color var(--ce-transition),
		color var(--ce-transition);
}

.ce-billing__input:checked + .ce-billing__tab {
	background: var(--ce-color-brand);
	color: var(--ce-color-heading);
}

.ce-billing__input:focus-visible + .ce-billing__tab {
	outline: 2px solid var(--ce-color-brand);
	outline-offset: 2px;
}

/* ---- The row ------------------------------------------------------------ */

/*
 * On the class itself, not only on `.e-con`. The deck is generated by
 * `[centry_pricing_cards]` now, so the grid is a plain div inside a shortcode widget
 * rather than an Elementor container - and this rule used to require `.e-con.e-flex`,
 * which meant the generated deck got no layout at all: three cards stacked full width,
 * the featured one a full-bleed orange block. It looked like a broken template and it
 * was a selector that no longer matched.
 *
 * 30px, which is the gap Secure has between its cards. At zero the tilt pulled the
 * outer two under the featured one and clipped their buttons - the overlap is the
 * rotation, not the spacing.
 */
.ce-pricing__grid {
	display: flex;
	flex-direction: row;
	gap: 30px;

	/*
	 * Stretch, not centre. Every card is the same width and the same height - the deck
	 * is one object, and the outer two are the same card rotated. Centring let each card
	 * take its own height, so a plan with a longer name or no unit stood shorter than its
	 * neighbours and the row read as three unrelated boxes.
	 */
	align-items: stretch;
	justify-content: center;
}

/* Elementor's own variables, for a deck that is still a builder container. */
.e-con.e-flex.ce-pricing__grid {
	--flex-direction: row;
	--gap: 30px;
}

/* ---- A standard tier ---------------------------------------------------- */

/*
 * 298px, which is what a card measures on centry-secure.io at 1440 - measured with
 * offsetWidth rather than a bounding rect, since two of the three are rotated and a
 * rect reports the rotated envelope. Ours rendered 360, which is the whole reason the
 * section read as oversized while every value inside it already matched.
 */
/*
 * A column, so the card can hold its parts apart: the action is pushed to the bottom
 * edge and every card ends at the same line however much is above it.
 */
.ce-price {
	display: flex;
	flex-direction: column;
	flex: 0 0 298px;
	position: relative;
	max-width: 298px;
	padding: 0;
	border: 1px solid var(--ce-color-border);

	/*
	 * The raised surface every other card on the site uses. Sunken is darker than the
	 * page itself, so the outer two cards read as holes beside the featured one instead
	 * of as the same object.
	 */
	background: var(--ce-color-surface-raised);
	text-align: left;
}

/*
 * Elementor's own 10px was winning here - `.e-con` applies padding from its variables,
 * so `padding: 0` above is discarded on a builder card and each one carried 10px on all
 * four sides. That is 20px of the width and 20px of the height difference on its own.
 */
.e-con.ce-price {
	--padding-top: 0px;
	--padding-right: 0px;
	--padding-bottom: 0px;
	--padding-left: 0px;

	/*
	 * And its 20px widget gap, which was adding another 60-odd px of height between the
	 * name, the price, the line of text and the button. Every one of those parts already
	 * carries the spacing Secure gives it as padding, so the gap was spacing counted
	 * twice.
	 */
	--gap: 0px;
	--row-gap: 0px;
	--column-gap: 0px;
}

/*
 * The tilt, on explicit classes rather than :first-child and :last-child.
 *
 * Two earlier attempts failed for different reasons and both were guesses. A plain
 * transform was fine - Elementor's own transform rule only applies to elements
 * carrying .e-transform, which these do not - but the positional selectors never
 * matched, because the grid's children are not only the three cards in every
 * context. Setting Elementor's --e-transform-* variables did nothing for the same
 * .e-transform reason.
 *
 * A class the template puts on the card cannot miss.
 */
.ce-price--left {
	transform: rotate(-5deg) translate(20px, 20px);
}

.ce-price--right {
	transform: rotate(5deg) translate(-20px, 20px);
}

/* 23px semibold on a 28px line, as theirs is - ours was 18px at body weight. */
.ce-price__name {
	margin: 0;
	padding: 40px 25px 0;
	color: var(--ce-color-heading);
	font-size: 23px;
	font-weight: var(--ce-weight-semibold);
	line-height: 28px;
}

/* price-wrap: 20px above, 30px below, 25px either side. */
.ce-price__amount {
	display: flex;
	margin: 20px 0 0;
	padding: 0 25px 30px;
	align-items: baseline;
}

/*
 * The figure's size lives here, on the wrapper, so the currency symbol can be
 * 0.36em *of the figure* - which is what calc(36em/100) means on Secure, where the
 * prefix is a child of the 76px price element rather than its sibling. Set on the
 * symbol alone it resolves against the inherited 16px and comes out at 6px.
 */
.ce-price__monthly,
.ce-price__annual {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	font-size: 58px;

	/* 0.9, theirs - a full line here is 7.6px taller per card at 76px. */
	line-height: 0.9;
}

@media (min-width: 769px) {
	.ce-price__monthly,
	.ce-price__annual {
		font-size: 76px;
	}
}

/* calc(36em/100) of the figure, top aligned, in their muted grey. */
.ce-price__currency {
	align-self: flex-start;
	padding: 2px 2px 0 0;
	color: var(--ce-color-muted);
	font-family: var(--ce-font-heading);
	font-size: 0.36em;
	line-height: 1;
}

.ce-price__figure {
	color: var(--ce-color-heading);
	font-family: var(--ce-font-heading);
	font-size: 1em;
	font-weight: var(--ce-weight-semibold);

	/* Inherits the wrapper's 0.9, which is the line Secure sets on its price. */
	line-height: inherit;
}

/*
 * The unit is data, not markup - [centry_plan_unit] returns "site" for Secure,
 * "seat" for Smart and nothing at all for Connect, which is priced flat. So the
 * separator after it is generated only when there is a unit to separate; hard
 * coding "/ site / month" would be wrong on two of the three products.
 */
.ce-price__per:not(:empty)::after {
	content: ' / ';
}

/*
 * Absolute 14px, so it does not scale with the figure above it, and on its own line -
 * "/ site / month" beside a 76px number pushed the figure off centre and read as part
 * of it.
 */
.ce-price__unit {
	flex: 0 0 100%;
	margin-left: 0;
	color: var(--ce-color-muted);
	font-size: 14px;
	line-height: 22px;
	white-space: nowrap;
}

/* footer: 32px below, and the button fills the column inside it. */
.ce-price__action {
	margin: 0;
	padding: 0 25px 32px;
}

.ce-price__action .elementor-button,
.ce-price__action .ce-button {
	display: block;
	width: 100%;
	padding: 15px;
	border: 0;

	/* 12px and semibold, theirs - not the site's 6px button radius. */
	border-radius: 12px;

	/* Brand orange on the plain cards; the featured card overrides it below, since
	   orange on orange is not a button. */
	background: var(--ce-color-brand);
	color: var(--ce-color-heading);
	font-size: 15px;
	font-weight: var(--ce-weight-semibold);
	line-height: 19px;
	text-align: center;
}

.ce-price__action .elementor-button:hover,
.ce-price__action .elementor-button:focus,
.ce-price__action .ce-button:hover,
.ce-price__action .ce-button:focus {
	background: var(--ce-color-brand-hover);
	color: var(--ce-color-heading);
}

/*
 * A tier's publication status, straight from the catalogue. Empty for an available
 * plan, so it takes no space until there is something to say.
 */
.ce-price__status:empty {
	display: none;
}

/*
 * Everything above flows from the top and the bottom group is pinned to the bottom, so a
 * name that wraps or a line that runs to two does not move the audience line up and down
 * from card to card - the prices align at the top, the line and the button align at the
 * bottom, and the slack sits in the middle where nothing is.
 */
.ce-price__who {
	margin-top: auto;
}

.ce-price:not(:has(.ce-price__who)) .ce-price__action {
	margin-top: auto;
}

/*
 * Who the plan is for, in the product's own words - `audience` on the plan, absent on
 * plenty of them. It was typed into each card once, which is why it disappeared when the
 * deck became generated: there was nothing to read it from. The catalogue owns the
 * sentence now, so it reads the same here as it does in the app.
 *
 * 14px on 1.6em, 25px sides, 15px below - the measurements the authored card used.
 */
.ce-price__who {
	padding: 0 25px 15px;
	color: var(--ce-color-text);
	font-size: 14px;
	line-height: 1.6em;
}

.ce-price__status {
	margin: 0 0 var(--ce-space-xs);
	padding: 0 25px;
	color: var(--ce-color-muted);
	font-size: var(--ce-text-sm);
	text-transform: capitalize;
}

/* ---- The highlighted tier ----------------------------------------------- */

/*
 * Brand fill, no border, no rotation, taller. Its price block carries 70px of
 * bottom padding against the standard 30px, which is what makes it taller rather
 * than a height being set anywhere.
 */
.ce-price--featured {
	z-index: 1;
	border: 0;
	background: var(--ce-color-brand);

	/* Upright and on top, as theirs is. */
	transform: none;
}

/*
 * Colour only. The featured card carried its own spacing - 50px above the name, 15px and
 * 70px around the price - which put every element on it a few pixels off its neighbours'.
 * One rhythm across the deck: the featured card differs by being orange and upright, not
 * by sitting differently.
 */
.ce-price--featured .ce-price__name {
	color: var(--ce-color-heading);
}

.ce-price--featured .ce-price__figure,
.ce-price--featured .ce-price__currency,
.ce-price--featured .ce-price__unit {
	color: var(--ce-color-heading);
}

.ce-price--featured .ce-price__who {
	color: color-mix(in srgb, var(--ce-color-heading) 80%, transparent);
}

/*
 * "Available" on the orange card, in the site's darkest surface rather than the muted
 * grey it inherits - grey on brand orange is 1.9:1 and unreadable. This is 12.4:1.
 */
.ce-price--featured .ce-price__status {
	color: var(--ce-color-surface-sunken);
}

.ce-price--featured .ce-price__action .elementor-button,
.ce-price--featured .ce-price__action .ce-button {
	background: var(--ce-color-surface-sunken);
	color: var(--ce-color-heading);
}

.ce-price--featured .ce-price__action .elementor-button:hover,
.ce-price--featured .ce-price__action .elementor-button:focus,
.ce-price--featured .ce-price__action .ce-button:hover,
.ce-price--featured .ce-price__action .ce-button:focus {
	background: var(--ce-color-surface-control);
	color: var(--ce-color-heading);
}

/* ---- Add-ons ------------------------------------------------------------ */

/*
 * A stacked row per add-on under the cards, listing what can be added to any tier.
 *
 * The price binds to [centry_addon_price] with an empty fallback, and an add-on the
 * API does not return for this product renders nothing - so the row removes itself
 * rather than showing a label with no price beside it. That is the whole conditional:
 * no flag to set, and a new add-on appears by being in the catalogue.
 *
 * They were shrink-wrapped boxes on one line at 16px, which read as a footnote to the
 * pricing rather than as things for sale. Each is now a card the width of the deck
 * above it, carrying the section's own idiom - the feature card's raised surface,
 * orange name and hover border - so an add-on is priced the way a plan is.
 */
.e-con.ce-addons {
	--text-align: center;

	max-width: var(--ce-container-max);

	/*
	 * Clears the deck, not the deck's box. The outer cards are rotated 5 degrees, so
	 * each one hangs about 26px below the row's own height and the heading here sat
	 * inside them at --ce-space-md.
	 */
	margin: var(--ce-space-lg) auto 0;
	padding: 0 var(--ce-space-md);
	text-align: center;
}

.ce-addons__title {
	margin: 0 0 var(--ce-space-md);
	font-size: var(--ce-text-xl);
	text-align: center;
}

.ce-addons__list {
	display: flex;
	flex-direction: column;
	gap: var(--ce-space-sm);
	align-items: center;
	margin: 0;
	padding: 0;
	list-style: none;
}

/*
 * 954px is three 298px pricing cards and the two 30px gaps between them, so a row
 * ends exactly where the deck does rather than near it.
 *
 * `flex-wrap` is what keeps a long add-on name from crushing the price: the price
 * and unit drop to their own line instead, which is also what happens on a phone.
 */
.ce-addon {
	display: flex;
	flex-wrap: wrap;
	gap: var(--ce-space-xs) var(--ce-space-sm);
	align-items: baseline;
	width: 100%;
	max-width: 954px;
	padding: var(--ce-space-sm) var(--ce-space-md);
	border: 1px solid var(--ce-color-border);
	border-radius: var(--ce-radius);
	background: var(--ce-color-surface-raised);
	text-align: left;
	transition: border-color var(--ce-transition);
}

.ce-addon:hover,
.ce-addon:focus-within {
	border-color: var(--ce-color-brand);
}

/* Not returned for this product, so not shown. */
.ce-addon:has(.ce-addon__price:empty) {
	display: none;
}

/*
 * And if none of them came back, the heading and the row go with them. Without this
 * a product with no add-ons still announces "Available Addons" above an empty line,
 * which is worse than saying nothing.
 */
.ce-addons:not(:has(.ce-addon__price:not(:empty))) {
	display: none;
}

/*
 * What the add-on is, in a line - the payload's `description`, absent on most of them.
 * Regular weight and muted beside the name deliberately: the name is the thing being
 * bought and this is the sentence that explains it, so it must not compete.
 *
 * It takes the slack between the name and the price, which is what used to push the
 * price right on its own.
 */
.ce-addon__desc {
	margin-right: auto;
	color: var(--ce-color-muted);

	/*
	 * The name's face and size, so the row reads as one line of type - at identical px
	 * the body face looks a size smaller than the heading one, which is what made this
	 * read as a caption. Weight and colour separate the two, not scale.
	 */
	font-family: var(--ce-font-heading);
	font-size: var(--ce-text-xl);
	font-weight: var(--ce-weight-regular);
	line-height: 1.2;
}

/* No description, so the name does the pushing. */
.ce-addon:not(:has(.ce-addon__desc)) .ce-addon__label {
	margin-right: auto;
}

/*
 * Brand orange, as every card title on these pages is - .ce-features__name sets the
 * same colour at the same size. `margin-right: auto` is what pushes the price and the
 * unit to the right edge: the shortcode emits three sibling spans and no wrapper, so
 * `justify-content: space-between` would strand the price in the middle.
 */
.ce-addon__label {
	color: var(--ce-color-brand);
	font-family: var(--ce-font-heading);
	font-size: var(--ce-text-xl);
	font-weight: var(--ce-weight-semibold);
	line-height: 1.2;
}

/*
 * 32px: large enough to be the thing the eye lands on, and deliberately well under the
 * tier price's 76px, because an add-on that outweighs the plan it attaches to reads as
 * the main offer.
 */
.ce-addon__price {
	color: var(--ce-color-heading);
	font-family: var(--ce-font-heading);
	font-size: 32px;
	font-weight: var(--ce-weight-semibold);
	line-height: 1;
}

/*
 * The unit comes from [centry_addon_unit], so the separator is generated rather than
 * typed - the same reason the plan unit's is. An add-on with no unit reads
 * "White-label $65" rather than "White-label $65 /".
 */
.ce-addon__unit:not(:empty)::before {
	content: '/ ';
}

.ce-addon__unit {
	color: var(--ce-color-muted);
	font-size: 14px;
	line-height: 22px;
}

/* ---- Which price shows ------------------------------------------------- */

.ce-price__annual {
	display: none;
}

/*
 * A card whose figure is empty removes itself.
 *
 * The deck is generated from the payload now, so a product that publishes nothing has no
 * cards at all rather than a row of blanks - this rule is the second line, for a plan
 * that is published with no figure to print. Connect's Enterprise is exactly that, and it
 * is skipped before it reaches the markup (ADR 0016) precisely because being hidden by a
 * stylesheet is not the same as a decision anyone recorded.
 *
 * The em-dash fallbacks this rule used to be defeated by are gone with the authored
 * cards.
 */
.ce-price:has(.ce-price__figure:empty) {
	display: none;
}

.ce-pricing.is-annual .ce-price__monthly,
.ce-pricing:has(#ce-billing-a:checked) .ce-price__monthly {
	display: none;
}

.ce-pricing.is-annual .ce-price__annual,
.ce-pricing:has(#ce-billing-a:checked) .ce-price__annual {
	display: flex;
}

/*
 * Below their tablet step the padding tightens to 20px and the price drops to
 * 58px, both of which are already handled above; the cards also stop leaning,
 * because a tilted card in a single column reads as broken rather than as a deck.
 */
@media (max-width: 900px) {
	.ce-pricing__grid {
		flex-wrap: wrap;
		gap: var(--ce-space-md);
	}

	.ce-price,
	.ce-price--left,
	.ce-price--right {
		flex: 1 1 260px;
		transform: none;
	}

	.ce-price__name {
		padding: 30px 20px 15px;
	}

	.ce-price__amount,
	.ce-price--featured .ce-price__amount {
		padding: 0 20px 20px;
	}

	.ce-price__who {
		padding: 0 20px 15px;
	}

	.ce-price__action {
		padding: 0 20px 25px;
	}
}

/* Statistics -------------------------------------------------------------- */

/*
 * The platform figures, as on centry-secure.io's home page: a row of large numbers
 * that count up, with a label under each.
 *
 * Elementor's Counter widget with its Ending Number bound to the Centry Stat dynamic
 * tag, format "value" - the exact number, because a counter counts to it. Nothing is
 * typed, and the count-up is the widget's own.
 *
 * A statistic the API does not return resolves to the tag's empty fallback, so the
 * counter renders nothing and its card removes itself; if none come back the row
 * goes with them.
 */
.ce-stats__row {
	display: flex;
	flex-wrap: wrap;
	gap: var(--ce-space-md);
	justify-content: center;
	margin: 0;
	padding: 0;
	list-style: none;
}

.ce-stats__row > .ce-stat {
	flex: 1 1 200px;
	max-width: 260px;
	padding: var(--ce-space-md) var(--ce-space-sm);
	border: 1px solid var(--ce-color-border);
	border-radius: var(--ce-radius);
	background: var(--ce-color-surface-raised);
	text-align: center;
	transition: border-color var(--ce-transition);
}

.ce-stats__row > .ce-stat:hover,
.ce-stats__row > .ce-stat:focus-within {
	border-color: var(--ce-color-brand);
}

/*
 * Not returned, so not shown - and the section goes if none of them are.
 *
 * Keyed on .ce-stat__figure, which is what the loop renders. These rules were written
 * for the Counter version and still named .elementor-counter-number after it was
 * replaced: the loop has no such element, so `:has()` was false, `:not()` inverted it,
 * and the section was display: none with nine cards inside it.
 */
.ce-stat:has(.ce-stat__figure:empty) {
	display: none;
}

.ce-stats:not(:has(.ce-stat__figure:not(:empty))) {
	display: none;
}

/*
 * The product a figure came from, as a badge at the top of the card. Empty until the
 * payload carries a product slug per statistic, and hidden while it is - so it costs
 * nothing today and needs no edit when the data arrives.
 *
 * Brand fill with --ce-color-on-brand rather than white: white on this orange is
 * 2.49:1. This is our own element, not one being matched to Secure.
 */
.ce-stat__badge:empty {
	display: none;
}

.ce-stat__badge {
	display: inline-block;
	margin: 0 auto var(--ce-space-sm);
	padding: 0.2em 0.7em;
	border-radius: 999px;
	background: var(--ce-color-brand);
	color: var(--ce-color-on-brand);
	font-family: var(--ce-font-heading);
	font-size: var(--ce-text-sm);
	font-weight: var(--ce-weight-medium);
	letter-spacing: 0.04em;
	text-transform: uppercase;
}

.ce-stat__figure {
	color: var(--ce-color-heading);
	font-family: var(--ce-font-heading);
	font-size: clamp(2.5rem, 2rem + 2vw, 4rem);
	font-weight: 600;
	line-height: 1;
}

.ce-stat__label {
	margin-top: var(--ce-space-xs);
	color: var(--ce-color-text);
	font-family: var(--ce-font-heading);
	font-size: var(--ce-text-lg);
	font-weight: var(--ce-weight-medium);
	line-height: 1.3;
	text-align: center;

	/* Two words on two lines rather than one clipped one. */
	overflow-wrap: break-word;
	text-wrap: balance;
}

/* Solution and audience cards --------------------------------------------- */

/*
 * The solution grid is a row of cards with a two-way arrow between each pair, the
 * same arrangement as the cross-sell strip on a product page - the platform reads as
 * connected rather than as four separate things.
 *
 * The arrow is decorative: the heading above says the products work together, so it
 * is aria-hidden and never the only carrier of that meaning. [centry_svg] without a
 * label sets that automatically.
 */
.e-con.e-flex.ce-solutions__row {
	--flex-direction: row;
	--flex-wrap: wrap;
	--justify-content: center;

	gap: var(--ce-space-sm);
	align-items: stretch;
	justify-content: center;
}

.ce-solutions__row > .ce-solutions__card {
	--width: auto;
	--text-align: center;

	text-align: center;

	flex: 1 1 200px;
	max-width: 260px;
}

.ce-solutions__row > .ce-solutions__join {
	--width: auto;

	flex: 0 0 auto;
	align-self: center;
}

/*
 * Once the cards wrap, an arrow pointing sideways between stacked cards is wrong -
 * and rotating four of them is worse than dropping them. The heading already carries
 * the meaning.
 */
@media (max-width: 900px) {
	.ce-solutions__join {
		display: none;
	}

	.ce-solutions__card {
		max-width: none;
	}
}

/*
 * The solution grid reuses the feature-card idiom rather than inventing a second
 * card. Its only difference is the wordmark in place of a heading, which needs a
 * height so four marks of different proportions line up.
 */
.ce-solution-card__mark {
	display: block;
	margin: 0 auto var(--ce-space-md);
}

.ce-solution-card__mark svg {
	display: block;

	/*
	 * Fills the card rather than sitting in it. 34px was set to line four marks of
	 * different proportions up on a shared baseline, which it did - at a size that
	 * read as a footnote next to the heading beside it.
	 */
	width: 100%;
	max-width: 200px;
	height: auto;
}

/* Kimo introduction ------------------------------------------------------- */

/*
 * The full-width introduction, as opposed to the sidebar card in
 * template-parts/kimo-card.php. Figure beside the text, stacking under 768px.
 */
/*
 * Two columns, as a grid rather than a flex row.
 *
 * Elementor gives every container width: 100% from --width, and applies flex-grow,
 * flex-shrink and flex-basis from its own variables - so a flex row of two containers
 * fights all four, and losing any one of them puts them back in a stack. That is what
 * three attempts at this ran into.
 *
 * In a grid it does not matter: a child at width 100% is 100% of its column. The
 * columns are declared here and Elementor's own values are left alone.
 */
.e-con.ce-kimo-intro {
	/*
	 * --display, not display. Elementor puts e-flex on the container and
	 * `.e-con.e-flex { display: flex }` is also two classes, so declaring display
	 * here ties and loses on load order - which is what the grid attempt ran into.
	 * It applies display from this variable, so setting the variable wins outright.
	 */
	--display: grid;

	display: grid;
	grid-template-columns: 260px minmax(0, 100ch);
	gap: var(--ce-space-lg);
	align-items: center;

	/*
	 * The pair centres as one block. Both columns are sized - 260px and up to 100ch -
	 * so the grid is narrower than the page measure, and justify-content puts the
	 * leftover space either side of the two rather than all of it after them.
	 */
	justify-content: center;
}

@media (max-width: 768px) {
	.e-con.ce-kimo-intro {
		--display: grid;

		grid-template-columns: minmax(0, 1fr);
	}
}

.ce-kimo-intro__mark svg {
	display: block;
	width: 100%;
	height: auto;
}

/* Contact details --------------------------------------------------------- */

/* Prose, so it keeps a reading measure inside the page one. */
.ce-contact-details__inner,
.ce-contact-details p {
	max-width: 65ch;
}

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

/*
 * For a page whose hero is an introduction rather than a launch - a service page,
 * contact, a thank you. Same hero, less of it.
 */
.ce-hero--compact .ce-hero__inner {
	padding-top: var(--ce-space-lg);
	padding-bottom: var(--ce-space-lg);
	min-height: 0;
}

/*
 * The FAQ carries more space than the shared section step. It is a block of rules with
 * no card or fill of its own, so it runs into whatever follows it without more room
 * around it than a section that has edges.
 */
.e-con.ce-faq {
	--margin-top: var(--ce-space-lg);
	--margin-bottom: var(--ce-space-xl);
}

/*
 * The theme declares margin-top: var(--ce-section-gap) on both of these, and Elementor
 * discards it - it applies margin-block-start from --margin-top, which defaults to 0.
 * So the 96px above a CTA or an FAQ never existed in a builder-rendered page and only
 * the 50px below it did.
 */
.e-con.ce-post-cta {
	--margin-top: var(--ce-space-lg);
	--margin-bottom: var(--ce-space-xl);
}

/* Containers are containers, even when Elementor forgets ------------------ */

/*
 * Elementor renders a container as `display: var(--display)` and writes --display into
 * the CSS file it generates per page. A section inserted after that file was last written
 * has no entry in it, so --display resolves to nothing, the declaration is invalid, and
 * the container falls back to `display: inline`.
 *
 * An inline box discards max-width, padding and vertical margins outright. That is why
 * /secure had no page margins at all while the home page had them, and why the measure
 * below looked like it was not working: the FAQ, the pricing section and the CTA on that
 * page were inline boxes. Regenerating Elementor's CSS fixes it until the next import;
 * this makes the theme not depend on that file having been rewritten.
 *
 * Attribute selector so it covers every section without a list to maintain, and two
 * compound selectors so it outranks `.e-con` on load order.
 */
.e-con[class*='ce-'] {
	display: flex;
}

/*
 * And a direction, for the same reason. `.e-con.e-flex { --flex-direction: column }` is
 * Elementor's, at two classes, loading after this file - so a two-class rule here ties
 * and loses, and every row on the page stacked. Three classes, and the row containers
 * say so once.
 */
.e-con.e-flex.ce-features__list,
.e-con.e-flex.ce-stats__row {
	--flex-direction: row;
	--flex-wrap: wrap;
	--justify-content: center;
}

/*
 * The add-ons list stacks, so it wants Elementor's own default direction rather than
 * the row above - stated at three classes for the same reason the row is, so it is a
 * decision in this file rather than whatever wins the cascade.
 */
.e-con.e-flex.ce-addons__list {
	--flex-direction: column;
	--align-items: center;
}

.e-con.ce-kimo-intro {
	display: grid;
}

/* The page measure ------------------------------------------------------- */

/*
 * Full width does not mean edge to edge. Every section carries the same gutter the
 * hero does, so its content starts on exactly the left edge of the hero's text and
 * ends the same distance from the right - at any viewport width, without a measure
 * that has to agree with the hero's.
 *
 * The hero already applies the gutter itself, and its inner is left aligned inside it.
 * Centring these on --ce-page-max instead put them on a different left edge the moment
 * the viewport passed the measure, which is the mistake this replaces.
 */
/*
 * Every selector here carries three classes, and that is the point. A container built
 * with content width "full" gets `.e-con-full`, which Elementor styles as
 * `.e-con.e-con-full { max-width: 100% }` - two classes, and its stylesheet loads after
 * this one, so the two-class version of this rule tied and lost. The measure below was
 * in the file for a day and never applied: every section rendered edge to edge with only
 * its 32px padding, which is the "margins are too narrow" this fixes.
 */
.e-con.e-con-full.ce-features,
.e-con.e-con-full.ce-faq,
.e-con.e-con-full.ce-pricing,
.e-con.e-con-full.ce-stats,
.e-con.e-con-full.ce-kimo-intro,
.e-con.e-con-full.ce-contact-details,
.e-con.e-con-full.ce-post-cta,
.e-con.e-con-full.ce-solution__inner {
	/*
	 * The same construct the hero's inner uses - a measure with automatic side
	 * margins, inside the page gutter - so a section's content lands on exactly the
	 * hero text's left edge at any width. Set through Elementor's margin variables
	 * because .e-con applies its margins from those, so `margin: 0 auto` here would be
	 * discarded.
	 */
	--margin-right: auto;
	--margin-left: auto;
	--padding-left: var(--ce-page-gutter);
	--padding-right: var(--ce-page-gutter);

	max-width: calc(var(--ce-page-max) + var(--ce-page-gutter) * 2);
}

/* Builder pages are full width -------------------------------------------- */

/*
 * GeneratePress wraps the content in a 1200px container and pads the article inside
 * it. A section built in Elementor sits inside both, so "full width" in the builder
 * only ever means "as wide as the article column".
 *
 * On a page built in the builder the container gets out of the way and each section
 * decides its own measure - which is what the sections already do: .ce-pricing and
 * .ce-stats hold themselves to --ce-container-max, .ce-hero runs edge to edge.
 *
 * Only these pages. A page written in the editor keeps the container, because prose
 * needs a measure.
 */
.ce-builder .site.container,
.ce-builder .site-content,
.ce-builder .content-area {
	max-width: none;
	padding: 0;
}

.ce-builder .inside-article {
	padding: 0;
}

.ce-builder .entry-content {
	margin-top: 0;
}

/* Section spacing --------------------------------------------------------- */

/*
 * Every section container gets 50px after it, set through Elementor's own
 * --margin-bottom because `.e-con` reads its margins from variables - a plain
 * margin-bottom here is discarded the same way text-align was.
 *
 * Qualified with .e-con so the selector carries two classes. `.e-con` itself sets
 * --margin-bottom: 0px and its stylesheet loads after this file, so a single-class
 * rule ties on specificity and loses on order - which is why the spacing did not
 * appear the first time.
 *
 * Section level only. A grid or an action row inside one is spaced by its gap, and
 * giving it a bottom margin as well is what produces uneven stacks.
 */
.e-con.ce-hero,
.e-con.ce-pricing,
.e-con.ce-features,
.e-con.ce-faq,
.e-con.ce-post-cta,
.e-con.ce-solution__inner,
.e-con.ce-proof-points,
.e-con.ce-kimo-intro,
.e-con.ce-contact-details,
.e-con.ce-stats {
	--margin-bottom: var(--ce-section-space);
}

/* Elementor container properties ------------------------------------------ */

/*
 * Alignment on a container has to be set through Elementor's own custom
 * properties, not the CSS properties.
 *
 * Its frontend stylesheet declares `text-align: var(--text-align)` on
 * `.e-con-full, .e-con > .e-con-inner`, with `--text-align: initial` on `.e-con`,
 * and `justify-content` / `flex-direction` on
 * `.elementor-element:where(.e-con-full, .elementor-widget)`. The `:where()` adds no
 * specificity, so those rules tie with ours at 0,1,0 and win on load order - the
 * per-post CSS is enqueued after this file.
 *
 * So a plain `text-align: center` on a container class is silently discarded. That
 * is what left the closing CTA left-aligned, and it is the same mechanism that made
 * the card tilt and the button row fail earlier. Anything below is a container in a
 * template; anything styled by element or widget class is unaffected.
 */
/*
 * Every selector below carries `.e-con` for exactly the reason the comment gives: at one
 * class these tie with Elementor's own and lose on load order. They were written at one
 * class, which is why the closing CTA's buttons stayed left-aligned after being "fixed".
 */
.e-con.ce-pricing,
.e-con.ce-post-cta,
.e-con.ce-solution__cta {
	--text-align: center;
}

.e-con.ce-price,
.e-con.ce-price--left,
.e-con.ce-price--featured,
.e-con.ce-price--right {
	--text-align: left;
}

.e-con.ce-pricing__grid,
.e-con.ce-post-cta__actions,
.e-con.ce-solution__cta-actions {
	--justify-content: center;
}

.e-con.e-flex.ce-post-cta__actions,
.e-con.e-flex.ce-solution__cta-actions,
.e-con.e-flex.ce-hero__actions {
	--flex-direction: row;
	--flex-wrap: wrap;
}

/*
 * The action row is a container, so it fills the section and its own justify-content is
 * what positions the buttons. Left in the hero, where the copy is left aligned; centred
 * under a CTA, where the heading is centred.
 */
.e-con.ce-hero__actions {
	--justify-content: flex-start;
}

/* Closing CTA -------------------------------------------------------------- */

/*
 * One treatment, two placements: the foot of a solution page and the foot of an
 * article. Grouped rather than duplicated - two CTAs that differ only in which
 * template rendered them would drift the first time one was touched.
 */
.ce-solution__cta,
.ce-post-cta {
	margin-top: var(--ce-section-gap);
	padding: var(--ce-space-md);
	border: 1px solid var(--ce-color-border);
	border-radius: var(--ce-radius);
	background: var(--ce-color-surface-raised);
	text-align: center;
}

.ce-solution__cta-title,
.ce-post-cta__title {
	margin: 0 0 var(--ce-space-sm);
	font-size: var(--ce-text-xl);
	text-align: center;
}

/*
 * Centred on the elements, not left to inherit the container's --text-align. In the
 * builder the heading came out left while the paragraph beside it centred, so
 * inheritance was not reaching every widget.
 */
.ce-post-cta,
.ce-post-cta__text,
.ce-post-cta .elementor-widget-heading,
.ce-post-cta .elementor-widget-text-editor {
	text-align: center;
}

.ce-post-cta__text {
	max-width: 52ch;
	margin: 0 auto var(--ce-space-md);
	color: var(--ce-color-muted);
}

.ce-solution__cta-actions,
.ce-post-cta__actions {
	display: flex;
	flex-wrap: wrap;
	gap: var(--ce-space-sm);
	justify-content: center;
	margin: 0;
}

/* Contact form ------------------------------------------------------------- */

/*
 * Sits directly under the closing CTA with no gap of its own - the section
 * above already ends with one, and stacking a second read as a hole in the page.
 *
 * No background band. An earlier version gave it a raised full-bleed surface to
 * "close the page", which made the form look full width when only the band was;
 * the fields were always capped. The container now matches every other section.
 */
.ce-contact {
	/*
	 * The header is sticky, so an anchor jump would otherwise land with the
	 * heading hidden behind it. scroll-margin pushes the landing point clear,
	 * keyed to the compact height because by the time you follow an in-page
	 * link the bar has already shrunk.
	 */
	scroll-margin-top: calc(var(--ce-header-height-compact) + var(--ce-space-md));
}

.ce-contact__inner {
	max-width: 760px;
	margin: 0 auto;
	padding: 0 var(--ce-space-md) var(--ce-section-gap);
}

.ce-contact__notice {
	margin: 0 0 var(--ce-space-md);
	padding: var(--ce-space-sm);
	border-left: 3px solid var(--ce-color-brand);
	background: var(--ce-color-surface-raised);
}

.ce-contact__notice--error {
	border-left-color: var(--ce-color-danger);
}

.ce-contact__row {
	display: grid;
	gap: var(--ce-space-sm);
	grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
}

.ce-contact__field {
	margin: 0 0 var(--ce-space-sm);
}

.ce-contact__field label {
	display: block;
	margin-bottom: 0.35rem;
	font-family: var(--ce-font-heading);
	font-size: var(--ce-text-sm);
	font-weight: var(--ce-weight-medium);
}

/*
 * Field styling is global rather than scoped to this form. A search widget, a
 * comment box or an Elementor form should not each look different - one field
 * idiom, wherever the field came from.
 */
input[type='text'],
input[type='email'],
input[type='url'],
input[type='tel'],
input[type='number'],
input[type='password'],
input[type='search'],
input[type='date'],
select,
textarea {
	width: 100%;
	padding: var(--ce-field-padding);
	border: 1px solid var(--ce-color-field-border);
	border-radius: var(--ce-field-radius);

	/*
	 * Transparent, as on centry-secure.io, rather than a fill of its own. It
	 * matters wherever a form sits on something other than the page background:
	 * a solid fill would draw a second, slightly-off rectangle inside the card
	 * behind it.
	 */
	background: transparent;
	color: var(--ce-color-text);
	font-family: inherit;
	font-size: var(--ce-field-size);
	transition: border-color var(--ce-transition);
}

/* Placeholders are muted, never mistaken for a filled value. */
::placeholder {
	color: var(--ce-color-muted);
	opacity: 1;
}

input:focus,
select:focus,
textarea:focus {
	border-color: var(--ce-color-brand);
	outline: 2px solid var(--ce-color-brand);
	outline-offset: 1px;
}

/*
 * Only styled once the field has been interacted with. :invalid alone paints
 * every empty required field red before anyone has typed anything, which reads
 * as a page full of errors on arrival.
 */
input:user-invalid,
select:user-invalid,
textarea:user-invalid {
	border-color: var(--ce-color-danger);
}

/*
 * Honeypot. Moved off-screen rather than display:none, because some bots skip
 * anything that is not rendered - which would defeat the point of it.
 */
/*
 * Consent and opt-in. Each label wraps its own checkbox, so the text is part of
 * the click target - a 16px box on its own is a small thing to hit.
 */
.ce-contact__consent {
	display: grid;
	gap: var(--ce-space-xs);
	margin-bottom: var(--ce-space-md);
}

.ce-contact__check {
	display: grid;
	grid-template-columns: auto 1fr;
	gap: var(--ce-space-xs);
	align-items: start;
	color: var(--ce-color-muted);
	font-size: var(--ce-text-sm);
	line-height: 1.45;
	cursor: pointer;
}

/*
 * accent-color rather than a rebuilt control. A restyled checkbox loses the
 * platform's own focus ring, indeterminate state and high-contrast handling, and
 * gains nothing here beyond the tick being orange.
 */
.ce-contact__check input[type='checkbox'] {
	width: 1rem;
	height: 1rem;

	/* The global field rule stretches inputs to 100%; a checkbox is exempt. */
	min-width: 1rem;
	margin: 0.2rem 0 0;
	padding: 0;
	border-radius: 3px;
	accent-color: var(--ce-color-brand);
}

/*
 * Underlined, not just orange. A link inside a sentence has to be findable
 * without colour vision, and WCAG wants 3:1 between link text and the copy
 * around it before colour alone can carry it - brand orange against this muted
 * grey is nowhere near that. The consent label is the case that exists today: a
 * sentence with "Privacy Policy" in the middle of it.
 *
 * Deliberately not a global rule on `a`. Navigation items, buttons and
 * whole-card links are distinguishable by position and shape already, and
 * underlining those is noise rather than accessibility.
 */
.ce-contact__check a,
.elementor-widget-theme-post-content a:not(.ce-button),
/*
 * The footer copy of the same form needs the extra class to win: `.ce-footer a`
 * sets text-decoration: none at the same specificity a thousand lines further
 * down, so the single-class rule lost to it and the newsletter consent link
 * stayed underline-free. That is the form Lighthouse was reporting.
 */
.ce-footer .ce-contact__check a {
	color: var(--ce-color-brand);
	text-decoration: underline;
	text-underline-offset: 0.15em;
}

.ce-contact__hp {
	position: absolute;
	left: -9999px;
	width: 1px;
	height: 1px;
	overflow: hidden;
}

.ce-contact__actions {
	display: flex;
	align-items: center;
	gap: var(--ce-space-sm);
	margin: var(--ce-space-sm) 0 0;
}

.ce-contact__required {
	color: var(--ce-color-muted);
	font-size: var(--ce-text-sm);
}

.ce-contact__title {
	margin: 0 0 var(--ce-space-xs);
	font-size: var(--ce-text-2xl);
}

/*
 * The second line of the heading - the question, then the action. Its own line, in brand
 * orange at the size of the section labels, so it reads as the answer to the line above
 * rather than as a longer heading that happens to wrap.
 */
.ce-contact__title-action {
	display: block;
	color: var(--ce-color-brand);
	font-size: var(--ce-text-lg);
}

.ce-contact__lead {
	margin: 0 0 var(--ce-space-md);
	max-width: 60ch;
	color: var(--ce-color-muted);
}

/* Related articles, and the Recent Posts widget that sits beside it --------- */

/*
 * The core Latest Posts block is given the same row treatment as the theme's
 * related panel. Two lists of articles in one column should not look like two
 * different components.
 */
.wp-block-latest-posts__list {
	margin: 0;
	padding: 0;
	list-style: none;
}

.wp-block-latest-posts__list li {
	display: flex;
	align-items: flex-start;
	gap: var(--ce-space-xs);
}

.wp-block-latest-posts__featured-image {
	flex: 0 0 64px;
	margin: 0;
	line-height: 0;
}

.wp-block-latest-posts__featured-image img {
	width: 64px;
	height: 64px;
	border-radius: var(--ce-radius);
	object-fit: cover;
}

.wp-block-latest-posts__post-title {
	color: var(--ce-color-text);
	font-family: var(--ce-font-heading);
	font-size: var(--ce-text-sm);
	font-weight: var(--ce-weight-medium);
	line-height: 1.35;
	text-decoration: none;
}

.wp-block-latest-posts__post-title:hover,
.wp-block-latest-posts__post-title:focus {
	color: var(--ce-color-brand);
	text-decoration: underline;
}

/* Related articles --------------------------------------------------------- */

.ce-related__list {
	margin: 0;
	padding: 0;
	list-style: none;
}

/*
 * The thumbnail is decorative - the title beside it is the link text - so it
 * carries an empty alt and does not need to be reachable separately.
 */
.ce-related__link {
	display: flex;
	align-items: flex-start;
	gap: var(--ce-space-xs);
	color: var(--ce-color-text);
	text-decoration: none;
}

.ce-related__link:hover .ce-related__text,
.ce-related__link:focus .ce-related__text {
	color: var(--ce-color-brand);
	text-decoration: underline;
}

.ce-related__thumb {
	flex: 0 0 64px;
	line-height: 0;
}

.ce-related__thumb img {
	width: 64px;
	height: 64px;
	border-radius: var(--ce-radius);
	object-fit: cover;
}

.ce-related__text {
	font-family: var(--ce-font-heading);
	font-size: var(--ce-text-sm);
	font-weight: var(--ce-weight-medium);
	line-height: 1.35;
}

/* The search card's form, so it matches the fields everywhere else on the site. */
.ce-search .search-form,
.ce-search form {
	display: flex;
	gap: var(--ce-space-xs);
}

.ce-search input[type='search'] {
	flex: 1 1 auto;
	min-width: 0;
}

/* Kimo card --------------------------------------------------------------- */

/*
 * Centred and capped only where it stands alone - at the foot of the archive.
 * In a sidebar it is one card in a column and fills it.
 */
.no-sidebar .ce-kimo {
	max-width: 640px;
	margin-top: var(--ce-section-gap);
	margin-right: auto;
	margin-left: auto;
}

/*
 * The mascot is inline SVG, so it scales without a second asset. The ring
 * behind it picks up the same motif as the brand mark.
 */
.ce-kimo__figure {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 140px;
	height: 140px;
	margin: 0 auto var(--ce-space-sm);
	border: 1px solid var(--ce-color-border);
	border-radius: 50%;
	background: var(--ce-color-surface);
}

.ce-kimo__figure svg {
	width: 104px;
	height: 104px;
}

.ce-kimo__eyebrow {
	margin: 0 0 0.25rem;
	color: var(--ce-color-brand);
	font-family: var(--ce-font-heading);
	font-size: 0.75rem;
	font-weight: var(--ce-weight-medium);
	letter-spacing: 0.08em;
	text-transform: uppercase;
}

.ce-kimo__title {
	margin: 0 0 var(--ce-space-xs);
	font-size: var(--ce-text-xl);
}

.ce-kimo__text {
	margin: 0;
	color: var(--ce-color-muted);
	font-size: var(--ce-text-sm);
}

.ce-kimo__more {
	margin: var(--ce-space-sm) 0 0;
}

.ce-kimo__more a {
	font-family: var(--ce-font-heading);
	font-size: var(--ce-text-sm);
	font-weight: var(--ce-weight-medium);
	text-decoration: none;
}

.ce-kimo__more a:hover,
.ce-kimo__more a:focus {
	text-decoration: underline;
}

/* 404 --------------------------------------------------------------------- */

/*
 * Layout from the error page on centry-secure.io: oversized numeral, short
 * subtitle, one line, one button.
 */
.ce-404 {
	max-width: 40rem;
	margin: 0 auto;
	padding: var(--ce-space-lg) 0;
	text-align: center;
}

/*
 * Decorative, and marked aria-hidden in the template - a screen reader
 * announcing "four hundred and four" adds nothing to "Oops".
 */
.ce-404__code {
	margin: 0;
	color: var(--ce-color-brand);
	font-family: var(--ce-font-heading);
	font-size: clamp(5rem, 3rem + 12vw, 11rem);
	font-weight: var(--ce-weight-bold);
	letter-spacing: -0.04em;
	line-height: 1;
}

.ce-404__title {
	margin: 0 0 var(--ce-space-sm);
	font-size: var(--ce-text-2xl);
}

.ce-404__text {
	margin: 0 0 var(--ce-space-md);
	color: var(--ce-color-muted);
	font-size: var(--ce-text-lg);
}

.ce-404__actions {
	margin: 0;
}

/* Archive header ----------------------------------------------------------- */

/*
 * The introduction and the Kimo card, side by side above the loop. Kimo is a
 * fixed column so the introduction takes whatever is left - the other way round
 * the card stretches to half the page and stops reading as a card.
 */
.ce-archive-intro {
	display: flex;
	align-items: flex-start;
	gap: var(--ce-space-md);
	max-width: 924px;
	margin: 0 auto var(--ce-section-gap);
	padding-bottom: var(--ce-space-md);
	border-bottom: 1px solid var(--ce-color-border);
}

.ce-archive-intro > .ce-archive-header {
	flex: 1 1 auto;
	max-width: none;
	margin: 0;
	padding-bottom: 0;
	border-bottom: 0;
}

/*
 * Top edge level with the "Resources" heading. align-items: flex-start above puts
 * the boxes on the same line; the card's own top padding is what made it read as
 * lower, so it is dropped here rather than trimmed - the figure inside provides
 * enough of its own breathing room.
 */
.ce-archive-intro > .ce-kimo {
	flex: 0 0 300px;

	/*
	 * Half a step down, not level. Flush with the heading, the card's border read
	 * as slightly high against the cap height of the type beside it.
	 */
	margin: var(--ce-space-xs) 0 0;
	padding-top: 0;
}

@media (max-width: 768px) {
	.ce-archive-intro {
		flex-direction: column;
	}

	.ce-archive-intro > .ce-kimo {
		flex-basis: auto;
		align-self: stretch;
	}
}

.ce-archive-header {
	max-width: 924px;
	margin: 0 auto var(--ce-section-gap);
	padding-bottom: var(--ce-space-md);
	border-bottom: 1px solid var(--ce-color-border);
}

/*
 * A label for the list itself. The page's h1 is "Resources", which covers the
 * introduction and the Kimo card too, so without this the articles are the one
 * thing on the page with no heading of their own.
 */
.ce-loop-title {
	margin: 0 0 var(--ce-space-md);
	font-size: var(--ce-text-2xl);
}

.ce-archive-header__title {
	margin: 0 0 var(--ce-space-sm);
	font-size: var(--ce-text-3xl);
}

/*
 * The answer-first summary, per the AEO rule. Held to a readable measure
 * because it is the passage most likely to be lifted whole.
 */
.ce-archive-header__lead {
	max-width: 65ch;
	margin: 0;
	color: var(--ce-color-muted);
	font-size: var(--ce-text-lg);
}

/* Empty entry ------------------------------------------------------------- */

/*
 * Collapse GeneratePress' article wrapper on a page with no content of its own.
 * The placeholder sections render outside it, so the wrapper is empty but keeps
 * its padding and reads as a blank box between them.
 *
 * The <article> stays in the DOM - it carries the CreativeWork microdata - and
 * only its padded inner is removed, so nothing is lost but the gap.
 */
.ce-empty-entry .inside-article {
	display: none;
}

/* Post card --------------------------------------------------------------- */

/*
 * Single stacked column, matching the blog list on centry-secure.io: image,
 * category, title, date, excerpt. Cards separate with a rule rather than a
 * fill, for the same reason the footer does - adjacent dark shades are within
 * ~1.05:1 and read as one surface.
 */
/*
 * Two columns. auto-fit with a floor rather than a hard `repeat(2, 1fr)` so a
 * narrow viewport collapses to one column without a second breakpoint, and a
 * single leftover card fills the row instead of sitting half-width.
 */
.ce-cards {
	display: grid;
	gap: var(--ce-space-md);
	grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
	align-items: start;
}

/*
 * Side by side, cards need containment - a divider rule works down a single
 * column but says nothing about which text belongs to which image once there
 * are two of them per row.
 */
.ce-card {
	display: flex;
	flex-direction: column;
	height: 100%;
	overflow: hidden;
	border: 1px solid var(--ce-color-border);
	border-radius: var(--ce-radius);
	background: var(--ce-color-surface-raised);
	transition: border-color var(--ce-transition);
}

.ce-card:hover,
.ce-card:focus-within {
	border-color: var(--ce-color-brand);
}

.ce-card__media {
	display: block;
	line-height: 0;
}

.ce-card__body {
	display: flex;
	flex: 1 1 auto;
	flex-direction: column;
	padding: var(--ce-space-sm) var(--ce-space-sm) var(--ce-space-md);
}

/* Pushed to the foot so the link sits on one line across a row of cards. */
.ce-card__more {
	margin-top: auto;
	padding-top: var(--ce-space-sm);
}

/*
 * The aspect ratio is declared so the space is reserved before the image
 * arrives. Without it a lazy-loaded card image shifts everything below it on
 * load, which is exactly the layout shift Core Web Vitals measures.
 */
.ce-card__image {
	display: block;
	width: 100%;
	height: auto;
	aspect-ratio: 16 / 9;
	object-fit: cover;
}

/*
 * Badge rather than plain text. Solution and audience are the two axes an
 * article is filed on, so on a grid of cards the category is what tells a
 * reader which pile a card belongs to before they read the title.
 *
 * Bordered rather than filled: a solid brand-orange chip on every card would
 * out-shout the titles, which are the thing being scanned.
 */
.ce-card__category {
	display: inline-block;
	padding: 0.25em 0.7em;
	border: 1px solid var(--ce-color-brand);
	border-radius: 999px;
	color: var(--ce-color-brand);
	font-family: var(--ce-font-heading);
	font-size: 0.75rem;
	font-weight: var(--ce-weight-medium);
	letter-spacing: 0.06em;
	line-height: 1.5;
	text-decoration: none;
	text-transform: uppercase;
	transition:
		background-color var(--ce-transition),
		color var(--ce-transition);
}

.ce-card__category:hover,
.ce-card__category:focus {
	background-color: var(--ce-color-brand);
	color: var(--ce-color-on-brand);
}

/* Badges wrap as a row; the separator a text list needed is gone. */
.ce-card__meta {
	display: flex;
	flex-wrap: wrap;
	gap: var(--ce-space-xs);
}

.ce-card__title {
	margin: 0 0 var(--ce-space-xs);
	font-size: var(--ce-text-2xl);
}

.ce-card__title a {
	color: var(--ce-color-heading);
	text-decoration: none;
}

.ce-card__title a:hover,
.ce-card__title a:focus {
	color: var(--ce-color-brand);
}

.ce-card__date {
	margin: 0 0 var(--ce-space-sm);
	color: var(--ce-color-muted);
	font-size: var(--ce-text-sm);
}

/*
 * A middot between the date and the byline, drawn by CSS because it is punctuation
 * between two values rather than part of either - and it disappears with the byline on
 * a card that has none, which a hard-coded separator in the markup would not.
 */
.ce-card__author::before {
	content: ' b7';
	margin: 0 0.4em;
}

.ce-card__excerpt {
	color: var(--ce-color-text);
}

.ce-card__excerpt p {
	margin: 0;
}

.ce-card__more a {
	font-family: var(--ce-font-heading);
	font-weight: var(--ce-weight-medium);
	text-decoration: none;
}

.ce-card__more a:hover,
.ce-card__more a:focus {
	text-decoration: underline;
}

/* Hero (placeholder) ------------------------------------------------------ */

/*
 * Full-bleed section, with the same spacing above its content as below it.
 *
 * The header height is NOT in this padding. It is added back only in overlay mode
 * below, where the header is pulled up over the hero and the clearance is real - and
 * overlay only applies where the theme renders the hero, so a builder page was
 * reserving 135px for a bar sitting above it rather than on it, and the content sat
 * roughly 100px low as a result.
 *
 * --ce-hero-image is the slot for real artwork: set it to a url() and the
 * gradient becomes the scrim over it. Until then the gradient is the
 * background, which is why this reads as a placeholder rather than a broken
 * image.
 */
.ce-hero {
	position: relative;
	display: flex;
	overflow: hidden;
	align-items: center;
	min-height: 78vh;
	padding: var(--ce-space-xl) var(--ce-space-md);
	background-color: var(--ce-color-surface);
}

/* The clearance, where the header really is on top of the hero. */
.ce-header-overlay .ce-hero {
	padding-top: calc(var(--ce-header-height) + var(--ce-space-lg));
	padding-bottom: var(--ce-space-xl);
}

/*
 * The same hero when Elementor renders it. Every one of these is a variable rather
 * than the property, and the selector carries .e-con so it outranks Elementor's own
 * defaults - .e-con sets --min-height: initial, --overflow, --align-items and a 10px
 * padding, and its stylesheet loads after this file, so a single-class rule ties and
 * loses. Without this a hero built in the builder is 10px tall.
 */
.e-con.ce-hero {
	--min-height: 78vh;
	--overflow: hidden;
	--align-items: center;
	--justify-content: flex-start;
	--padding-top: var(--ce-space-xl);
	--padding-right: var(--ce-space-md);
	--padding-bottom: var(--ce-space-xl);
	--padding-left: var(--ce-space-md);

	position: relative;
	overflow: hidden;
}

.ce-header-overlay .e-con.ce-hero {
	--padding-top: calc(var(--ce-header-height) + var(--ce-space-lg));
}

/* The compact variant, for a service, contact or thank-you page. */
.e-con.ce-hero--compact {
	--min-height: 0;
	--padding-top: calc(var(--ce-header-height-compact) + var(--ce-space-lg));
	--padding-bottom: var(--ce-space-lg);
}

/*
 * Signal-ring artwork, sat centre-right behind the copy. Anchored to the right
 * edge and allowed to overflow, so the rings run off the side rather than being
 * squeezed into a neat circle - the crop is what makes it read as a backdrop
 * rather than an illustration.
 */
/*
 * The backdrop arrives inside an Elementor Shortcode widget, which adds two wrappers
 * of its own. Neither is positioned, so the absolute placement still resolves against
 * .ce-hero - but they are laid out as flex items, so they must not take up space.
 */
.ce-hero .elementor-widget-shortcode:has(.ce-hero__backdrop),
.ce-hero .elementor-widget-shortcode:has(.ce-hero__backdrop) .elementor-shortcode {
	position: static;
	width: 0;
	height: 0;
}

.ce-hero__backdrop {
	position: absolute;
	z-index: 0;
	top: 50%;
	right: 0;
	width: min(70%, 900px);
	transform: translate(18%, -50%);
	pointer-events: none;
}

.ce-hero__backdrop svg {
	display: block;
	width: 100%;
	height: auto;
}

/* Below the point where the copy needs the width, it becomes a faint wash. */
@media (max-width: 900px) {
	.ce-hero__backdrop {
		width: 120%;
		opacity: 0.35;
		transform: translate(20%, -50%);
	}
}

/*
 * SMIL animation cannot be stopped from CSS, so the expanding rings are hidden
 * outright for anyone who asked for less motion. The static pulse point and
 * glow remain, so the graphic still reads.
 */
@media (prefers-reduced-motion: reduce) {
	.ce-hero__ping {
		display: none;
	}
}

.ce-hero__inner {
	position: relative;
	z-index: 1;
	max-width: var(--ce-page-max);
	width: 100%;
	margin: 0 auto;
}

/*
 * The hero's inner, when Elementor renders it.
 *
 * `.ce-hero__inner` above centres with `margin: 0 auto`, which works in the theme's
 * own hero and is discarded in a builder one - .e-con applies margin-inline-start from
 * --margin-left, defaulting to 0px, and that wins on load order. So the same hero
 * lands its text at 190px rendered by the theme and at 32px rendered by the builder,
 * and any section rule can only match one of them.
 *
 * Both centre now. The measure and the gutter are the same tokens the sections use, so
 * the left edge is identical whichever renders it.
 */
.e-con.ce-hero__inner {
	--margin-right: auto;
	--margin-left: auto;
	--padding-right: 0px;
	--padding-left: 0px;

	max-width: var(--ce-page-max);
}

/*
 * The eyebrow is the product's own tagline, so it is a line to read rather than a label
 * on the heading - at 0.875rem, uppercase and letter-spaced, four words of positioning
 * read as small print above a wordmark. Set to the lead's size; uppercase, brand colour
 * and the heading face keep the two apart without the eyebrow reaching the heading.
 */
.ce-hero__eyebrow {
	margin: 0 0 var(--ce-space-sm);
	color: var(--ce-color-brand);
	font-family: var(--ce-font-heading);
	font-size: var(--ce-text-lg);
	font-weight: var(--ce-weight-medium);
	letter-spacing: 0.08em;
	text-transform: uppercase;
}

.ce-hero__title {
	max-width: 20ch;
	margin: 0 0 var(--ce-space-sm);
	font-size: var(--ce-text-3xl);
}

/*
 * When the heading is a wordmark, the ch-based measure is meaningless - there
 * is no text to measure. Sized to fit the column instead, with a ceiling so it
 * does not become a billboard on a wide screen.
 */
.ce-hero__title--mark {
	max-width: none;
}

/*
 * Same size and position whether the theme rendered the hero or Elementor did:
 * left aligned, block, filling the column to a 420px ceiling. The wordmark also
 * carries the heading's own bottom margin in the builder, because there it is a
 * Text Editor rather than the h1 itself.
 */
.ce-hero__title--mark .ce-hero__mark,
.ce-hero__mark {
	display: block;
	margin: 0;
}

.ce-hero__mark svg,
.ce-hero__mark img {
	display: block;
	width: min(100%, 420px);
	height: auto;

	/*
	 * Pulled left by the empty space inside the artwork, so the helmet's left edge
	 * lands on the same line as the eyebrow and the lead rather than 35px right of
	 * them. The wordmarks draw from x=17.59 in a 212.07 viewBox - 8.29% of their own
	 * width - measured, not estimated, and identical across the three product logos.
	 *
	 * A percentage translate resolves against the element's own width, so this holds
	 * at every size the logo renders at. A negative margin would resolve against the
	 * container instead and only be right at one width.
	 */
	transform: translateX(-8.29%);
}

.ce-hero__lead {
	max-width: 60ch;
	margin: 0 0 var(--ce-space-md);
	color: var(--ce-color-muted);
	font-size: var(--ce-text-lg);
}

.ce-hero__actions {
	display: flex;
	flex-wrap: wrap;
	gap: var(--ce-space-sm);
}

@media (max-width: 768px) {
	.ce-hero {
		min-height: 0;
		padding-top: calc(var(--ce-header-height-compact) + var(--ce-space-lg));
	}
}

/* Scroll to top ----------------------------------------------------------- */

/*
 * Geometry from centry-secure.io: a 3em square pinned 2em from the bottom
 * right, sliding up from -4em and fading in when shown.
 *
 * Not carried over: that site's white fill, which on a dark page is a bright
 * square in the corner of every screen. Raised surface with a border reads as
 * a control without competing with the content.
 */
.ce-to-top {
	position: fixed;
	z-index: 40;
	right: 2em;
	bottom: -4em;
	display: flex;
	align-items: center;
	justify-content: center;
	width: 3em;
	height: 3em;
	padding: 0;
	border: 1px solid var(--ce-color-border);
	border-radius: 50%;
	opacity: 0;
	background-color: var(--ce-color-surface-raised);
	color: var(--ce-color-text);
	cursor: pointer;
	transition:
		bottom var(--ce-transition),
		opacity var(--ce-transition),
		color var(--ce-transition),
		border-color var(--ce-transition);
}

/*
 * display:flex above beats the user-agent [hidden] { display: none }, so
 * without this the button is present and focusable before JavaScript reveals
 * it - invisible at opacity 0, but still a tab stop that does nothing.
 */
.ce-to-top[hidden] {
	display: none;
}

.ce-to-top svg {
	width: 20px;
	height: 20px;
}

.ce-to-top.is-visible {
	bottom: 2em;
	opacity: 1;
}

.ce-to-top:hover,
.ce-to-top:focus-visible {
	border-color: var(--ce-color-brand);
	background-color: var(--ce-color-surface-raised);
	color: var(--ce-color-brand);
}

/*
 * Below the header breakpoint the button sits where a thumb reaches for the
 * browser chrome, so it tucks in closer to the corner.
 */
@media (max-width: 768px) {
	.ce-to-top {
		right: 1em;
	}

	.ce-to-top.is-visible {
		bottom: 1em;
	}
}

/* Footer ------------------------------------------------------------------ */

/*
 * The footer used to separate itself with a darker fill. On a dark page that
 * does nothing - every neighbouring shade is within ~1.05:1 of the background
 * and reads as one flat surface. It separates with a rule instead.
 */
.ce-footer {
	margin-top: 50px;
	border-top: 1px solid var(--ce-color-border);
	background: var(--ce-color-surface);
	color: var(--ce-color-text);
}

/*
 * Column proportions from centry-secure.io: a brand column and three equal
 * link columns, 50px side padding. Fixed at four rather than auto-fitting -
 * auto-fit reflows to five or two depending on how many groups exist, and the
 * row only reads well at four.
 */
/*
 * Full width. The columns used to sit in a 1200px container centred in the
 * footer, which left the brand mark floating in the middle of a very wide dark
 * band while the header above it ran to 1340px. The band and its contents now
 * span the viewport, with the 50px gutter doing the work the container did.
 */
.ce-footer__inner {
	display: grid;
	gap: var(--ce-space-lg) var(--ce-space-md);
	grid-template-columns: 1.6fr repeat(3, 1fr);
	padding: var(--ce-space-lg) 50px;
}

/* ------------------------------------------------------------------------- */

/*
 * Footer newsletter signup, carried over from centry-secure.io's footer: an
 * envelope inside the field, the button beside it, consent underneath.
 */
.ce-newsletter {
	display: flex;
	flex-wrap: wrap;
	gap: var(--ce-space-md);
	align-items: start;
	justify-content: space-between;
	padding: var(--ce-space-md) 50px;
	border-bottom: 1px solid var(--ce-color-border);
}

.ce-newsletter__intro {
	flex: 1 1 20rem;
}

.ce-newsletter__title {
	margin: 0 0 0.25rem;
	color: var(--ce-color-heading);
	font-family: var(--ce-font-heading);
	font-size: var(--ce-text-lg);
	font-weight: var(--ce-weight-medium);
}

.ce-newsletter__lead {
	max-width: 46ch;
	margin: 0;
	color: var(--ce-color-muted);
	font-size: var(--ce-text-sm);
}

.ce-newsletter__form {
	flex: 1 1 26rem;
	max-width: 30rem;
}

.ce-newsletter__row {
	display: flex;
	flex-wrap: wrap;
	gap: var(--ce-space-xs);
	margin-bottom: var(--ce-space-xs);
}

/*
 * The icon sits inside the field rather than beside it, which is what the 43px
 * of left padding on Secure's version is for. Positioned against this wrapper,
 * so it does not move when the input grows.
 */
.ce-newsletter__field {
	position: relative;
	flex: 1 1 12rem;
	display: flex;
	align-items: center;
}

.ce-newsletter__field svg {
	position: absolute;
	left: 16px;
	color: var(--ce-color-muted);
	pointer-events: none;
}

.ce-newsletter__field input[type='email'] {
	padding-left: 43px;
}

.ce-newsletter__notice {
	margin: 0 0 var(--ce-space-xs);
	color: var(--ce-color-heading);
	font-size: var(--ce-text-sm);
}

.ce-newsletter__notice--error {
	color: var(--ce-color-danger);
}

@media (max-width: 768px) {
	.ce-newsletter {
		padding: var(--ce-space-md) var(--ce-space-sm);
	}

	.ce-newsletter__row .ce-button {
		flex: 1 1 100%;
	}
}

.ce-footer__brand .ce-logo svg {
	width: auto;
	height: 96px;
	max-width: 100%;
}

.ce-footer__summary {
	margin: var(--ce-space-sm) 0;
	max-width: 40ch;
	color: var(--ce-color-muted);
	font-size: var(--ce-text-sm);
	line-height: var(--ce-leading-normal);
}

.ce-footer__heading {
	margin: 0 0 var(--ce-space-xs);
	color: var(--ce-color-text);
	font-size: var(--ce-text-sm);
	font-weight: var(--ce-weight-bold);
	letter-spacing: 0.04em;
	text-transform: uppercase;
}

.ce-footer__column ul,
.ce-footer__social {
	margin: 0;
	padding: 0;
	list-style: none;
}

.ce-footer__social {
	display: flex;
	gap: var(--ce-space-xs);
	margin-top: var(--ce-space-sm);
}

/*
 * 44px hit area around a 20px glyph - the WCAG 2.5.8 target-size minimum. Icon
 * links are the usual place that gets missed, because the icon looks like the
 * whole control.
 */
.ce-footer__social-link {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 44px;
	height: 44px;
	border: 1px solid var(--ce-color-border);
	border-radius: 50%;
	color: var(--ce-color-text);
	transition:
		color var(--ce-transition),
		border-color var(--ce-transition);
}

.ce-footer__social-link svg {
	width: 20px;
	height: 20px;
	fill: currentColor;
}

.ce-footer__social-link:hover,
.ce-footer__social-link:focus-visible {
	border-color: var(--ce-color-brand);
	color: var(--ce-color-brand);
}

.ce-footer__column li + li {
	margin-top: 0.4rem;
}

.ce-footer a {
	color: var(--ce-color-text);
	font-size: var(--ce-text-sm);
	text-decoration: none;
}

.ce-footer a:hover,
.ce-footer a:focus {
	color: var(--ce-color-brand);
	text-decoration: underline;
}

.ce-footer__legal {
	border-top: 1px solid var(--ce-color-border);
}

.ce-footer__legal p {
	max-width: var(--ce-container-max);
	margin: 0 auto;
	padding: var(--ce-space-sm) 50px;
	color: var(--ce-color-muted);
	font-size: var(--ce-text-sm);
}

@media (max-width: 900px) {
	.ce-footer__inner {
		grid-template-columns: repeat(2, 1fr);
	}

	.ce-footer__brand {
		grid-column: 1 / -1;
	}
}

@media (max-width: 600px) {
	.ce-footer__inner {
		grid-template-columns: 1fr;
		padding: var(--ce-space-lg) var(--ce-space-sm);
	}

	.ce-footer__legal p {
		padding: var(--ce-space-sm);
	}
}

/*
 * Inline icon. Sized in em so it tracks whatever text it sits beside, and
 * coloured by currentColor so it inherits link and hover states for free.
 * Only applies to single-colour icons - the logos carry their own fills.
 */
.ce-icon {
	display: inline-block;
	width: 1em;
	height: 1em;
	vertical-align: -0.125em;
	fill: currentColor;
}

/* ------------------------------------------------------------------------- */
/* 4. Utilities                                                              */
/* ------------------------------------------------------------------------- */

.ce-visually-hidden {
	position: absolute;
	width: 1px;
	height: 1px;
	padding: 0;
	margin: -1px;
	overflow: hidden;
	clip: rect(0, 0, 0, 0);
	white-space: nowrap;
	border: 0;
}

/* Testimonials and case studies ------------------------------------------- */

/*
 * Both are the row-of-cards idiom the features, statistics and solutions rows use, so a
 * page that gains a testimonial section does not gain a new shape. Wider cards than a
 * statistic: a quote is prose and 260px would set it four words to a line.
 */
.ce-testimonials,
.ce-cases {
	display: flex;
	flex-wrap: wrap;
	gap: var(--ce-space-md);
	justify-content: center;
	margin: 0;
	padding: 0;
	list-style: none;
}

.ce-testimonial,
.ce-case {
	display: flex;
	flex: 1 1 320px;
	flex-direction: column;
	align-self: stretch;
	max-width: 400px;
	padding: var(--ce-space-md);
	border: 1px solid var(--ce-color-border);
	border-radius: var(--ce-radius);
	background: var(--ce-color-surface-raised);
	transition: border-color var(--ce-transition);
}

.ce-testimonial:hover,
.ce-case:hover,
.ce-testimonial:focus-within,
.ce-case:focus-within {
	border-color: var(--ce-color-brand);
}

/*
 * The whole card is the link. Two links in one card - a title and a "read more" - are two tab
 * stops and one destination, and the second says nothing the first did not.
 */
.ce-testimonial__card {
	display: flex;
	flex: 1 1 auto;
	flex-direction: column;
	color: inherit;
	text-decoration: none;
}

/*
 * The badge names the product this is about, so a strip of cards reads as coverage across the
 * platform rather than as eight anonymous quotes. Small, and above the content, because it is
 * a label on what follows rather than a claim of its own.
 */
.ce-badge--card {
	align-self: flex-start;
	margin: 0 0 var(--ce-space-sm);
	padding: 3px 10px;
	font-size: 0.8rem;
}

/* Says a video is there without spending four third-party requests to prove it. */
.ce-card__flag {
	margin-top: auto;
	padding-top: var(--ce-space-xs);
	color: var(--ce-color-muted);
	font-family: var(--ce-font-heading);
	font-size: var(--ce-text-sm);
}

.ce-testimonial__card:hover .ce-testimonial__name,
.ce-testimonial__card:focus-visible .ce-testimonial__name {
	color: var(--ce-color-brand);
	text-decoration: underline;
}

/* Sidebar index entries - the company under the name, quieter than it. */
.ce-related__name {
	display: block;
}

.ce-related__meta {
	display: block;
	color: var(--ce-color-muted);
	font-size: 0.8rem;
	font-weight: var(--ce-weight-regular);
}

/*
 * A testimonial's own page. The quote is the post content and GeneratePress renders it at
 * reading size; this is what sits under it.
 */
.ce-testimonial-detail__who {
	color: var(--ce-color-muted);
	font-family: var(--ce-font-heading);
}

.ce-testimonial-detail__links {
	display: flex;
	flex-wrap: wrap;
	gap: var(--ce-space-sm);
}

.ce-testimonial-detail__links a {
	color: var(--ce-color-brand);
	text-decoration: underline;
	text-underline-offset: 0.15em;
}

/* Round, small, and never the reason a card is tall. */
.ce-testimonial__avatar {
	width: 64px;
	height: 64px;
	margin: 0 0 var(--ce-space-sm);
	border-radius: 50%;
	object-fit: cover;
}

.ce-testimonial__quote {
	margin: 0 0 var(--ce-space-sm);
	border: 0;
	padding: 0;
	color: var(--ce-color-text);
	font-size: var(--ce-text-lg);
	font-style: italic;
}

.ce-testimonial__quote p:last-child {
	margin-bottom: 0;
}

.ce-testimonial__who {
	display: flex;
	flex-direction: column;
	margin: 0;
	gap: 2px;
}

.ce-testimonial__name {
	color: var(--ce-color-heading);
	font-family: var(--ce-font-heading);
	font-weight: var(--ce-weight-medium);
}

.ce-testimonial__company {
	color: var(--ce-color-muted);
	font-size: var(--ce-text-sm);
}

.ce-testimonial__links {
	display: flex;
	flex-wrap: wrap;
	margin-top: var(--ce-space-xs);
	gap: var(--ce-space-sm);
}

.ce-testimonial__link {
	color: var(--ce-color-brand);
	font-size: var(--ce-text-sm);
}

/*
 * The embed keeps its aspect ratio without the padding-top trick: every oEmbed provider
 * returns an iframe, and aspect-ratio on the wrapper with the iframe filling it is fewer
 * moving parts than a percentage padding hack.
 */
.ce-video {
	margin: var(--ce-space-sm) 0 var(--ce-space-xs);
	overflow: hidden;
	border-radius: var(--ce-radius);
	aspect-ratio: 16 / 9;
	background: var(--ce-color-surface-sunken);
}

.ce-video iframe,
.ce-video video {
	display: block;
	width: 100%;
	height: 100%;
	border: 0;
}

.ce-video__source {
	margin: 0;
	font-size: var(--ce-text-sm);
}

.ce-case__image {
	width: 100%;
	height: auto;
	margin: 0 0 var(--ce-space-sm);
	border-radius: var(--ce-radius);
}

.ce-case__title {
	margin: 0 0 var(--ce-space-xs);
	color: var(--ce-color-brand);
	font-size: var(--ce-text-lg);
}

.ce-case__meta {
	margin: 0 0 var(--ce-space-xs);
	color: var(--ce-color-muted);
	font-size: var(--ce-text-sm);
	text-transform: uppercase;
	letter-spacing: 0.06em;
}

.ce-case__excerpt {
	margin: 0 0 var(--ce-space-sm);
	color: var(--ce-color-text);
}

/* Pushed to the bottom, so the link sits on one line across a row of uneven cards. */
.ce-case .ce-card__more {
	margin-top: auto;
}

/* A case study's own page: the four-part structure the portfolio schema uses. */
.ce-case-detail__meta {
	display: flex;
	flex-wrap: wrap;
	gap: var(--ce-space-md);
	margin: 0 0 var(--ce-section-space);
	padding: var(--ce-space-sm);
	border-left: 2px solid var(--ce-color-brand);
	list-style: none;
}

.ce-case-detail__meta dt {
	color: var(--ce-color-muted);
	font-size: var(--ce-text-sm);
	text-transform: uppercase;
	letter-spacing: 0.06em;
}

.ce-case-detail__meta dd {
	margin: 0;
	color: var(--ce-color-heading);
}

/*
 * A card per section, and the panel the testimonial page uses for the same reason: the sidebar
 * already reads as cards, and a main column of bare headings next to it reads as the part that
 * did not get designed.
 */
.ce-case-detail__section,
.ce-panel {
	margin-top: var(--ce-space-md);
	padding: var(--ce-space-md);
	border: 1px solid var(--ce-color-border);
	border-radius: var(--ce-radius);
	background: var(--ce-color-surface-raised);
}

.ce-case-detail__section h2 {
	margin-top: 0;
}

.ce-case-detail__section > p:last-child,
.ce-panel > p:last-child {
	margin-bottom: 0;
}

/* Logo cloud --------------------------------------------------------------- */

/*
 * A row of customer marks, centred and wrapping. Every logo arrives at a different size and
 * on a different background, so the height is fixed and the width is left alone - scaling
 * both distorts them, and a set of marks all forced to one width reads as clip art.
 *
 * Muted until hover: the marks are evidence, not the thing being sold, and at full contrast
 * a row of other companies' branding outshouts the page it sits on.
 */
.ce-logos {
	display: flex;
	flex-wrap: wrap;
	gap: var(--ce-space-lg);
	align-items: center;
	justify-content: center;
	margin: 0;
	padding: 0;
	list-style: none;
}

.ce-logos__item {
	display: flex;
	align-items: center;
}

/*
 * Full colour, at full opacity. The usual logo-strip treatment desaturates the marks and
 * restores them on hover, which reads as tasteful and is a customer's brand shown wrong -
 * these are the organisations on the platform, and there is no reason to make them look
 * provisional.
 */
.ce-logos__mark {
	width: auto;
	height: 40px;
	max-width: 180px;
	object-fit: contain;
}

/*
 * The carousel. Two identical lists in one track, travelling exactly half the track's width,
 * so the second set lands where the first began and the loop has no seam. Duration comes from
 * the shortcode as --ce-logos-duration, scaled to the number of marks, so adding a customer
 * makes the strip longer rather than faster.
 */
/*
 * Full width of the container it sits in, gutter included. Every other section stops at the
 * page measure so its text lines up with the hero's, and a strip of marks is the one thing
 * that should not: a logo travelling into a 2rem margin and stopping there looks like a bug,
 * where one fading out at the container's own edge looks like a list that continues.
 */
.ce-logos-carousel {
	margin-inline: calc(var(--ce-page-gutter) * -1);
	overflow: hidden;
}

/*
 * Static until something says otherwise. Whether the marks overflow is a measurement, and
 * `is-looping` is main.js answering it - so six customers on a wide screen sit still and
 * centred, and thirty travel. The duplicate set is hidden until it is needed, which also
 * means a page with JavaScript unavailable shows one honest row rather than two.
 */
.ce-logos__track {
	display: flex;
	justify-content: center;
	gap: var(--ce-space-lg);
}

.ce-logos__track > [aria-hidden='true'] {
	display: none;
}

.ce-logos-carousel.is-looping {
	/* Fade at both ends, so marks enter and leave rather than being cut off mid-wordmark. */
	mask-image: linear-gradient(90deg, transparent, #000 4rem, #000 calc(100% - 4rem), transparent);
}

.ce-logos-carousel.is-looping .ce-logos__track {
	width: max-content;
	justify-content: flex-start;
	animation: ce-logos-scroll var(--ce-logos-duration, 40s) linear infinite;
}

.ce-logos-carousel.is-looping .ce-logos__track > [aria-hidden='true'] {
	display: flex;
}

.ce-logos--carousel {
	flex-wrap: nowrap;
	justify-content: flex-start;
}

@keyframes ce-logos-scroll {
	to {
		transform: translateX(calc(-50% - var(--ce-space-lg) / 2));
	}
}

/*
 * Pause on hover, and on focus - a keyboard reader tabbing to a linked mark should not have it
 * move out from under them, which is the same requirement stated two ways.
 */
.ce-logos-carousel:hover .ce-logos__track,
.ce-logos-carousel:focus-within .ce-logos__track {
	animation-play-state: paused;
}

/* Taller than the static grid: this is the section's subject rather than a footnote to it. */
.ce-logos--carousel .ce-logos__mark {
	height: auto;
	max-height: 80px;
	max-width: 220px;
}

@media (prefers-reduced-motion: reduce) {
	/*
	 * No animation, and the strip scrolls by hand instead - hiding the overflow without the
	 * motion would leave the last customers unreachable. The duplicate set goes with it:
	 * a second copy of the list exists to make a loop seamless, and there is no loop.
	 */
	.ce-logos-carousel.is-looping .ce-logos__track {
		animation: none;
	}

	.ce-logos-carousel.is-looping {
		overflow-x: auto;
		mask-image: none;
	}

	.ce-logos-carousel.is-looping .ce-logos__track > [aria-hidden='true'] {
		display: none;
	}
}

/* Comparison table --------------------------------------------------------- */

/*
 * Three columns: the capability, how the traditional stack delivers it, how we do. The
 * design does the arguing the copy does not - our column is the only one with a fill, so
 * the eye reads down it rather than across sixteen rows.
 *
 * The wrapper scrolls, not the page. Sixteen rows of three columns fit a phone only
 * sideways, and a table that overflows its section takes the whole document with it.
 */
.ce-compare {
	overflow-x: auto;
	max-width: 100%;
	margin: 0 0 var(--ce-space-md);
	border: 1px solid var(--ce-color-border);
	border-radius: var(--ce-radius);
	background: var(--ce-color-surface-raised);
}

.ce-compare__table {
	width: 100%;
	border-collapse: collapse;
	font-size: var(--ce-text-sm);
	text-align: left;
}

.ce-compare__table th,
.ce-compare__table td {
	padding: 14px var(--ce-space-sm);
	border-bottom: 1px solid var(--ce-color-border);
	vertical-align: middle;
	white-space: nowrap;
}

.ce-compare__table thead th {
	position: sticky;
	top: 0;
	background: var(--ce-color-surface-sunken);
	color: var(--ce-color-heading);
	font-family: var(--ce-font-heading);
	font-size: var(--ce-text-sm);
	font-weight: var(--ce-weight-semibold);
	letter-spacing: 0.04em;
	text-transform: uppercase;
}

/* The capability is a row header, so it carries the weight of one. */
.ce-compare__table tbody th {
	color: var(--ce-color-heading);
	font-weight: var(--ce-weight-medium);
	white-space: normal;
}

.ce-compare__table tbody tr:last-child th,
.ce-compare__table tbody tr:last-child td {
	border-bottom: 0;
}

/* What the stack gives you: muted, because it is the thing being left behind. */
.ce-compare__alt {
	color: var(--ce-color-muted);
}

/*
 * Ours: filled and in brand orange. The fill is on the column rather than the row so it
 * reads as one continuous claim, and the left border closes it off from the muted column.
 */
.ce-compare__ours,
.ce-compare__table thead th:last-child {
	border-left: 1px solid var(--ce-color-border);
	background: color-mix(in srgb, var(--ce-color-brand) 8%, transparent);
	color: var(--ce-color-brand);
	font-weight: var(--ce-weight-medium);
}

.ce-compare__table thead th:last-child {
	color: var(--ce-color-heading);
}

/* The sentence after the table, which is the argument the rows only imply. */
.ce-compare__trust {
	max-width: 80ch;
	margin: 0 auto;
	color: var(--ce-color-text);
	text-align: center;
}

@media (max-width: 600px) {
	.ce-compare__table th,
	.ce-compare__table td {
		padding: 12px var(--ce-space-xs);
	}
}

/* Comparison tabs ---------------------------------------------------------- */

/*
 * Four product tables in the space of one. Radio inputs and `:has()`, the mechanism the
 * pricing switch already uses - no JavaScript, so the tabs work before the script loads and
 * if it never does. A radio group is also what this is: one of four, exactly one selected,
 * announced correctly by a screen reader with no ARIA to get wrong.
 */
.ce-compare-tabs {
	display: flex;
	flex-direction: column;
	gap: var(--ce-space-sm);
}

.ce-compare__input {
	position: absolute;
	width: 1px;
	height: 1px;
	opacity: 0;
}

.ce-compare__tab {
	order: -1;
	padding: 12px 24px;
	border: 1px solid var(--ce-color-border);
	border-radius: var(--ce-radius);
	color: var(--ce-color-muted);
	font-family: var(--ce-font-heading);
	font-size: var(--ce-text-sm);
	font-weight: var(--ce-weight-medium);
	cursor: pointer;
	transition:
		background-color var(--ce-transition),
		border-color var(--ce-transition),
		color var(--ce-transition);
}

/*
 * The labels sit in a row above the panels. `order: -1` puts every label first regardless of
 * where its input is in the source, which is what lets the input stay next to its own label
 * for the `+` selector below.
 */
.ce-compare-tabs {
	flex-flow: row wrap;
	align-items: flex-start;
	justify-content: center;
}

.ce-compare__input:checked + .ce-compare__tab {
	border-color: var(--ce-color-brand);
	background: var(--ce-color-brand);
	color: var(--ce-color-surface-sunken);
}

.ce-compare__input:focus-visible + .ce-compare__tab {
	outline: 2px solid var(--ce-color-brand);
	outline-offset: 2px;
}

/* One panel at a time, and full width beneath the row of tabs. */
.ce-compare__panel {
	display: none;
	flex: 0 0 100%;
	margin-top: var(--ce-space-sm);
}

/*
 * Structural, not a list of ids. The previous rule enumerated the five solution ids, so a tab
 * set it had never heard of - the two plugin tables - could never show a panel at all. The
 * panel now follows its own label, so this works for any tab, present or future.
 */
.ce-compare__input:checked + .ce-compare__tab + .ce-compare__panel {
	display: block;
}

/*
 * Without :has()... nothing here needs :has() any more, but an older browser still gets a
 * sensible page: every panel shows, stacked, each under its own headline. Longer, still
 * correct.
 */
@supports not selector(:checked + * + *) {
	.ce-compare__panel {
		display: block;
	}

	.ce-compare__tab {
		display: none;
	}
}

.ce-compare__headline {
	margin: 0 0 var(--ce-space-sm);
	color: var(--ce-color-heading);
	font-size: var(--ce-text-xl);
	text-align: center;
}

/* An article rendered by Theme Builder --------------------------------------- */

/*
 * The layout GeneratePress produces today, measured on a migrated article at 1414px: an 880px
 * content column with 780px of prose inside it, a 320px sidebar beside it, both inside the
 * 1200px page measure, title at the site's own h1 size. Reproduced rather than redesigned, so
 * switching an existing post to this template changes nothing a reader would notice.
 */
.e-con.e-flex.ce-article {
	--flex-direction: row;
	--flex-wrap: wrap;
	--gap: 0px;
	--margin-right: auto;
	--margin-left: auto;
	--padding-left: var(--ce-page-gutter);
	--padding-right: var(--ce-page-gutter);
	--align-items: flex-start;

	max-width: calc(var(--ce-container-max) + var(--ce-page-gutter) * 2);
}

/* 880 of the 1200, with 50px either side leaving the 780 the prose has now. */
.e-con.ce-article__main {
	--width: 880px;
	--padding-left: 50px;
	--padding-right: 50px;

	flex: 1 1 560px;
	max-width: 880px;
}

.e-con.ce-article__aside {
	--width: 320px;

	flex: 0 1 320px;
	max-width: 320px;
}

.ce-article__meta {
	color: var(--ce-color-muted);
	font-size: var(--ce-text-sm);
	text-transform: uppercase;
	letter-spacing: 0.06em;
}

/*
 * The lead image. Full width of the article column, and it keeps its own aspect ratio - the
 * source artwork is 16:9 and cropping it to a fixed height would cut the text that is part of
 * most of these images.
 */
.ce-article__image {
	margin: 0 0 var(--ce-space-md);
}

.ce-article__image img {
	display: block;
	width: 100%;
	height: auto;
	border-radius: var(--ce-radius);
}

/*
 * No font-size here. The site's own h1 rule is what makes the title 42px today, and repeating
 * that number is how the two drift apart.
 */
.ce-article__title {
	margin: var(--ce-space-xs) 0 var(--ce-space-sm);
	color: var(--ce-color-heading);
}

.ce-article__media img {
	width: 100%;
	height: auto;
	margin-bottom: var(--ce-space-md);
	border-radius: var(--ce-radius);
}

/*
 * Below the width where two columns fit, the sidebar goes under the article rather than
 * squeezing 320px out of a 400px screen - which is what GeneratePress does today.
 */
@media (max-width: 900px) {
	.e-con.ce-article__main,
	.e-con.ce-article__aside {
		--width: 100%;

		flex: 1 1 100%;
		max-width: 100%;
	}

	.e-con.ce-article__main {
		--padding-left: var(--ce-space-sm);
		--padding-right: var(--ce-space-sm);
	}
}

/* What a plugin needs ------------------------------------------------------- */

/*
 * A version requirement is what someone checks before installing, so it gets its own block rather
 * than a card in a grid of benefits. Bordered on the left like the old positioning block, because
 * it is a note rather than a claim.
 */
.ce-requires {
	max-width: 70ch;
	margin: 0 auto;
	padding: var(--ce-space-sm) var(--ce-space-md);
	border-left: 2px solid var(--ce-color-brand);
	background: var(--ce-color-surface-raised);
	text-align: left;
}

.ce-requires__title {
	margin: 0 0 var(--ce-space-xs);
	color: var(--ce-color-heading);
	font-size: var(--ce-text-sm);
	text-transform: uppercase;
	letter-spacing: 0.06em;
}

.ce-requires__text {
	margin: 0;
	color: var(--ce-color-text);
}

/* Kimo: badges, capabilities, prose ------------------------------------------ */

/*
 * Six short claims under the hero actions. Pills rather than a list: they are read at a glance and
 * in any order, which is what distinguishes them from the feature cards further down.
 */
.ce-badges {
	display: flex;
	flex-wrap: wrap;
	gap: var(--ce-space-xs);
	margin: var(--ce-space-md) 0 0;
	padding: 0;
	list-style: none;
}

.ce-badge {
	padding: 6px 14px;
	border: 1px solid var(--ce-color-border);
	border-radius: 999px;
	background: var(--ce-color-surface-raised);
	color: var(--ce-color-muted);
	font-family: var(--ce-font-heading);
	font-size: var(--ce-text-sm);
	white-space: nowrap;
}

/*
 * Four categories of work, five examples each. A list, not twenty cards: cards would make the page
 * look like it has twenty features rather than four kinds of help.
 */
.ce-capabilities {
	display: grid;
	gap: var(--ce-space-md);
	grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
	text-align: left;
}

.ce-capability {
	padding: var(--ce-space-sm);
	border-top: 2px solid var(--ce-color-brand);
	background: var(--ce-color-surface-raised);
}

.ce-capability__title {
	margin: 0 0 var(--ce-space-xs);
	color: var(--ce-color-heading);
	font-size: var(--ce-text-lg);
}

.ce-capability__list {
	margin: 0;
	padding: 0;
	color: var(--ce-color-text);
	font-size: var(--ce-text-sm);
	list-style: none;
}

.ce-capability__list li {
	padding: 4px 0;
	border-bottom: 1px solid var(--ce-color-border);
}

.ce-capability__list li:last-child {
	border-bottom: 0;
}

/* A titled paragraph, centred on the measure prose wants rather than the section's. */
.ce-prose__text {
	max-width: 75ch;
	margin: 0 auto;
	color: var(--ce-color-text);
	font-size: var(--ce-text-lg);
	text-align: center;
}

/*
 * Prose beside its artwork. One column on a phone with the prose first: the paragraph is the
 * point and the illustration supports it, so a reader on a narrow screen should not have to
 * scroll past a 300px mascot to reach the sentence.
 */
.ce-prose--split {
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	gap: var(--ce-space-lg);
	align-items: center;
}

@media (min-width: 782px) {
	.ce-prose--split {
		grid-template-columns: minmax(0, 1fr) minmax(0, 20rem);
		gap: var(--ce-space-xl);
	}

	/* In a column the paragraph sets its own measure, and centred text beside artwork reads as a caption. */
	.ce-prose--split .ce-prose__text {
		max-width: none;
		margin: 0;
		text-align: left;
	}
}

.ce-prose__figure {
	display: block;
	margin: 0 auto;
	max-width: 20rem;
	width: 100%;
}

.ce-prose__figure svg {
	display: block;
	width: 100%;
	height: auto;
}

/* ---------------------------------------------------------------------------
 * Legal modals
 *
 * A native <dialog>, so focus trapping, Escape and the inert background are the
 * browser's job rather than ours. Only the presentation is here.
 * ------------------------------------------------------------------------ */

/*
 * showModal() puts the dialog in the top layer, where z-index does not apply and no
 * card can cover it. The z-index is for the state that is not that one: a dialog left
 * open non-modally sits in normal flow, and the featured pricing card is positioned.
 * Cheap insurance against the close button ending up underneath something.
 */
.ce-modal {
	z-index: 100;
	width: min(72rem, calc(100vw - 2 * var(--ce-space-md)));
	max-width: none;
	max-height: min(80vh, 56rem);
	padding: 0;
	border: 1px solid var(--ce-color-border);
	border-radius: var(--ce-radius);
	background: var(--ce-color-surface-raised);
	color: var(--ce-color-text);
}

.ce-modal::backdrop {
	background: rgb(0 0 0 / 70%);
}

/*
 * Grid rather than overflow on the dialog: the head and foot stay put and only the
 * document scrolls, so the close button is reachable at any scroll position on a
 * document as long as the Terms.
 *
 * Scoped to [open], and it has to be. `display` on a bare `.ce-modal--lg` overrides the
 * browser's `dialog:not([open]) { display: none }`, which renders every dialog into the
 * page below the footer - in normal flow, under a positioned card, with a close button
 * that closes a dialog nothing was showing modally.
 */
.ce-modal--lg[open] {
	display: grid;
	grid-template-rows: auto minmax(0, 1fr) auto;
}

.ce-modal__head,
.ce-modal__foot {
	display: flex;
	align-items: center;
	gap: var(--ce-space-sm, 1rem);
	padding: 1.25rem var(--ce-space-md);
	background: var(--ce-color-surface);
}

.ce-modal__head {
	justify-content: space-between;
	border-bottom: 1px solid var(--ce-color-border);
}

.ce-modal__foot {
	border-top: 1px solid var(--ce-color-border);
}

.ce-modal__title {
	margin: 0;
	font-size: var(--ce-text-xl);
}

.ce-modal__close {
	display: flex;
	align-items: center;
	justify-content: center;
	/* 44px, so the target passes the pointer-size rule rather than only looking small. */
	width: 2.75rem;
	height: 2.75rem;
	padding: 0;
	border: 1px solid var(--ce-color-border);
	border-radius: var(--ce-radius);
	background: var(--ce-color-surface-control);
	color: var(--ce-color-text);
	font-size: 1.5rem;
	line-height: 1;
	cursor: pointer;
}

.ce-modal__close:hover,
.ce-modal__close:focus-visible {
	border-color: var(--ce-color-accent, var(--ce-color-text));
}

.ce-modal__body {
	max-width: none;
	padding: var(--ce-space-md);
	overflow-y: auto;
	overscroll-behavior: contain;
}

.ce-modal__body > * {
	max-width: 78ch;
}

.ce-modal__body h3,
.ce-modal__body h4 {
	margin: var(--ce-space-md) 0 0.5rem;
	font-size: var(--ce-text-lg, 1.125rem);
}

.ce-modal__body > :first-child {
	margin-top: 0;
}

.ce-modal__body p,
.ce-modal__body li {
	color: var(--ce-color-muted);
	line-height: 1.7;
}

.ce-modal__body table {
	width: 100%;
	max-width: 78ch;
	margin: 1rem 0;
	border-collapse: collapse;
}

.ce-modal__body th,
.ce-modal__body td {
	padding: 0.5rem 0.75rem;
	border: 1px solid var(--ce-color-border);
	color: var(--ce-color-muted);
	text-align: left;
	vertical-align: top;
}

.ce-modal__body th {
	color: var(--ce-color-text);
}

@media (max-width: 782px) {
	.ce-modal {
		width: 100vw;
		max-width: 100vw;
		max-height: 100dvh;
		height: 100dvh;
		border: 0;
		border-radius: 0;
	}
}

/*
 * The policy line under the pricing. Muted and small - it is a pointer to the terms,
 * not a selling point - but --ce-color-muted keeps it at 10.14:1 rather than grey mush.
 */
.ce-legal-note {
	margin: var(--ce-space-md) 0 0;
	color: var(--ce-color-muted);
	font-size: var(--ce-text-sm);
}

/*
 * A showcase with no screenshots renders nothing, but the container the builder put it in
 * still renders - and now carries a section's worth of margin, so an empty one left an 80px
 * hole. The section removes itself when it holds no showcase, rather than the renderer
 * trying to delete a parent it does not own.
 */
.ce-showcase-section:not(:has(.ce-showcase)) {
	display: none;
}
