/*
Theme Name: North Blue Agency
Theme URI: https://northblueagency.com
Author: North Blue Agency
Description: Custom theme for North Blue Agency — a semantic-CSS port of the original Next.js site, with a Gutenberg block library covering every page section.
Version: 1.0.0
Requires at least: 6.5
Tested up to: 7.1
Requires PHP: 7.4
License: Proprietary
Text Domain: north-blue
*/

/* ==========================================================================
   1. Design tokens
   --------------------------------------------------------------------------
   Every colour, size and shadow the original Tailwind build produced, lifted
   into named custom properties. Nothing below this block should ever hardcode
   a brand colour — change it here and it changes everywhere.
   ========================================================================== */

:root {
	/* Brand */
	--nb-pink: #ff4081;
	--nb-blue: #00b2ff;
	--nb-purple: #a855f7; /* purple-500, the midpoint of the tri-stop gradient */
	--nb-indigo: #6f8cff; /* used by the "Strategy" process chip */

	--nb-gradient: linear-gradient(to right, var(--nb-pink), var(--nb-blue));
	--nb-gradient-reverse: linear-gradient(to right, var(--nb-blue), var(--nb-pink));
	--nb-gradient-br: linear-gradient(to bottom right, var(--nb-pink), var(--nb-blue));
	--nb-gradient-tri: linear-gradient(to right, var(--nb-pink), var(--nb-purple), var(--nb-blue));

	/* Neutrals — the Tailwind gray ramp the site was built on */
	--nb-white: #ffffff;
	--nb-gray-50: #f9fafb;
	--nb-gray-100: #f3f4f6;
	--nb-gray-200: #e5e7eb;
	--nb-gray-300: #d1d5db;
	--nb-gray-400: #9ca3af;
	--nb-gray-500: #6b7280;
	--nb-gray-600: #4b5563;
	--nb-gray-700: #374151;
	--nb-gray-800: #1f2937;
	--nb-gray-900: #111827;
	--nb-gray-950: #030712;
	--nb-slate-900: #0f172a;
	--nb-slate-950: #020617;
	--nb-black: #000000;

	/*
	 * The per-page accent pair.
	 *
	 * Every SEO specialisation on the original site has its own two-colour
	 * ramp — AEO is blue into pink, GEO purple into orange — and that ramp is
	 * not just the hero: it colours the tick bullets, the numbered step badges,
	 * the metrics heading and the ecosystem badges on the same page. Holding it
	 * as two custom properties means one wrapper on the template sets it and
	 * every block downstream inherits, instead of six blocks each growing their
	 * own colour attribute. Defaults are the brand pair, so a page that sets
	 * nothing looks exactly as it did.
	 */
	--nb-accent-from: var(--nb-pink);
	--nb-accent-to: var(--nb-blue);
	--nb-accent-gradient: linear-gradient(to right, var(--nb-accent-from), var(--nb-accent-to));

	/* Semantic roles */
	--nb-text: var(--nb-gray-900);
	--nb-text-muted: var(--nb-gray-600);
	--nb-text-subtle: var(--nb-gray-500);
	--nb-surface: var(--nb-white);
	--nb-surface-alt: var(--nb-gray-50);
	--nb-border: var(--nb-gray-200);

	/* Type */
	--nb-font: 'Inter Variable', Inter, ui-sans-serif, system-ui, -apple-system,
		'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;

	--nb-text-sm: 0.875rem;
	--nb-text-base: 1rem;
	--nb-text-lg: 1.125rem;
	--nb-text-xl: 1.25rem;
	--nb-text-2xl: 1.5rem;
	--nb-text-3xl: 1.875rem;
	--nb-text-4xl: 2.25rem;
	--nb-text-5xl: 3rem;
	--nb-text-7xl: 4.5rem;

	/* Radii */
	--nb-radius-sm: 0.375rem;
	--nb-radius: 0.5rem;
	--nb-radius-lg: 0.75rem;
	--nb-radius-xl: 1rem;
	--nb-radius-2xl: 1.5rem;
	--nb-radius-full: 9999px;

	/* Shadows — Tailwind's scale, verbatim */
	--nb-shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
	--nb-shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.1);
	--nb-shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -4px rgba(0, 0, 0, 0.1);
	--nb-shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1);
	--nb-shadow-2xl: 0 25px 50px -12px rgba(0, 0, 0, 0.25);

	/* Layout */
	--nb-header-height: 80px;
	--nb-gutter: 1rem;
	--nb-max-width: 1640px;

	/* Motion */
	--nb-ease: cubic-bezier(0.25, 0.46, 0.45, 0.94);
	--nb-reveal-duration: 1000ms;
}

/* ==========================================================================
   2. Base
   ========================================================================== */

*,
*::before,
*::after {
	box-sizing: border-box;
}

html {
	-webkit-text-size-adjust: 100%;
	scroll-behavior: smooth;
}

html,
body {
	/*
	 * The original site clamped horizontal overflow globally — several hero
	 * decorations are deliberately positioned outside the viewport.
	 *
	 * `overflow-x: hidden` on html or body is the single most common way to
	 * break `position: sticky` on a page, and it broke the diagram sequences
	 * here: it makes the element a scroll container, sticky then anchors to a
	 * box that is not the one actually scrolling, and the panel travels with
	 * the page instead of pinning. `clip` clamps the same overflow without
	 * creating that container. The `hidden` line stays as the fallback for
	 * browsers without `clip`, which get the stacked cards instead.
	 */
	overflow-x: hidden;
	max-width: 100vw;
}

@supports (overflow: clip) {
	html,
	body {
		overflow-x: clip;
	}
}

body {
	margin: 0;
	font-family: var(--nb-font);
	font-size: var(--nb-text-base);
	line-height: 1.5;
	color: var(--nb-text);
	background-color: var(--nb-surface);
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
}

img,
svg,
video,
canvas {
	display: block;
	max-width: 100%;
	height: auto;
}

a {
	color: inherit;
	text-decoration: none;
}

button {
	font: inherit;
	color: inherit;
	background: none;
	border: 0;
	padding: 0;
	cursor: pointer;
}

h1,
h2,
h3,
h4,
h5,
h6,
p,
figure,
blockquote,
ul,
ol,
dd {
	margin: 0;
}

ul,
ol {
	padding: 0;
	list-style: none;
}

:focus-visible {
	outline: 2px solid var(--nb-pink);
	outline-offset: 2px;
}

/* Skip link — keyboard users land here first. */
.nb-skip-link {
	position: absolute;
	top: -100%;
	left: 0.5rem;
	z-index: 100;
	padding: 0.75rem 1.25rem;
	background: var(--nb-white);
	color: var(--nb-gray-900);
	border-radius: var(--nb-radius);
	box-shadow: var(--nb-shadow-lg);
	font-weight: 600;
}

.nb-skip-link:focus {
	top: 0.5rem;
}

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

/* ==========================================================================
   3. Layout primitives
   --------------------------------------------------------------------------
   The Next build overrode Tailwind's `.container` with `max-width: 100%` plus
   a 1rem gutter, so the original site was genuinely full-bleed at every
   breakpoint — verified against the production DOM. This build clamps it at
   `--nb-max-width` instead, because a line of body copy stretched across a
   2560px monitor is unreadable, and a four-column grid at that width leaves
   cards further apart than they are wide.

   The clamp is on the **container**, not the section. Section backgrounds stay
   edge to edge, so the alternating white and grey bands still read as bands;
   what centres inside them is the content. Clamping the section itself would
   put grey margins down both sides of every white band.

   Below 1640px this is a no-op, so the site is unchanged on every laptop and
   phone — `.nb-container--narrow` and `--wide` clamp tighter still and come
   later in the cascade, so they keep winning where a block asks for them.
   ========================================================================== */

.nb-container {
	width: 100%;
	max-width: var(--nb-max-width);
	margin-left: auto;
	margin-right: auto;
	padding-left: var(--nb-gutter);
	padding-right: var(--nb-gutter);
}

.nb-container--narrow {
	max-width: 48rem; /* max-w-3xl */
}

.nb-container--wide {
	max-width: 56rem; /* max-w-4xl */
}

.nb-section {
	padding-top: 5rem; /* py-20 */
	padding-bottom: 5rem;
}

.nb-section--tall {
	padding-top: 9rem; /* py-36 */
	padding-bottom: 9rem;
}

.nb-section--light {
	background-color: var(--nb-white);
}

.nb-section--muted {
	background-color: var(--nb-gray-50);
}

.nb-section--brand {
	background-image: var(--nb-gradient);
	color: var(--nb-white);
}

.nb-section--dark {
	background-image: linear-gradient(
		to bottom right,
		var(--nb-gray-900),
		var(--nb-gray-800),
		var(--nb-black)
	);
	color: var(--nb-white);
}

/*
 * The dark surfaces the SEO set uses.
 *
 * These live here rather than beside the one block that first needed them,
 * because a block's stylesheet only loads when that block is on the page —
 * `--night` used to sit in comparison-grid/style.scss, which meant a process
 * section asking for it on a page with no comparison table rendered light grey
 * with white text on it. See "Two traps worth knowing about" in DEVELOPMENT.md.
 */
.nb-section--night {
	background-image: linear-gradient(
		to bottom,
		var(--nb-gray-900),
		var(--nb-gray-900),
		var(--nb-black)
	);
	color: var(--nb-white);
}

/* Flat near-black: the methodology sections and the ecosystem hub. */
.nb-section--ink {
	background-color: var(--nb-gray-900);
	color: var(--nb-white);
}

.nb-section--slate {
	background-color: var(--nb-slate-900);
	color: var(--nb-white);
}

.nb-section--slate-deep {
	background-color: var(--nb-slate-950);
	color: var(--nb-white);
}

.nb-section--midnight {
	background-color: var(--nb-gray-950);
	color: var(--nb-white);
}

/*
 * On any dark surface the section header has to invert. Doing it once here,
 * keyed off the surface rather than off the block, is what lets the same
 * Process Steps or Feature Grid block sit on white and on near-black without
 * either one knowing which it is.
 */
.nb-section--night .nb-lead,
.nb-section--ink .nb-lead,
.nb-section--slate .nb-lead,
.nb-section--slate-deep .nb-lead,
.nb-section--midnight .nb-lead,
.nb-section--dark .nb-lead {
	color: rgba(255, 255, 255, 0.8);
}

.nb-section--night h2,
.nb-section--night h3,
.nb-section--ink h2,
.nb-section--ink h3,
.nb-section--slate h2,
.nb-section--slate h3,
.nb-section--slate-deep h2,
.nb-section--slate-deep h3,
.nb-section--midnight h2,
.nb-section--midnight h3,
.nb-section--dark h2,
.nb-section--dark h3 {
	color: var(--nb-white);
}

/*
 * The accent scope.
 *
 * `single-nb_service.php` and `single-nb_sub_service.php` print this wrapper
 * with the page's two accent stops as inline custom properties. Everything
 * inside then reads --nb-accent-from / --nb-accent-to and comes out in that
 * page's colours without a single block being told which page it is on.
 */
.nb-accent-scope {
	display: contents;
}

.nb-main {
	/*
	 * Containing the hero orbs, which are positioned outside the viewport on
	 * purpose and would otherwise give the page a horizontal scrollbar.
	 *
	 * `hidden` is the fallback and `clip` is the real answer. They look
	 * identical and behave differently in one way that matters here: `hidden`
	 * makes this element a scroll container, and a scroll container between a
	 * `position: sticky` element and the viewport stops the sticky from ever
	 * sticking. That is exactly what happened to the diagram sequences, which
	 * scrolled straight past and left a screen of empty space behind them.
	 */
	overflow: hidden;
}

@supports (overflow: clip) {
	.nb-main {
		overflow-x: clip;
		overflow-y: visible;
	}
}

/* ==========================================================================
   4. Typography
   ========================================================================== */

.nb-heading-xl,
.nb-heading-lg,
.nb-heading-md {
	font-weight: 700;
	letter-spacing: -0.01em;
}

.nb-heading-xl {
	font-size: var(--nb-text-4xl);
	line-height: 1.2;
}

.nb-heading-lg {
	font-size: var(--nb-text-4xl);
	line-height: 1.15;
}

.nb-heading-md {
	font-size: var(--nb-text-2xl);
	line-height: 1.25;
}

.nb-eyebrow {
	font-size: var(--nb-text-sm);
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.1em;
	color: var(--nb-pink);
	margin-bottom: 0.75rem;
}

.nb-lead {
	font-size: var(--nb-text-xl);
	color: var(--nb-text-muted);
	line-height: 1.625;
}

.nb-section__header {
	text-align: center;
	margin-bottom: 4rem;
}

.nb-section__header .nb-lead {
	max-width: 48rem;
	margin-left: auto;
	margin-right: auto;
}

/* A left-aligned section header keeps its lead flush rather than centred. */
.nb-section__header--left {
	text-align: left;
}

.nb-section__header--left .nb-lead {
	margin-left: 0;
	margin-right: 0;
}

/* The signature gradient word inside a heading. */
.nb-gradient-text {
	background-image: var(--nb-gradient-tri);
	background-size: 400% 400%;
	-webkit-background-clip: text;
	background-clip: text;
	color: transparent;
	-webkit-text-fill-color: transparent;
	animation: nb-gradient-x 3s ease infinite;
}

/*
 * A whole heading filled with the page's accent pair, rather than one tinted
 * word inside it. Static, not animated: this is used on the metrics headings,
 * where the section is a wall of small text and a moving heading over it reads
 * as a bug rather than as flair.
 */
.nb-accent-text {
	background-image: var(--nb-accent-gradient);
	-webkit-background-clip: text;
	background-clip: text;
	color: transparent;
	-webkit-text-fill-color: transparent;
}

.nb-gradient-text--block {
	display: block;
}

.nb-gradient-text--xy {
	animation-name: nb-gradient-xy;
	animation-duration: 4s;
}

.nb-gradient-text--y {
	animation-name: nb-gradient-y;
}

@media (min-width: 768px) {
	.nb-heading-xl {
		font-size: var(--nb-text-7xl);
	}

	.nb-heading-lg {
		font-size: var(--nb-text-5xl);
	}
}

/* ==========================================================================
   4b. Prose
   ==========================================================================
   Typography for ordinary written content — the Prose Section block, blog
   posts, and legal pages all render into `.nb-prose`. It lives here rather
   than in the block's stylesheet because the single-post template uses it
   with no Prose Section block on the page, and a block stylesheet is only
   loaded when its block is present.

   Everything is scoped to `.nb-prose` so it never leaks into the designed
   sections, which set their own type.
   ========================================================================== */

.nb-prose {
	color: var(--nb-gray-700);
	line-height: 1.8;
}

.nb-prose > * + * {
	margin-top: 1.5rem;
}

.nb-prose h2,
.nb-prose h3,
.nb-prose h4 {
	color: var(--nb-gray-900);
	font-weight: 700;
	letter-spacing: -0.01em;
	line-height: 1.3;
}

.nb-prose h2 {
	margin-top: 3rem;
	padding-bottom: 0.5rem;
	border-bottom: 1px solid var(--nb-gray-200);
	font-size: var(--nb-text-2xl);
}

.nb-prose h3 {
	margin-top: 2.5rem;
	font-size: var(--nb-text-xl);
}

.nb-prose a {
	color: var(--nb-pink);
	text-decoration: underline;
	text-underline-offset: 2px;
}

.nb-prose strong {
	color: var(--nb-gray-900);
}

.nb-prose ul,
.nb-prose ol {
	padding-left: 1.5rem;
	color: var(--nb-gray-800);
}

.nb-prose ul {
	list-style-type: disc;
}

.nb-prose ol {
	list-style-type: decimal;
}

.nb-prose li + li {
	margin-top: 0.5rem;
}

.nb-prose li::marker {
	color: var(--nb-gray-800);
}

.nb-prose blockquote {
	padding: 0.75rem 1.5rem;
	border-left: 4px solid rgba(255, 64, 129, 0.6);
	border-radius: 0 var(--nb-radius-sm) var(--nb-radius-sm) 0;
	background-color: var(--nb-gray-50);
	color: var(--nb-gray-800);
	font-style: italic;
}

.nb-prose code {
	padding: 0.125rem 0.375rem;
	border-radius: var(--nb-radius-sm);
	background-color: var(--nb-gray-100);
	color: #9d174d;
}

.nb-prose pre {
	overflow-x: auto;
	padding: 1rem;
	border-radius: var(--nb-radius);
	background-color: var(--nb-gray-900);
	color: var(--nb-gray-100);
}

.nb-prose pre code {
	padding: 0;
	background: none;
	color: inherit;
}

.nb-prose img {
	max-height: 700px;
	margin-left: auto;
	margin-right: auto;
	border-radius: var(--nb-radius);
	box-shadow: var(--nb-shadow-sm);
}

.nb-prose figcaption {
	margin-top: 0.5rem;
	font-size: var(--nb-text-sm);
	text-align: center;
	color: var(--nb-text-subtle);
}

.nb-prose table {
	width: 100%;
	border-collapse: collapse;
}

.nb-prose th,
.nb-prose td {
	padding: 0.5rem 0.75rem;
	border: 1px solid var(--nb-gray-200);
	vertical-align: top;
}

.nb-prose th {
	background-color: var(--nb-gray-50);
	color: var(--nb-gray-900);
	font-weight: 600;
}

.nb-prose hr {
	margin: 2.5rem 0;
	border: 0;
	border-top: 1px solid var(--nb-gray-200);
}

/* Wide media inside a narrow column should still be able to breathe. */
.nb-prose .alignwide,
.nb-prose .alignfull {
	max-width: none;
}

/* ==========================================================================
   4c. Post listings and articles
   ==========================================================================
   The post card is shared by the Post Grid block, the blog archive and the
   search results, so it lives in the theme stylesheet rather than in the
   block's — the archive templates use the markup with no Post Grid block on
   the page, and a block stylesheet only loads when its block is present.
   ========================================================================== */

.nb-postgrid__grid {
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	gap: 2rem;
}

.nb-postgrid__empty {
	padding: 3rem 0;
	text-align: center;
	color: var(--nb-text-subtle);
	font-size: var(--nb-text-lg);
}

.nb-postcard {
	display: flex;
	flex-direction: column;
	height: 100%;
	overflow: hidden;
	border: 1px solid var(--nb-border);
	border-radius: var(--nb-radius-lg);
	background-color: var(--nb-white);
	transition: box-shadow 0.3s ease, transform 0.3s ease;
}

.nb-postcard:hover {
	box-shadow: var(--nb-shadow-xl);
	transform: translateY(-0.25rem);
}

.nb-postcard__media {
	display: block;
	overflow: hidden;
	background-color: var(--nb-gray-100);
	aspect-ratio: 16 / 9;
}

.nb-postcard__image {
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.nb-postcard__body {
	display: flex;
	flex: 1;
	flex-direction: column;
	align-items: flex-start;
	padding: 1.5rem;
}

.nb-postcard__meta {
	display: flex;
	align-items: center;
	gap: 0.5rem;
	margin-bottom: 0.75rem;
	font-size: var(--nb-text-sm);
	color: var(--nb-text-subtle);
}

.nb-postcard__category {
	padding: 0.125rem 0.625rem;
	border-radius: var(--nb-radius-full);
	background-image: var(--nb-gradient);
	color: var(--nb-white);
	font-weight: 600;
	font-size: 0.75rem;
}

.nb-postcard__title {
	margin-bottom: 0.75rem;
	font-size: var(--nb-text-xl);
	font-weight: 700;
	line-height: 1.3;
}

.nb-postcard__title a:hover {
	color: var(--nb-pink);
}

.nb-postcard__excerpt {
	margin-bottom: 1.5rem;
	color: var(--nb-text-muted);
	line-height: 1.625;
}

.nb-postcard__link {
	display: inline-flex;
	align-items: center;
	gap: 0.5rem;
	margin-top: auto;
	font-weight: 500;
	color: var(--nb-pink);
}

.nb-postcard__link:hover .nb-btn__icon {
	transform: translateX(0.25rem);
}

@media (min-width: 768px) {
	.nb-postgrid__grid {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

@media (min-width: 1024px) {
	.nb-postgrid__grid[data-columns='3'] {
		grid-template-columns: repeat(3, minmax(0, 1fr));
	}
}

/* --- Pagination ---------------------------------------------------------- */

.nb-pagination {
	margin-top: 4rem;
}

.nb-pagination .nav-links {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: center;
	gap: 0.5rem;
}

.nb-pagination .page-numbers {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 2.5rem;
	height: 2.5rem;
	padding: 0 0.75rem;
	border: 1px solid var(--nb-border);
	border-radius: var(--nb-radius);
	color: var(--nb-gray-700);
	font-weight: 500;
	transition: border-color 0.2s ease, color 0.2s ease;
}

.nb-pagination a.page-numbers:hover {
	border-color: var(--nb-pink);
	color: var(--nb-pink);
}

.nb-pagination .page-numbers.current {
	border-color: transparent;
	background-image: var(--nb-gradient);
	color: var(--nb-white);
}

.nb-pagination .page-numbers.dots {
	border-color: transparent;
}

/* --- Single article ------------------------------------------------------ */

.nb-article__meta {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: center;
	gap: 0.5rem;
	margin-bottom: 2.5rem;
	color: var(--nb-text-subtle);
	font-size: var(--nb-text-sm);
}

.nb-article__figure {
	margin-bottom: 3rem;
}

.nb-article__image {
	width: 100%;
	border-radius: var(--nb-radius-lg);
	box-shadow: var(--nb-shadow-lg);
}

.nb-article__figure figcaption {
	margin-top: 0.75rem;
	text-align: center;
	font-size: var(--nb-text-sm);
	color: var(--nb-text-subtle);
}

.nb-article__tags {
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem;
	margin-top: 3rem;
	list-style: none;
}

.nb-article__tags a {
	display: inline-block;
	padding: 0.25rem 0.75rem;
	border-radius: var(--nb-radius-full);
	background-color: var(--nb-gray-100);
	color: var(--nb-gray-700);
	font-size: var(--nb-text-sm);
	transition: background-color 0.2s ease, color 0.2s ease;
}

.nb-article__tags a:hover {
	background-color: var(--nb-gray-200);
	color: var(--nb-pink);
}

.nb-article__nav {
	display: grid;
	gap: 1rem;
	margin-top: 4rem;
	padding-top: 2rem;
	border-top: 1px solid var(--nb-border);
}

.nb-article__nav-link {
	display: block;
	padding: 1.25rem;
	border: 1px solid var(--nb-border);
	border-radius: var(--nb-radius-lg);
	transition: border-color 0.2s ease;
}

.nb-article__nav-link:hover {
	border-color: var(--nb-pink);
}

.nb-article__nav-link--next {
	text-align: right;
}

.nb-article__nav-label {
	display: block;
	margin-bottom: 0.25rem;
	font-size: var(--nb-text-sm);
	color: var(--nb-text-subtle);
}

.nb-article__nav-title {
	display: block;
	font-weight: 600;
	color: var(--nb-gray-900);
}

@media (min-width: 768px) {
	.nb-article__nav {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

/* ==========================================================================
   5. Buttons
   ========================================================================== */

.nb-btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 0.5rem;
	padding: 0.5rem 1rem;
	border-radius: var(--nb-radius);
	border: 1px solid transparent;
	font-size: var(--nb-text-sm);
	font-weight: 500;
	line-height: 1.25rem;
	white-space: nowrap;
	cursor: pointer;
	transition: color 0.3s ease, background-color 0.3s ease, border-color 0.3s ease,
		box-shadow 0.3s ease, transform 0.3s ease, opacity 0.3s ease;
}

.nb-btn--lg {
	font-size: var(--nb-text-lg);
	padding: 1rem 2rem;
	border-radius: var(--nb-radius);
}

.nb-btn__icon {
	flex-shrink: 0;
	transition: transform 0.2s ease;
}

/* Primary — the brand gradient pill. */
.nb-btn--primary {
	background-image: var(--nb-gradient);
	color: var(--nb-white);
}

.nb-btn--primary:hover {
	box-shadow: var(--nb-shadow-2xl);
	transform: scale(1.05);
}

/* Outline on a light surface. */
.nb-btn--outline {
	border-color: var(--nb-gray-300);
	color: var(--nb-gray-700);
	background-color: transparent;
}

.nb-btn--outline:hover {
	border-color: var(--nb-pink);
	color: var(--nb-pink);
}

.nb-btn--outline:hover .nb-btn__icon {
	transform: translateX(0.25rem);
}

/* Outline in brand pink — "View all services". */
.nb-btn--outline-brand {
	border-color: var(--nb-pink);
	color: var(--nb-pink);
	background-color: transparent;
}

.nb-btn--outline-brand:hover {
	background-color: var(--nb-pink);
	color: var(--nb-white);
}

/* Solid white on a coloured band — the CTA section. */
.nb-btn--on-brand {
	background-color: var(--nb-white);
	color: var(--nb-black);
	border-color: var(--nb-white);
}

.nb-btn--on-brand:hover {
	background-color: var(--nb-gray-100);
	color: var(--nb-blue);
}

/*
 * The radial "ink" hover from the original globals.css: a dot of brand
 * gradient scales up from the centre of the button and swallows it.
 */
.nb-btn--ink {
	position: relative;
	overflow: hidden;
	isolation: isolate;
	background-color: transparent;
	border-color: var(--nb-white);
	color: var(--nb-white);
}

.nb-btn--ink::before {
	content: '';
	position: absolute;
	top: 50%;
	left: 50%;
	width: 0;
	height: 0;
	border-radius: 50%;
	background-image: radial-gradient(circle, var(--nb-pink), var(--nb-blue));
	transform: translate(-50%, -50%);
	transition: width 0.6s ease, height 0.6s ease;
	z-index: -1;
}

.nb-btn--ink:hover::before {
	width: 300px;
	height: 300px;
}

.nb-btn--ink:hover {
	color: var(--nb-white);
	transform: translateY(-2px);
	box-shadow: 0 10px 25px rgba(255, 64, 129, 0.3);
}

/* ==========================================================================
   6. Keyframes
   ========================================================================== */

@keyframes nb-gradient-x {
	0%,
	100% {
		background-position: 0% 50%;
	}
	50% {
		background-position: 100% 50%;
	}
}

@keyframes nb-gradient-y {
	0%,
	100% {
		background-position: 50% 0%;
	}
	50% {
		background-position: 50% 100%;
	}
}

@keyframes nb-gradient-xy {
	0%,
	100% {
		background-position: 0% 0%;
	}
	25% {
		background-position: 100% 0%;
	}
	50% {
		background-position: 100% 100%;
	}
	75% {
		background-position: 0% 100%;
	}
}

@keyframes nb-pulse {
	0%,
	100% {
		opacity: 1;
	}
	50% {
		opacity: 0.5;
	}
}

@keyframes nb-bounce {
	0%,
	100% {
		transform: translateY(-25%);
		animation-timing-function: cubic-bezier(0.8, 0, 1, 1);
	}
	50% {
		transform: none;
		animation-timing-function: cubic-bezier(0, 0, 0.2, 1);
	}
}

@keyframes nb-slide-in-from-top {
	from {
		transform: translateY(-100%);
		opacity: 0;
	}
	to {
		transform: translateY(0);
		opacity: 1;
	}
}

@keyframes nb-slide-out-to-top {
	from {
		transform: translateY(0);
		opacity: 1;
	}
	to {
		transform: translateY(-100%);
		opacity: 0;
	}
}

@keyframes nb-fade-in-up {
	from {
		transform: translateY(30px);
		opacity: 0;
	}
	to {
		transform: translateY(0);
		opacity: 1;
	}
}

@keyframes nb-fade-out-down {
	from {
		transform: translateY(0);
		opacity: 1;
	}
	to {
		transform: translateY(30px);
		opacity: 0;
	}
}

@keyframes nb-slide-down {
	from {
		opacity: 0;
		transform: translateY(-10px);
	}
	to {
		opacity: 1;
		transform: translateY(0);
	}
}

/* ==========================================================================
   7. Scroll reveal
   --------------------------------------------------------------------------
   The React AnimatedSection component, as CSS + a shared IntersectionObserver
   in main.js. Elements start displaced and transparent; `.is-revealed` puts
   them back. Without JS (or with reduced motion) they simply render in place,
   which is also what the original did during SSR.
   ========================================================================== */

.nb-reveal {
	opacity: 1;
	transform: none;
}

.js .nb-reveal {
	opacity: 0;
	transition: opacity var(--nb-reveal-duration) ease-out,
		transform var(--nb-reveal-duration) ease-out;
	transition-delay: var(--nb-reveal-delay, 0ms);
}

.js .nb-reveal--up {
	transform: translateY(2rem);
}

.js .nb-reveal--left {
	transform: translateX(-2rem);
}

.js .nb-reveal--right {
	transform: translateX(2rem);
}

.js .nb-reveal--scale {
	transform: scale(0.95);
}

.js .nb-reveal.is-revealed {
	opacity: 1;
	transform: none;
}

@media (prefers-reduced-motion: reduce) {
	html {
		scroll-behavior: auto;
	}

	.js .nb-reveal,
	.js .nb-reveal--up,
	.js .nb-reveal--left,
	.js .nb-reveal--right,
	.js .nb-reveal--scale {
		opacity: 1;
		transform: none;
		transition: none;
	}

	.nb-gradient-text,
	.nb-hero__orb,
	.nb-hero__scroll-cue,
	.nb-mobile-menu__orb {
		animation: none;
	}
}

/* ==========================================================================
   8. Site header
   --------------------------------------------------------------------------
   Fixed and transparent over the hero; on scroll past 50px it gains a frosted
   white bar and swaps the light logo for the dark one. `main.js` toggles
   `.is-scrolled`; everything else here is pure CSS.
   ========================================================================== */

.nb-header {
	position: fixed;
	top: 0;
	left: 0;
	width: 100%;
	z-index: 50;
	background-color: transparent;
	transition: background-color 0.3s ease, box-shadow 0.3s ease;
}

/*
 * Two ways into the solid state: scrolling past the hero (.is-scrolled), or
 * being on a view that never had a dark hero to sit over (.is-solid, set
 * server-side). Without the second, a white page renders the white logo on
 * a white bar.
 */
/*
 * No `backdrop-filter` here, and it must not come back.
 *
 * A backdrop-filter — like transform and filter — makes the element a
 * containing block for its `position: fixed` descendants. The full-width bar
 * panel is fixed and lives inside this header, so the moment the header gained
 * the blur on scroll, the panel stopped measuring `top` from the viewport and
 * started measuring it from the header. The admin bar's 32px compensation then
 * applied twice and the panel hung 32px below the header with a gap under it.
 *
 * Nothing is lost visually: the bar is 95% opaque white, so the blur behind it
 * was showing 5% of the page through a 12px blur — invisible. The panel itself
 * still blurs, and it is not an ancestor of anything fixed.
 */
.nb-header.is-scrolled,
.nb-header.is-solid {
	background-color: rgba(255, 255, 255, 0.95);
	box-shadow: var(--nb-shadow-lg);
}

/*
 * A third state, for the service pages: solid dark from the moment the page
 * loads, rather than transparent over the hero. Those pages open on a strong
 * gradient and the floating bar had no edge of its own against it.
 *
 * Every rule here is scoped `:not(.is-scrolled)`. The dark bar is only the
 * resting state — as soon as the visitor scrolls, `.is-scrolled` takes over
 * exactly as it does everywhere else on the site: white bar, dark logo, dark
 * links. This state replaces the transparent one, it does not replace that.
 */
.nb-header.is-dark:not(.is-scrolled) {
	background-color: var(--nb-gray-900);
}

.nb-header.is-dark:not(.is-scrolled) .nb-nav__link,
.nb-header.is-dark:not(.is-scrolled) .nb-nav__link--blue {
	color: var(--nb-white);
}

.nb-header.is-dark:not(.is-scrolled) .nb-nav__link:hover,
.nb-header.is-dark:not(.is-scrolled) .nb-nav__link--blue:hover {
	color: rgba(255, 255, 255, 0.8);
}

.nb-header.is-dark:not(.is-scrolled) .nb-header__toggle,
.nb-header.is-dark:not(.is-scrolled) .nb-header__toggle-icons {
	color: var(--nb-white);
}

.nb-header__bar {
	display: flex;
	align-items: center;
	justify-content: space-between;
	height: var(--nb-header-height);
	width: 100%;
}

.nb-header__brand {
	display: flex;
	align-items: center;
	flex-shrink: 0;
}

.nb-header__logo {
	width: 180px;
	height: 40px;
	object-fit: contain;
	object-position: left center;
}

/* Two logo files, cross-faded rather than swapped, so the change reads as
   part of the same transition as the bar itself. */
.nb-header__logo--dark {
	display: none;
}

.nb-header.is-scrolled .nb-header__logo--light,
.nb-header.is-solid .nb-header__logo--light {
	display: none;
}

.nb-header.is-scrolled .nb-header__logo--dark,
.nb-header.is-solid .nb-header__logo--dark {
	display: block;
}

/* At rest the dark bar keeps the white logo; scrolled, it swaps like the rest. */
.nb-header.is-dark:not(.is-scrolled) .nb-header__logo--light {
	display: block;
}

.nb-header.is-dark:not(.is-scrolled) .nb-header__logo--dark {
	display: none;
}

/* --- Desktop navigation --------------------------------------------------- */

/*
 * The nav and each of its items stretch to the full 80px header height, so the
 * hover target reaches all the way down to where the flyouts begin. Sizing the
 * items to the text alone leaves a dead band between link and panel, and the
 * SEO bar menu — which is fixed at the header's bottom edge — closes before the
 * pointer can cross it.
 */
.nb-nav {
	display: none;
	align-self: stretch;
	align-items: stretch;
	gap: 2rem;
}

/* The Contact button is a direct child, and must not stretch with them. */
.nb-nav > .nb-btn {
	align-self: center;
}

@media (min-width: 1024px) {
	.nb-nav {
		display: flex;
	}
}

/*
 * Both pillars now have their own top-level slot, so the bar carries seven
 * items rather than five. At the narrow end of the desktop range that is a
 * squeeze, and a nav that wraps is worse than one that is a little tighter.
 */
@media (min-width: 1024px) and (max-width: 1279px) {
	.nb-nav {
		gap: 1.25rem;
	}
}

.nb-nav__item {
	position: relative;
	display: flex;
	align-items: center;
}

/*
 * An invisible strip just below each nav item. The SEO panel is
 * position:fixed and starts at the header's bottom edge, so any sub-pixel
 * rounding between the two leaves a dead row where the pointer is over
 * neither — and the panel closes mid-approach. This spans that row.
 */
.nb-nav__item::after {
	content: '';
	position: absolute;
	top: 100%;
	left: 0;
	right: 0;
	height: 14px;
}

.nb-nav__link {
	height: 100%;
}

.nb-nav__link {
	display: flex;
	align-items: center;
	gap: 0.25rem;
	font-weight: 500;
	color: var(--nb-pink);
	transition: color 0.3s ease;
}

/* Two nav links (About, Blog) are blue rather than pink over the hero. */
.nb-nav__link--blue {
	color: var(--nb-blue);
}

.nb-nav__link:hover {
	color: rgba(255, 64, 129, 0.8);
}

.nb-nav__link--blue:hover {
	color: rgba(0, 178, 255, 0.8);
}

.nb-header.is-scrolled .nb-nav__link,
.nb-header.is-scrolled .nb-nav__link--blue,
.nb-header.is-solid .nb-nav__link,
.nb-header.is-solid .nb-nav__link--blue {
	color: var(--nb-gray-700);
}

.nb-header.is-scrolled .nb-nav__link:hover,
.nb-header.is-scrolled .nb-nav__link--blue:hover,
.nb-header.is-solid .nb-nav__link:hover,
.nb-header.is-solid .nb-nav__link--blue:hover {
	color: var(--nb-pink);
}

/*
 * Over the brand-gradient hero the whole palette inverts: the pink and blue
 * link colours have nothing to contrast against, so everything goes white and
 * the dark logo takes over from the light one.
 */
.nb-header.is-on-brand:not(.is-scrolled) .nb-nav__link,
.nb-header.is-on-brand:not(.is-scrolled) .nb-nav__link--blue {
	color: var(--nb-white);
}

.nb-header.is-on-brand:not(.is-scrolled) .nb-nav__link:hover,
.nb-header.is-on-brand:not(.is-scrolled) .nb-nav__link--blue:hover {
	color: rgba(255, 255, 255, 0.8);
}

.nb-header.is-on-brand:not(.is-scrolled) .nb-header__toggle-icons {
	color: var(--nb-white);
}

/* The gradient Contact button vanishes into the gradient behind it. */
.nb-header.is-on-brand:not(.is-scrolled) .nb-nav > .nb-btn--primary {
	background-image: none;
	background-color: var(--nb-white);
	color: var(--nb-pink);
}

.nb-nav__chevron {
	flex-shrink: 0;
	transition: transform 0.3s ease;
}

/* --- Mega menu (Services) -------------------------------------------------- */

.nb-megamenu {
	position: absolute;
	top: 100%;
	left: 50%;
	width: 800px;
	padding-top: 0.5rem;
	z-index: 50;
	opacity: 0;
	transform: translateX(-50%) translateY(0.5rem) scale(0.95);
	pointer-events: none;
	transition: opacity 0.3s ease-out, transform 0.3s ease-out;
}

.nb-nav__item:hover > .nb-megamenu,
.nb-nav__item:focus-within > .nb-megamenu,
.nb-nav__item.is-open > .nb-megamenu {
	opacity: 1;
	transform: translateX(-50%) translateY(0) scale(1);
	pointer-events: auto;
}

.nb-megamenu__panel {
	position: relative;
	background-color: var(--nb-white);
	padding: 2rem;
	border-radius: var(--nb-radius-xl);
	border: 1px solid rgba(255, 255, 255, 0.1);
	box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
}

/* An invisible lip above the panel keeps hover alive across the gap. */
.nb-megamenu__panel::before {
	content: '';
	position: absolute;
	top: -8px;
	left: 0;
	right: 0;
	height: 8px;
	background: transparent;
}

.nb-megamenu__grid {
	display: grid;
	grid-template-columns: repeat(4, minmax(0, 1fr));
	gap: 1.5rem;
}

.nb-megamenu__link {
	display: block;
	padding: 0.5rem;
	border-radius: var(--nb-radius-lg);
	transition: background-color 0.2s ease;
}

.nb-megamenu__link:hover {
	background-image: linear-gradient(
		to bottom right,
		rgba(255, 64, 129, 0.05),
		rgba(0, 178, 255, 0.05)
	);
}

.nb-megamenu__icon {
	width: 2.5rem;
	height: 2.5rem;
	display: flex;
	align-items: center;
	justify-content: center;
	border-radius: var(--nb-radius);
	background-image: var(--nb-gradient);
	color: var(--nb-white);
	transition: transform 0.2s ease;
}

.nb-megamenu__link:hover .nb-megamenu__icon {
	transform: scale(1.1);
}

.nb-megamenu__title {
	display: block;
	margin-top: 0.25rem;
	font-weight: 600;
	color: var(--nb-gray-900);
	transition: color 0.2s ease;
}

.nb-megamenu__link:hover .nb-megamenu__title {
	color: var(--nb-pink);
}

.nb-megamenu__desc {
	display: block;
	font-size: var(--nb-text-sm);
	color: var(--nb-gray-600);
}

.nb-megamenu__footer {
	margin-top: 1.5rem;
	padding-top: 1.5rem;
	border-top: 1px solid var(--nb-gray-100);
	text-align: center;
}

.nb-megamenu__more {
	display: inline-flex;
	align-items: center;
	gap: 0.25rem;
	font-weight: 500;
	color: var(--nb-pink);
}

.nb-megamenu__more:hover {
	color: rgba(255, 64, 129, 0.8);
}

/* --- Full-width bar menu (SEO) --------------------------------------------- */

.nb-barmenu {
	position: fixed;
	top: var(--nb-header-height);
	left: 0;
	width: 100%;
	background-color: rgba(255, 255, 255, 0.95);
	backdrop-filter: blur(12px);
	-webkit-backdrop-filter: blur(12px);
	box-shadow: var(--nb-shadow-lg);
	border-top: 1px solid var(--nb-gray-100);
	opacity: 0;
	transform: translateY(-0.5rem);
	pointer-events: none;
	transition: opacity 0.3s ease-out, transform 0.3s ease-out;
	z-index: 40;
}

.nb-nav__item:hover > .nb-barmenu,
.nb-nav__item:focus-within > .nb-barmenu,
.nb-nav__item.is-open > .nb-barmenu {
	opacity: 1;
	transform: translateY(0);
	pointer-events: auto;
}

.nb-barmenu__inner {
	padding-top: 2rem;
	padding-bottom: 2rem;
}

.nb-barmenu__grid {
	display: grid;
	grid-template-columns: repeat(4, minmax(0, 1fr));
	gap: 1.5rem;
}

.nb-barmenu__link {
	display: flex;
	align-items: center;
	gap: 1rem;
	padding: 1rem;
	border: 1px solid transparent;
	border-radius: var(--nb-radius-lg);
	transition: background-color 0.2s ease, border-color 0.2s ease;
}

.nb-barmenu__link:hover {
	background-image: linear-gradient(
		to bottom right,
		rgba(255, 64, 129, 0.05),
		rgba(0, 178, 255, 0.05)
	);
	border-color: var(--nb-gray-100);
}

.nb-barmenu__icon {
	width: 3rem;
	height: 3rem;
	flex-shrink: 0;
	display: flex;
	align-items: center;
	justify-content: center;
	border-radius: var(--nb-radius);
	background-image: var(--nb-gradient);
	color: var(--nb-white);
	box-shadow: var(--nb-shadow-md);
	transition: transform 0.2s ease;
}

.nb-barmenu__link:hover .nb-barmenu__icon {
	transform: scale(1.1);
}

.nb-barmenu__title {
	display: block;
	font-size: var(--nb-text-lg);
	font-weight: 700;
	color: var(--nb-gray-900);
	transition: color 0.2s ease;
}

.nb-barmenu__link:hover .nb-barmenu__title {
	color: var(--nb-pink);
}

.nb-barmenu__desc {
	display: block;
	margin-top: 0.25rem;
	font-size: var(--nb-text-sm);
	color: var(--nb-gray-600);
}

/* --- Small dropdown (About) ------------------------------------------------ */

.nb-dropdown {
	position: absolute;
	top: 100%;
	left: 50%;
	width: 13rem;
	padding-top: 0.5rem;
	z-index: 50;
	opacity: 0;
	transform: translateX(-50%) translateY(0.5rem) scale(0.95);
	pointer-events: none;
	transition: opacity 0.3s ease-out, transform 0.3s ease-out;
}

.nb-nav__item:hover > .nb-dropdown,
.nb-nav__item:focus-within > .nb-dropdown,
.nb-nav__item.is-open > .nb-dropdown {
	opacity: 1;
	transform: translateX(-50%) translateY(0) scale(1);
	pointer-events: auto;
}

.nb-dropdown__panel {
	display: flex;
	flex-direction: column;
	gap: 0.25rem;
	padding: 0.75rem;
	background-color: var(--nb-white);
	border-radius: var(--nb-radius-xl);
	box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
}

.nb-dropdown__link {
	display: flex;
	align-items: center;
	gap: 0.75rem;
	padding: 0.75rem 1rem;
	border-radius: var(--nb-radius-lg);
	transition: background-color 0.2s ease;
}

.nb-dropdown__link:hover {
	background-image: linear-gradient(
		to bottom right,
		rgba(255, 64, 129, 0.05),
		rgba(0, 178, 255, 0.05)
	);
}

.nb-dropdown__icon {
	width: 2rem;
	height: 2rem;
	flex-shrink: 0;
	display: flex;
	align-items: center;
	justify-content: center;
	border-radius: var(--nb-radius);
	background-image: var(--nb-gradient);
	color: var(--nb-white);
	transition: transform 0.2s ease;
}

.nb-dropdown__link:hover .nb-dropdown__icon {
	transform: scale(1.1);
}

.nb-dropdown__title {
	display: block;
	font-size: var(--nb-text-sm);
	font-weight: 600;
	color: var(--nb-gray-900);
	transition: color 0.2s ease;
}

.nb-dropdown__link:hover .nb-dropdown__title {
	color: var(--nb-pink);
}

.nb-dropdown__desc {
	display: block;
	font-size: 0.75rem;
	color: var(--nb-gray-500);
}

/* --- Hamburger ------------------------------------------------------------- */

.nb-header__toggle {
	display: flex;
	flex-shrink: 0;
	align-items: center;
	justify-content: center;
	width: 2.5rem;
	height: 2.5rem;
	border-radius: var(--nb-radius);
	transition: background-color 0.2s ease;
}

.nb-header__toggle:hover {
	background-color: rgba(255, 64, 129, 0.1);
}

@media (min-width: 1024px) {
	.nb-header__toggle {
		display: none;
	}
}

.nb-header__toggle-icons {
	position: relative;
	width: 1.5rem;
	height: 1.5rem;
	color: var(--nb-pink);
}

.nb-header__toggle-icons svg {
	position: absolute;
	inset: 0;
	transition: opacity 0.3s ease, transform 0.3s ease;
}

.nb-header__toggle-icons .nb-icon-close,
.nb-header__toggle[aria-expanded='true'] .nb-icon-menu {
	opacity: 0;
	transform: rotate(180deg) scale(0.75);
}

.nb-header__toggle[aria-expanded='true'] .nb-icon-close {
	opacity: 1;
	transform: rotate(0) scale(1);
}

/* ==========================================================================
   9. Mobile menu
   ========================================================================== */

.nb-mobile-menu {
	position: fixed;
	inset: 0;
	z-index: 40;
	display: none;
}

.nb-mobile-menu.is-open {
	display: block;
}

@media (min-width: 1024px) {
	.nb-mobile-menu,
	.nb-mobile-menu.is-open {
		display: none;
	}
}

.nb-mobile-menu__surface {
	position: absolute;
	inset: 0;
	overflow-y: auto;
	background-image: linear-gradient(
		to bottom right,
		var(--nb-pink),
		#9333ea,
		var(--nb-blue)
	);
	animation: nb-slide-in-from-top 0.5s var(--nb-ease) forwards;
}

.nb-mobile-menu.is-closing .nb-mobile-menu__surface {
	animation: nb-slide-out-to-top 0.5s cubic-bezier(0.55, 0.06, 0.68, 0.19) forwards;
}

.nb-mobile-menu__orbs {
	position: absolute;
	inset: 0;
	overflow: hidden;
	pointer-events: none;
}

.nb-mobile-menu__orb {
	position: absolute;
	border-radius: var(--nb-radius-full);
	background-color: rgba(255, 255, 255, 0.1);
	filter: blur(64px);
	animation: nb-pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
}

.nb-mobile-menu__orb--1 {
	top: 5rem;
	left: 2.5rem;
	width: 18rem;
	height: 18rem;
}

.nb-mobile-menu__orb--2 {
	bottom: 5rem;
	right: 2.5rem;
	width: 24rem;
	height: 24rem;
	animation-delay: 1s;
}

.nb-mobile-menu__orb--3 {
	top: 50%;
	left: 50%;
	width: 600px;
	height: 600px;
	transform: translate(-50%, -50%);
	background-color: rgba(255, 255, 255, 0.05);
	animation: none;
}

.nb-mobile-menu__inner {
	position: relative;
	z-index: 10;
	display: flex;
	flex-direction: column;
	min-height: 100%;
	padding: 8rem 1rem 5rem;
	color: var(--nb-white);
}

.nb-mobile-menu__nav {
	flex: 1;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: 1.5rem;
	width: 100%;
	max-width: 24rem;
	margin: 0 auto;
	text-align: center;
}

.nb-mobile-menu__item {
	width: 100%;
	opacity: 0;
	animation: nb-fade-in-up 0.6s var(--nb-ease) forwards;
	animation-delay: var(--nb-stagger, 0.2s);
}

.nb-mobile-menu.is-closing .nb-mobile-menu__item {
	opacity: 1;
	animation: nb-fade-out-down 0.4s cubic-bezier(0.55, 0.06, 0.68, 0.19) forwards;
}

.nb-mobile-menu__link,
.nb-mobile-menu__disclosure {
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 0.5rem;
	width: 100%;
	font-size: var(--nb-text-3xl);
	font-weight: 700;
	color: var(--nb-white);
	transition: transform 0.3s ease;
}

.nb-mobile-menu__link:hover,
.nb-mobile-menu__disclosure:hover {
	transform: scale(1.1);
}

.nb-mobile-menu__disclosure[aria-expanded='true'] .nb-nav__chevron {
	transform: rotate(180deg);
}

.nb-mobile-menu__panel {
	overflow: hidden;
	max-height: 0;
	opacity: 0;
	transition: max-height 0.3s ease-out, opacity 0.3s ease-out,
		margin-top 0.3s ease-out;
}

.nb-mobile-menu__disclosure[aria-expanded='true'] + .nb-mobile-menu__panel {
	max-height: 40rem;
	opacity: 1;
	margin-top: 1.5rem;
}

.nb-mobile-menu__card {
	max-width: 24rem;
	margin: 0 auto;
	padding: 1.5rem;
	border-radius: var(--nb-radius-lg);
	background-color: rgba(255, 255, 255, 0.1);
	backdrop-filter: blur(4px);
	-webkit-backdrop-filter: blur(4px);
}

.nb-mobile-menu__grid {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: 1rem;
}

.nb-mobile-menu__service {
	display: block;
	padding: 0.75rem 1rem;
	text-align: start;
	border: 1px solid rgba(255, 255, 255, 0.2);
	border-radius: var(--nb-radius);
	color: rgba(255, 255, 255, 0.9);
	transition: background-color 0.2s ease, border-color 0.2s ease,
		transform 0.2s ease, color 0.2s ease;
}

.nb-mobile-menu__service:hover {
	background-color: rgba(255, 255, 255, 0.1);
	border-color: rgba(255, 255, 255, 0.4);
	color: var(--nb-white);
	transform: scale(1.05);
}

.nb-mobile-menu__service-icon {
	width: 2rem;
	height: 2rem;
	display: flex;
	align-items: center;
	justify-content: center;
	border-radius: var(--nb-radius);
	background-color: rgba(255, 255, 255, 0.2);
}

.nb-mobile-menu__service-label {
	display: block;
	margin-top: 1rem;
	font-size: var(--nb-text-sm);
	line-height: 1.25;
}

.nb-mobile-menu__card-footer {
	margin-top: 1rem;
	padding-top: 1rem;
	border-top: 1px solid rgba(255, 255, 255, 0.2);
	text-align: center;
}

.nb-mobile-menu__card-footer a {
	font-size: var(--nb-text-sm);
	font-weight: 500;
	color: rgba(255, 255, 255, 0.8);
}

.nb-mobile-menu__card-footer a:hover {
	color: var(--nb-white);
}

.nb-mobile-menu__cta {
	background-color: var(--nb-white);
	color: var(--nb-pink);
	font-size: var(--nb-text-xl);
	padding: 1rem 2rem;
	margin-top: 0.5rem;
}

.nb-mobile-menu__social {
	display: flex;
	justify-content: center;
	gap: 1.5rem;
	margin-top: 2rem;
	padding-bottom: 2rem;
	opacity: 0;
	animation: nb-fade-in-up 0.6s var(--nb-ease) forwards;
	animation-delay: 0.9s;
}

.nb-mobile-menu__social a {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 3rem;
	height: 3rem;
	border-radius: var(--nb-radius-full);
	background-color: rgba(255, 255, 255, 0.2);
	color: var(--nb-white);
	transition: background-color 0.2s ease;
}

.nb-mobile-menu__social a:hover {
	background-color: rgba(255, 255, 255, 0.3);
}

/* Scroll lock applied to <body> while the menu is open. */
.nb-scroll-locked {
	position: fixed;
	width: 100%;
	overflow: hidden;
}

/* ==========================================================================
   10. Site footer
   ========================================================================== */

.nb-footer {
	background-color: var(--nb-gray-900);
	color: var(--nb-white);
}

.nb-footer__inner {
	padding-top: 4rem;
	padding-bottom: 2rem;
}

.nb-footer__grid {
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	gap: 2rem;
}

@media (min-width: 768px) {
	.nb-footer__grid {
		grid-template-columns: repeat(4, minmax(0, 1fr));
	}
}

.nb-footer__brand {
	display: flex;
	flex-direction: column;
	gap: 1rem;
	align-items: flex-start;
}

.nb-footer__logo {
	width: 200px;
	height: 48px;
	object-fit: contain;
	object-position: left center;
}

.nb-footer__tagline {
	color: var(--nb-gray-400);
}

.nb-footer__social {
	display: flex;
	gap: 1rem;
}

.nb-footer__social a {
	color: var(--nb-gray-400);
	transition: color 0.2s ease;
}

.nb-footer__social a:nth-child(1):hover,
.nb-footer__social a:nth-child(3):hover {
	color: var(--nb-pink);
}

.nb-footer__social a:nth-child(2):hover {
	color: var(--nb-blue);
}

.nb-footer__heading {
	font-size: var(--nb-text-lg);
	font-weight: 600;
	margin-bottom: 1rem;
}

.nb-footer__nav a {
	color: var(--nb-gray-400);
	transition: color 0.2s ease;
}

.nb-footer__nav a:hover {
	color: var(--nb-white);
}

.nb-footer__list {
	display: flex;
	flex-direction: column;
	gap: 0.5rem;
}

/* The Services column splits into two columns from md up. */
.nb-footer__list--split {
	gap: 0.25rem;
}

@media (min-width: 768px) {
	.nb-footer__nav--services {
		padding-left: 2.5rem;
	}

	.nb-footer__nav--company {
		padding-left: 5rem;
	}

	.nb-footer__list--split {
		display: grid;
		grid-template-columns: repeat(2, minmax(0, 1fr));
		column-gap: 0.5rem;
		row-gap: 0.25rem;
	}
}

.nb-footer__contact {
	font-style: normal;
}

.nb-footer__contact-list {
	display: flex;
	flex-direction: column;
	gap: 0.75rem;
}

.nb-footer__contact-row {
	display: flex;
	align-items: center;
	gap: 0.75rem;
	color: var(--nb-gray-400);
}

.nb-footer__contact-row svg {
	flex-shrink: 0;
}

.nb-footer__contact-row--pink svg {
	color: var(--nb-pink);
}

.nb-footer__contact-row--blue svg {
	color: var(--nb-blue);
}

.nb-footer__contact-row a:hover {
	color: var(--nb-white);
}

.nb-footer__bottom {
	margin-top: 3rem;
	padding-top: 2rem;
	border-top: 1px solid var(--nb-gray-800);
	text-align: center;
	color: var(--nb-gray-400);
}

.nb-footer__bottom p + p {
	margin-top: 0.5rem;
	font-size: var(--nb-text-sm);
}

.nb-footer__bottom a {
	text-decoration: underline;
	text-underline-offset: 4px;
}

.nb-footer__bottom a:hover {
	color: var(--nb-white);
}

/* ==========================================================================
   11. Floating WhatsApp button
   ========================================================================== */

.nb-whatsapp {
	position: fixed;
	bottom: 1.5rem;
	right: 1.5rem;
	z-index: 50;
}

.nb-whatsapp__button {
	position: relative;
	display: flex;
	align-items: center;
	justify-content: center;
	width: 3.5rem;
	height: 3.5rem;
	border-radius: var(--nb-radius-full);
	background-color: #22c55e;
	color: var(--nb-white);
	box-shadow: var(--nb-shadow-lg);
	transition: background-color 0.3s ease, transform 0.3s ease, box-shadow 0.3s ease;
}

.nb-whatsapp__button:hover {
	background-color: #16a34a;
	transform: scale(1.1);
	box-shadow: var(--nb-shadow-xl);
}

.nb-whatsapp__button:focus-visible {
	outline: 4px solid rgba(134, 239, 172, 0.5);
	outline-offset: 0;
}

.nb-whatsapp__tooltip {
	position: absolute;
	bottom: 100%;
	right: 0;
	margin-bottom: 0.75rem;
	display: none;
}

.nb-whatsapp__button:hover .nb-whatsapp__tooltip,
.nb-whatsapp__button:focus-visible .nb-whatsapp__tooltip {
	display: block;
}

.nb-whatsapp__bubble {
	position: relative;
	white-space: nowrap;
	border-radius: var(--nb-radius);
	background-color: var(--nb-gray-800);
	padding: 0.5rem 0.75rem;
	font-size: var(--nb-text-sm);
	color: var(--nb-white);
	box-shadow: var(--nb-shadow-lg);
}

.nb-whatsapp__bubble::after {
	content: '';
	position: absolute;
	top: 100%;
	right: 1rem;
	width: 0;
	height: 0;
	border-left: 4px solid transparent;
	border-right: 4px solid transparent;
	border-top: 4px solid var(--nb-gray-800);
}

/* ==========================================================================
   12. Back-to-top button
   ========================================================================== */

.nb-to-top {
	position: fixed;
	bottom: 1.5rem;
	right: 5.5rem;
	z-index: 50;
	display: flex;
	align-items: center;
	justify-content: center;
	width: 3rem;
	height: 3rem;
	border-radius: var(--nb-radius-full);
	background-color: var(--nb-gray-900);
	color: var(--nb-white);
	box-shadow: var(--nb-shadow-lg);
	opacity: 0;
	visibility: hidden;
	transform: translateY(0.5rem);
	transition: opacity 0.3s ease, visibility 0.3s ease, transform 0.3s ease,
		background-color 0.3s ease;
}

.nb-to-top.is-visible {
	opacity: 1;
	visibility: visible;
	transform: translateY(0);
}

.nb-to-top:hover {
	background-image: var(--nb-gradient);
}

/* ==========================================================================
   13. Editor-only affordances
   --------------------------------------------------------------------------
   The block editor renders block markup without the theme's header/footer
   chrome, so a couple of fixed/viewport-relative rules need neutralising to
   keep the canvas usable.
   ========================================================================== */

.editor-styles-wrapper .nb-header,
.editor-styles-wrapper .nb-whatsapp,
.editor-styles-wrapper .nb-to-top {
	display: none;
}

.editor-styles-wrapper .nb-reveal {
	opacity: 1;
	transform: none;
}

/* ==========================================================================
   14. Admin bar
   --------------------------------------------------------------------------
   WordPress pushes the document down for the admin bar but leaves fixed
   elements where they are, so a logged-in editor would otherwise see the
   header sliding underneath it. Logged-out visitors never load any of this.
   ========================================================================== */

.admin-bar .nb-header {
	top: 32px;
}

.admin-bar .nb-barmenu {
	top: calc(var(--nb-header-height) + 32px);
}

.admin-bar .nb-mobile-menu {
	top: 32px;
}

@media screen and (max-width: 782px) {
	.admin-bar .nb-header {
		top: 46px;
	}

	.admin-bar .nb-barmenu {
		top: calc(var(--nb-header-height) + 46px);
	}

	.admin-bar .nb-mobile-menu {
		top: 46px;
	}
}

/* ==========================================================================
   15. Block editor helpers
   --------------------------------------------------------------------------
   Affordances that exist only on the editing canvas: the empty-state notice a
   repeater block shows before it has rows, and neutral placeholders standing
   in for icons the editor does not render.
   ========================================================================== */

.nb-block-empty {
	padding: 2rem;
	border: 1px dashed var(--nb-gray-300);
	border-radius: var(--nb-radius-lg);
	background-color: var(--nb-gray-50);
	color: var(--nb-text-subtle);
	text-align: center;
}

.editor-styles-wrapper {
	.nb-card__icon--placeholder,
	.nb-feature__icon:empty,
	.nb-step__icon:empty {
		opacity: 0.55;
	}

	.nb-card__icon--placeholder {
		border-radius: var(--nb-radius);
		background-color: rgba(255, 255, 255, 0.35);
	}

	/* Nested media blocks need room to be clicked into. */
	.nb-split__media {
		min-height: 6rem;
	}
}

/* ==========================================================================
   Glossary term footer
   --------------------------------------------------------------------------
   Lives here rather than with a block because `single-nb_term.php` draws it
   directly and there is no block on the page to carry the stylesheet. See
   "Two traps worth knowing about" in DEVELOPMENT.md.
   ========================================================================== */

.nb-termfoot__service {
	max-width: 42rem;
	margin-bottom: 3.5rem;
}

.nb-termfoot__eyebrow {
	margin-bottom: 0.5rem;
	font-size: var(--nb-text-sm);
	font-weight: 600;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	background-image: var(--nb-accent-gradient);
	-webkit-background-clip: text;
	background-clip: text;
	color: transparent;
	-webkit-text-fill-color: transparent;
}

.nb-termfoot__service .nb-lead {
	margin-bottom: 1.5rem;
}

.nb-termfoot__heading {
	margin-bottom: 1.25rem;
	font-size: var(--nb-text-xl);
	font-weight: 800;
	letter-spacing: -0.01em;
}

.nb-termfoot__related ul {
	display: grid;
	gap: 0.75rem;
	margin: 0;
	padding: 0;
	list-style: none;
	grid-template-columns: minmax(0, 1fr);
}

.nb-termfoot__related a {
	display: flex;
	flex-direction: column;
	gap: 0.2rem;
	height: 100%;
	padding: 1rem 1.15rem;
	border: 1px solid var(--nb-border);
	border-radius: var(--nb-radius-lg);
	background-color: var(--nb-white);
	color: var(--nb-text);
	transition: border-color 0.2s ease, box-shadow 0.2s ease;
}

.nb-termfoot__related a:hover {
	border-color: transparent;
	box-shadow: var(--nb-shadow-lg);
}

.nb-termfoot__related strong {
	font-size: var(--nb-text-base);
	font-weight: 700;
}

.nb-termfoot__related span {
	font-size: var(--nb-text-sm);
	line-height: 1.55;
	color: var(--nb-text-muted);
}

@media (min-width: 768px) {
	.nb-termfoot__related ul { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* -------------------------------------------------------------------------
 * The glossary strip on a service page
 *
 * Lives here rather than in a block, because it is printed by the service
 * templates and a block's stylesheet only loads on pages that contain it.
 * ---------------------------------------------------------------------- */

.nb-servterms__head {
	max-width: 40rem;
	margin-bottom: 2rem;
}

.nb-servterms__head h2 {
	margin: 0;
}

.nb-servterms__list {
	display: grid;
	gap: 0.75rem;
	margin: 0 0 2rem;
	padding: 0;
	list-style: none;
	grid-template-columns: minmax(0, 1fr);
}

.nb-servterms__list a {
	display: flex;
	flex-direction: column;
	gap: 0.3rem;
	height: 100%;
	padding: 1.1rem 1.25rem;
	border: 1px solid var(--nb-border);
	border-radius: var(--nb-radius-lg);
	background-color: var(--nb-white);
	transition: border-color 0.25s ease, box-shadow 0.25s ease, transform 0.25s ease;
}

.nb-servterms__list a:hover {
	border-color: transparent;
	box-shadow: var(--nb-shadow-lg);
	transform: translateY(-0.15rem);
}

.nb-servterms__list strong {
	font-size: var(--nb-text-base);
	font-weight: 700;
}

.nb-servterms__list span {
	font-size: var(--nb-text-sm);
	line-height: 1.55;
	color: var(--nb-text-muted);
}

.nb-servterms__all {
	display: inline-flex;
	align-items: center;
	gap: 0.4rem;
	font-weight: 600;
	/* Picks up the page's own accent pair; see inc/accents.php. */
	color: var(--nb-accent-to);
}

.nb-servterms__all:hover {
	color: var(--nb-accent-from);
}

@media (min-width: 768px) {
	.nb-servterms__list { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (min-width: 1280px) {
	.nb-servterms__list { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/* -------------------------------------------------------------------------
 * Diagram tokens
 *
 * The drawings in inc/diagrams.php read these rather than hardcoding colours,
 * which is what lets one SVG come out in six different accent pairs. They live
 * in style.css rather than in the block's own stylesheet because the diagrams
 * are printed by templates as well as by the block, and a block stylesheet only
 * loads on pages that contain that block.
 * ---------------------------------------------------------------------- */

:root {
	--nb-dg-bg: var(--nb-gray-50);
	--nb-dg-card: var(--nb-white);
	--nb-dg-line: var(--nb-gray-300);
	--nb-dg-faint: var(--nb-gray-100);
	--nb-dg-ink: var(--nb-text);
	--nb-dg-muted: var(--nb-text-muted);
	--nb-dg-ghost: var(--nb-gray-400);
	--nb-dg-from-dim: rgba(255, 64, 129, 0.1);
	--nb-dg-to-dim: rgba(0, 178, 255, 0.1);
}

/*
 * On a dark band the paper flips. The tinted fills stay as they are: they are
 * already low-alpha washes of the accent, so they read on either ground.
 */
.nb-section--night,
.nb-section--ink,
.nb-section--slate,
.nb-section--slate-deep,
.nb-section--midnight {
	--nb-dg-bg: rgba(255, 255, 255, 0.04);
	--nb-dg-card: rgba(255, 255, 255, 0.07);
	--nb-dg-line: rgba(255, 255, 255, 0.22);
	--nb-dg-faint: rgba(255, 255, 255, 0.12);
	--nb-dg-ink: #ffffff;
	--nb-dg-muted: rgba(255, 255, 255, 0.66);
	--nb-dg-ghost: rgba(255, 255, 255, 0.38);
}
