/*
Theme Name: Sebo Theme
Theme URI: https://sebomarketing.com
Author: Sebo Marketing
Author URI: https://sebomarketing.com
Description: Brand-agnostic WordPress block theme used as the starting point for Sebo Marketing client sites. All color, type, and spacing decisions live as design tokens in theme.json; this stylesheet only covers what theme.json cannot express. WooCommerce-ready.
Requires at least: 6.6
Tested up to: 7.0
Requires PHP: 8.1
Version: 1.0.0
License: GNU General Public License v2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
Text Domain: sebo
Tags: block-theme, full-site-editing, e-commerce, one-column, custom-colors, custom-menu, editor-style
*/

/* -------------------------------------------------------------------------
   1. Base
   ---------------------------------------------------------------------- */

:root {
	/* 3:1 against the field background, per WCAG 1.4.11. A hairline that
	   fails contrast is the thing that tells someone where the input is. */
	--sb-field-border: color-mix(in srgb, var(--wp--preset--color--ink) 58%, var(--wp--preset--color--base));
}

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

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

	*,
	*::before,
	*::after {
		animation-duration: 0.01ms !important;
		animation-iteration-count: 1 !important;
		transition-duration: 0.01ms !important;
	}
}

body {
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
	text-rendering: optimizeLegibility;
	font-optical-sizing: auto;
}

/* Balance short headings rather than leaving a single orphaned word. */
h1,
h2,
h3,
.wp-block-post-title {
	text-wrap: balance;
}

p,
li {
	text-wrap: pretty;
}

/* Body copy caps its measure even inside wide containers. */
:where(.entry-content) p:not([class*="has-"]) {
	max-width: 68ch;
}

img,
video {
	max-width: 100%;
	height: auto;
}

/* WordPress puts a block-gap margin between every top-level block, which
   leaves a white strip between the header and the first full-bleed section,
   and another between the last section and the footer. Sections carry their
   own padding, so those gaps are never wanted here. */
.wp-site-blocks > main,
.wp-site-blocks > .wp-block-template-part {
	margin-block-start: 0;
}

/* -------------------------------------------------------------------------
   2. Focus — a single visible treatment everywhere.
      Never remove this; keyboard users depend on it.
   ---------------------------------------------------------------------- */

:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
	outline: 3px solid var(--wp--preset--color--action);
	outline-offset: 2px;
	border-radius: 2px;
}

/* Dark grounds need a light ring to stay visible. */
.sb-on-dark :where(a, button, input, select, textarea):focus-visible {
	outline-color: var(--wp--preset--color--accent);
}

.skip-link {
	position: absolute;
	top: -100vh;
	left: 0;
	z-index: 999999;
	padding: 0.85rem 1.5rem;
	background: var(--wp--preset--color--ink);
	color: var(--wp--preset--color--base);
	font-family: var(--wp--preset--font-family--body);
	font-size: var(--wp--preset--font-size--small);
	font-weight: 600;
	text-decoration: none;
	border-bottom-right-radius: 6px;
}

.skip-link:focus {
	top: 0;
}

.screen-reader-text {
	position: absolute !important;
	width: 1px;
	height: 1px;
	padding: 0;
	margin: -1px;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
	border: 0;
}

/* -------------------------------------------------------------------------
   3. Links — underlines that sit below the baseline rather than
      slicing through descenders.
   ---------------------------------------------------------------------- */

:where(.entry-content, .wp-block-post-content) a:where(:not(.wp-element-button):not(.wp-block-button__link)) {
	text-decoration-thickness: 1px;
	text-underline-offset: 0.18em;
	text-decoration-color: color-mix(in srgb, var(--wp--preset--color--action) 42%, transparent);
	transition: text-decoration-color var(--wp--custom--transition--base);
}

:where(.entry-content, .wp-block-post-content) a:where(:not(.wp-element-button)):hover {
	text-decoration-color: currentColor;
}

/* Buttons and nav links must not inherit the content underline. */
.wp-block-navigation a,
.wp-element-button,
.wp-block-button__link {
	text-decoration: none;
}

.wp-element-button,
.wp-block-button__link {
	transition: background-color var(--wp--custom--transition--base),
		color var(--wp--custom--transition--base),
		transform var(--wp--custom--transition--base);
}

.wp-element-button:hover,
.wp-block-button__link:hover {
	transform: translateY(-1px);
}

/* Secondary button: outlined, for lower-priority actions. */
.wp-block-button.is-style-outline > .wp-block-button__link {
	background: transparent;
	color: var(--wp--preset--color--action);
	border: 1.5px solid var(--wp--preset--color--action);
}

.wp-block-button.is-style-outline > .wp-block-button__link:hover {
	background: var(--wp--preset--color--action);
	color: var(--wp--preset--color--base);
}

/* -------------------------------------------------------------------------
   4. Header
   ---------------------------------------------------------------------- */

/* header.js adds this to <html> for the length of one measurement, so it can
   read the header's expanded height instead of whatever height the transition
   happened to be part-way through. Removed in the same frame. */
.sb-measuring *,
.sb-measuring *::before,
.sb-measuring *::after {
	transition: none !important;
	animation: none !important;
}

/* Stickiness has to live on the template-part wrapper, not on .sb-header.
   WordPress renders the header part inside a <div class="wp-block-template-part">
   that is exactly as tall as the header, and a sticky element cannot travel
   beyond its containing block — so sticking it to .sb-header gives it zero
   travel and it scrolls away immediately. */
.wp-site-blocks > .wp-block-template-part:has(.sb-header),
.wp-site-blocks > .wp-block-template-part:first-child {
	position: sticky;
	/* The admin bar is position:fixed at the top of the viewport for logged-in
	   users, so a header stuck to 0 slides underneath it. WordPress exposes the
	   bar's height as a custom property (32px, or 46px under 782px), which also
	   keeps this correct when the bar is absent. */
	top: var(--wp-admin--admin-bar--height, 0px);
	z-index: 100;
}

/* Fallback for WordPress versions that do not set the custom property. */
body.admin-bar .wp-site-blocks > .wp-block-template-part:has(.sb-header),
body.admin-bar .wp-site-blocks > .wp-block-template-part:first-child {
	top: var(--wp-admin--admin-bar--height, 32px);
}

@media screen and (max-width: 782px) {
	body.admin-bar .wp-site-blocks > .wp-block-template-part:has(.sb-header),
	body.admin-bar .wp-site-blocks > .wp-block-template-part:first-child {
		top: var(--wp-admin--admin-bar--height, 46px);
	}
}

/* Below 600px the admin bar stops being fixed and scrolls away with the page,
   so the header must sit flush again or it leaves a 46px gap. */
@media screen and (max-width: 600px) {
	body.admin-bar .wp-site-blocks > .wp-block-template-part:has(.sb-header),
	body.admin-bar .wp-site-blocks > .wp-block-template-part:first-child {
		top: 0;
	}
}

/* The frosted background lives on a pseudo-element, not on .sb-header itself.
   backdrop-filter makes an element the containing block for its
   position:fixed descendants, which collapsed the mobile menu overlay to the
   height of the header instead of the viewport. Keeping the filter on a
   childless pseudo-element preserves the effect without that side effect. */
.sb-header {
	position: relative;
	background: transparent;
	border-bottom: var(--wp--custom--rule--hairline);
}

.sb-header::before {
	content: "";
	position: absolute;
	inset: 0;
	pointer-events: none;
	background: rgba(255, 255, 255, 0.92);
	backdrop-filter: saturate(180%) blur(12px);
	-webkit-backdrop-filter: saturate(180%) blur(12px);
}

.sb-header__bar {
	position: relative;
	z-index: 1;
}

/* The bar carries the vertical rhythm, and shrinks in the compact state.
   Padding is on the bar rather than the header so the sticky background
   still spans the full viewport width. */
.sb-header__bar {
	padding-block: clamp(0.85rem, 1.6vw, 1.35rem);
	transition: padding-block var(--wp--custom--transition--base);
}

.sb-header .custom-logo-link,
.sb-header .wp-block-site-logo a {
	display: block;
	line-height: 0;
}

.sb-header .wp-block-site-logo img {
	/* The mark is fine line art and the "PUBLISHING" lettering is light, so
	   the logo needs a little more room than a typical wordmark to stay
	   legible at small sizes. */
	width: clamp(156px, 17vw, 198px);
	height: auto;
	transition: opacity var(--wp--custom--transition--base);
}

.sb-header .wp-block-site-logo a:hover img {
	opacity: 0.78;
}

/* -----------------------------------------------------------------
   Compact (scrolled) header.

   The `is-compact` class is toggled by assets/js/header.js past a
   scroll threshold. Only the circular fairy mark shows, and the bar
   loses height, so more of the page stays visible while scrolling.
   ----------------------------------------------------------------- */

.sb-brand__mark {
	display: none;
	margin: 0;
	line-height: 0;
}

.sb-brand__mark img {
	display: block;
	width: 46px;
	height: auto;
	transition: opacity var(--wp--custom--transition--base);
}

.sb-brand__mark a:hover img {
	opacity: 0.78;
}

.sb-header.is-compact .sb-header__bar {
	padding-block: 0.5rem;
}

.sb-header.is-compact .wp-block-site-logo {
	display: none;
}

.sb-header.is-compact .sb-brand__mark {
	display: block;
}

/* Without JS the header simply stays in its full state — the mark is the
   progressive enhancement, not the baseline. */

/* Nav links: an animated rule that grows from the left on hover, and
   stays put for the current page. */
.sb-header .wp-block-navigation-item__content {
	position: relative;
	padding-block: 0.35rem;
	color: var(--wp--preset--color--ink);
}

.sb-header .wp-block-navigation-item__content::after {
	content: "";
	position: absolute;
	left: 0;
	bottom: 0;
	width: 100%;
	height: 2px;
	background: var(--wp--preset--color--accent);
	transform: scaleX(0);
	transform-origin: left;
	transition: transform var(--wp--custom--transition--base);
}

.sb-header .wp-block-navigation-item:hover .wp-block-navigation-item__content::after,
.sb-header .wp-block-navigation-item.current-menu-item .wp-block-navigation-item__content::after,
.sb-header .wp-block-navigation-item.current-menu-ancestor .wp-block-navigation-item__content::after {
	transform: scaleX(1);
}

/* Submenu (the Books dropdown). */
.sb-header .wp-block-navigation__submenu-container {
	border: none;
	border-radius: 10px;
	padding: 0.4rem;
	min-width: 15rem;
	background: var(--wp--preset--color--base);
	box-shadow: var(--wp--preset--shadow--lifted);
}

.sb-header .wp-block-navigation__submenu-container .wp-block-navigation-item__content {
	padding: 0.6rem 0.85rem;
	border-radius: 6px;
	width: 100%;
	/* Core's 200px submenu min-width outranks ours; keep labels on one line. */
	white-space: nowrap;
}

.sb-header .wp-block-navigation__submenu-container .wp-block-navigation-item__content::after {
	display: none;
}

.sb-header .wp-block-navigation__submenu-container .wp-block-navigation-item__content:hover {
	background: var(--wp--preset--color--surface);
	color: var(--wp--preset--color--action);
}

/* Nav item styled as the primary button, for the estimate CTA. */
.sb-header .sb-nav-cta .wp-block-navigation-item__content {
	padding: 0.5rem 1.1rem;
	border-radius: 999px;
	background: var(--wp--preset--color--action);
	color: var(--wp--preset--color--base);
}

.sb-header .sb-nav-cta .wp-block-navigation-item__content::after {
	display: none;
}

.sb-header .sb-nav-cta .wp-block-navigation-item__content:hover {
	background: var(--wp--preset--color--ink);
	color: var(--wp--preset--color--base);
}

/* -----------------------------------------------------------------
   Mobile overlay menu

   Full-screen, translucent so the page stays faintly visible behind
   it, with a large close control. Woo/WP already render the open and
   close buttons; this is presentation only.
   ----------------------------------------------------------------- */

.wp-block-navigation__responsive-container.is-menu-open,
.wp-block-navigation__responsive-container.is-menu-open:not(.disable-default-overlay) {
	padding: clamp(1.25rem, 5vw, 2.5rem);
	/* Warm wash — enough to read against, still showing the page beneath.
	   !important because Woo/WP set `background-color: inherit` here at equal
	   specificity, which otherwise picks up the header's opaque white. */
	background-color: rgba(247, 244, 236, 0.9) !important;
	backdrop-filter: blur(16px) saturate(150%);
	-webkit-backdrop-filter: blur(16px) saturate(150%);
	align-items: stretch;
	justify-content: flex-start;
}

/* Give the list room below the close button and center it in the sheet. */
/* WordPress nests two wrappers between the overlay and the menu list
   (__responsive-close, then __responsive-dialog). Both must grow, or the
   content has no height to be centered within. */
.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__responsive-close,
.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__responsive-dialog {
	display: flex;
	flex-direction: column;
	flex: 1 1 auto;
	width: 100%;
	min-height: 0;
}

.wp-block-navigation__responsive-container.is-menu-open
	.wp-block-navigation__responsive-container-content {
	display: flex;
	flex: 1 1 auto;
	flex-direction: column;
	align-items: center;
	/* Center the list in the sheet rather than stacking it under the close
	   button with dead space below. */
	justify-content: center;
	padding-block: clamp(2rem, 8vh, 4rem);
	width: 100%;
	min-height: 0;
}

.wp-block-navigation__responsive-container.is-menu-open
	.wp-block-navigation__container {
	gap: 0;
	width: 100%;
	max-width: 22rem;
	text-align: center;
	/* WordPress gives the list flex-grow, which pins the items to the top of
	   the sheet. Auto block margins center it regardless of that. */
	flex: 0 0 auto;
	margin-block: auto;
}

.wp-block-navigation__responsive-container.is-menu-open
	.wp-block-navigation-item {
	width: 100%;
	justify-content: center;
	border-bottom: 1px solid color-mix(in srgb, var(--wp--preset--color--ink) 14%, transparent);
}

.wp-block-navigation__responsive-container.is-menu-open
	.wp-block-navigation-item:last-child {
	border-bottom: 0;
}

.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation-item__content {
	font-family: var(--wp--preset--font-family--heading);
	font-size: var(--wp--preset--font-size--x-large);
	font-weight: 500;
	color: var(--wp--preset--color--ink);
	/* Comfortable tap target. */
	padding-block: 0.85rem;
	width: 100%;
	justify-content: center;
}

/* The desktop hover rule draws an underline bar; not wanted in the sheet. */
.wp-block-navigation__responsive-container.is-menu-open
	.wp-block-navigation-item__content::after {
	display: none;
}

.wp-block-navigation__responsive-container.is-menu-open
	.wp-block-navigation-item__content:hover {
	color: var(--wp--preset--color--action);
}

/* Submenu (Books) sits indented and quieter, always expanded in the sheet. */
.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__submenu-container {
	box-shadow: none;
	background: transparent;
	border: 0;
	padding: 0 0 0.5rem;
	min-width: 0;
}

.wp-block-navigation__responsive-container.is-menu-open
	.wp-block-navigation__submenu-container
	.wp-block-navigation-item {
	border-bottom: 0;
}

.wp-block-navigation__responsive-container.is-menu-open
	.wp-block-navigation__submenu-container
	.wp-block-navigation-item__content {
	font-family: var(--wp--preset--font-family--body);
	font-size: var(--wp--preset--font-size--medium);
	font-weight: 400;
	color: var(--wp--preset--color--muted);
	padding-block: 0.6rem;
}

/* Open (hamburger) control. */
.wp-block-navigation__responsive-container-open {
	padding: 0.4rem;
	color: var(--wp--preset--color--ink);
}

.wp-block-navigation__responsive-container-open:hover {
	color: var(--wp--preset--color--action);
}

/* Close (X) control — enlarged and given a visible hit area, since the
   default is a small bare glyph in the corner. */
.wp-block-navigation__responsive-container-close {
	top: clamp(1.25rem, 5vw, 2.5rem);
	right: clamp(1.25rem, 5vw, 2.5rem);
	display: flex;
	align-items: center;
	justify-content: center;
	width: 46px;
	height: 46px;
	border-radius: 999px;
	background: rgba(255, 255, 255, 0.9);
	color: var(--wp--preset--color--ink);
	box-shadow: var(--wp--preset--shadow--soft);
	transition: background-color var(--wp--custom--transition--base),
		color var(--wp--custom--transition--base);
}

.wp-block-navigation__responsive-container-close:hover {
	background: var(--wp--preset--color--action);
	color: var(--wp--preset--color--base);
}

.wp-block-navigation__responsive-container-close svg {
	width: 26px;
	height: 26px;
}

/* The overlay is fixed to the viewport, so it must clear the admin bar. */
body.admin-bar .wp-block-navigation__responsive-container.is-menu-open {
	top: var(--wp-admin--admin-bar--height, 46px);
}

/* -------------------------------------------------------------------------
   5. Cart indicator in the header
   ---------------------------------------------------------------------- */

.sb-cart {
	position: relative;
	display: inline-flex;
	align-items: center;
	gap: 0.4rem;
	padding: 0.5rem;
	border-radius: 999px;
	color: var(--wp--preset--color--ink);
	text-decoration: none;
	transition: background-color var(--wp--custom--transition--base);
}

.sb-cart:hover {
	background: var(--wp--preset--color--surface);
	color: var(--wp--preset--color--action);
}

.sb-cart svg {
	width: 22px;
	height: 22px;
	display: block;
}

.sb-cart__count {
	position: absolute;
	top: -1px;
	right: -3px;
	min-width: 18px;
	height: 18px;
	padding: 0 5px;
	border-radius: 999px;
	background: var(--wp--preset--color--action);
	color: var(--wp--preset--color--base);
	font-family: var(--wp--preset--font-family--body);
	font-size: 11px;
	font-weight: 700;
	line-height: 18px;
	text-align: center;
}

.sb-cart__count:empty,
.sb-cart__count[data-count="0"] {
	display: none;
}

/* -------------------------------------------------------------------------
   6. Footer
   ---------------------------------------------------------------------- */

.sb-footer {
	background: var(--wp--preset--color--ink);
	color: rgba(255, 255, 255, 0.82);
}

/* The stacked lockup's fairy mark is hairline linework. At 200px those
   white strokes fall below a device pixel and alias into looking rough,
   which reads as pixelation even though the source is vector. Giving it
   more room is the actual fix. */
.sb-footer .wp-block-site-logo img,
.sb-footer__logo img {
	width: clamp(215px, 22vw, 275px);
	height: auto;
	/* Nudge the fine strokes away from sub-pixel rendering. */
	shape-rendering: geometricPrecision;
}

.sb-footer :where(h2, h3, h4, h5, h6) {
	color: var(--wp--preset--color--base);
}

.sb-footer a {
	color: rgba(255, 255, 255, 0.82);
	text-decoration: none;
}

.sb-footer a:hover {
	color: var(--wp--preset--color--accent);
	text-decoration: underline;
	text-underline-offset: 0.18em;
}

.sb-footer .wp-block-navigation {
	gap: 0.55rem;
}

.sb-footer__legal {
	border-top: 1px solid rgba(255, 255, 255, 0.14);
}

/* -------------------------------------------------------------------------
   7. Editorial pieces
   ---------------------------------------------------------------------- */

/* Eyebrow label above a section heading. */
.sb-eyebrow {
	font-family: var(--wp--preset--font-family--body);
	font-size: var(--wp--preset--font-size--x-small);
	font-weight: 700;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	color: var(--wp--preset--color--action);
}

/* When the eyebrow is a term list (e.g. the product category on a book page)
   its links must not pick up the content underline — at this size and letter
   spacing an underline reads as noise. */
.sb-eyebrow a {
	color: inherit;
	text-decoration: none;
}

.sb-eyebrow a:hover {
	text-decoration: underline;
	text-underline-offset: 0.25em;
}

/* A framed image with depth, for a product shot or cover. */
.sb-object img {
	border-radius: 3px 10px 10px 3px;
	box-shadow: var(--wp--preset--shadow--lifted);
}

/* -----------------------------------------------------------------
   Immersive hero — artwork behind the copy

   A whole-image dim would flatten the painting, so the scrim is
   left-weighted: dark enough for white type on the copy side, and
   clear on the right where the cover sits.
   ----------------------------------------------------------------- */

.sb-hero-immersive {
	position: relative;
	overflow: hidden;
}

.sb-hero-immersive::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: 1;
	pointer-events: none;
	background:
		linear-gradient(
			100deg,
			rgba(38, 30, 26, 0.88) 0%,
			rgba(38, 30, 26, 0.74) 36%,
			rgba(38, 30, 26, 0.34) 62%,
			rgba(38, 30, 26, 0.12) 100%
		);
}

/* On narrow screens the columns stack, so the copy sits over the middle of
   the image and needs an even wash instead of a side gradient. */
@media (max-width: 781px) {
	.sb-hero-immersive::before {
		background: linear-gradient(
			180deg,
			rgba(38, 30, 26, 0.72) 0%,
			rgba(38, 30, 26, 0.84) 55%,
			rgba(38, 30, 26, 0.72) 100%
		);
	}
}

.sb-hero-immersive .wp-block-cover__inner-container {
	position: relative;
	z-index: 2;
}

.sb-hero-immersive__eyebrow {
	font-family: var(--wp--preset--font-family--body);
	font-size: var(--wp--preset--font-size--x-small);
	font-weight: 700;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	/* Brand green reads well against the dark scrim; it is only unusable
	   on light grounds. */
	color: var(--wp--preset--color--accent);
}

.sb-hero-immersive__meta {
	font-family: var(--wp--preset--font-family--body);
	font-size: var(--wp--preset--font-size--x-small);
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: rgba(255, 255, 255, 0.72);
}

.sb-hero-immersive h1 em {
	font-style: italic;
}

/* Lift the cover off the artwork so it reads as a physical object rather
   than part of the painting. */
.sb-object--floating img {
	box-shadow: 0 4px 12px rgba(20, 28, 25, 0.3), 0 28px 64px rgba(20, 28, 25, 0.45);
}

/* Outline button on a dark ground. */
.sb-btn-on-dark .wp-block-button__link,
.wp-block-button.is-style-outline.sb-btn-on-dark > .wp-block-button__link {
	color: var(--wp--preset--color--base);
	border-color: rgba(255, 255, 255, 0.65);
	background: transparent;
}

.sb-btn-on-dark .wp-block-button__link:hover,
.wp-block-button.is-style-outline.sb-btn-on-dark > .wp-block-button__link:hover {
	background: var(--wp--preset--color--base);
	color: var(--wp--preset--color--action);
	border-color: var(--wp--preset--color--base);
}

/* A soft rounded frame for photography and artwork. */
.sb-media img {
	border-radius: 14px;
}

/* Emphasized pull quote, for a tagline or short testimonial. */
.sb-lede-quote {
	font-family: var(--wp--preset--font-family--heading);
	font-size: var(--wp--preset--font-size--large);
	font-weight: 500;
	font-style: italic;
	line-height: 1.55;
	color: var(--wp--preset--color--action);
	text-align: center;
}

/* Decorative divider: a hairline rule either side of a small glyph. */
.sb-divider {
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 0.75rem;
	color: var(--wp--preset--color--accent);
}

.sb-divider::before,
.sb-divider::after {
	content: "";
	height: 1px;
	flex: 1 1 auto;
	max-width: 7rem;
	background: currentColor;
}

/* Cards */
.sb-card {
	background: var(--wp--preset--color--base);
	border-radius: 16px;
	box-shadow: var(--wp--preset--shadow--soft);
	overflow: hidden;
	transition: box-shadow var(--wp--custom--transition--base),
		transform var(--wp--custom--transition--base);
}

.sb-card:hover {
	box-shadow: var(--wp--preset--shadow--lifted);
	transform: translateY(-3px);
}

/* -------------------------------------------------------------------------
   8. Blog
   ---------------------------------------------------------------------- */

/* The post grid is declared as a fixed 3-up in the templates, because
   combining columnCount with minimumColumnWidth made WordPress emit an
   unpredictable 2-up. Collapsing for narrower screens is done here. */
.wp-block-post-template.is-layout-grid {
	gap: var(--wp--preset--spacing--30);
}

@media (max-width: 1024px) {
	.wp-block-post-template.is-layout-grid {
		grid-template-columns: repeat(2, minmax(0, 1fr)) !important;
	}
}

@media (max-width: 660px) {
	.wp-block-post-template.is-layout-grid {
		grid-template-columns: minmax(0, 1fr) !important;
	}
}

/* The blog intro sits in a wide container so its rule spans the grid; its
   text should start at the same left edge as the first card, not be centered
   inside it. */
.sb-blog-intro > * {
	margin-inline: 0;
}

.sb-blog-intro p {
	max-width: 58ch;
}

/* Cards stretch to the row height so the "Keep reading" link lands on a
   consistent baseline instead of floating wherever the excerpt ends. */
.sb-post-card {
	display: flex;
	flex-direction: column;
	height: 100%;
}

.sb-post-card .wp-block-post-excerpt {
	display: flex;
	flex-direction: column;
	flex: 1 1 auto;
}

.sb-post-card .wp-block-post-excerpt__more-text {
	margin-top: auto;
	padding-top: 0.75rem;
}

.sb-post-card .wp-block-post-excerpt__more-text a {
	font-weight: 600;
	text-decoration: none;
	border-bottom: 1px solid color-mix(in srgb, var(--wp--preset--color--action) 38%, transparent);
}

.sb-post-card .wp-block-post-excerpt__more-text a:hover {
	border-bottom-color: currentColor;
}

.sb-post-card .wp-block-post-featured-image img {
	border-radius: 12px;
	aspect-ratio: 3 / 2;
	object-fit: cover;
	width: 100%;
}

.sb-post-card .wp-block-post-title {
	font-size: var(--wp--preset--font-size--large);
	line-height: 1.25;
}

.sb-post-card .wp-block-post-title a {
	text-decoration: none;
	color: var(--wp--preset--color--ink);
}

.sb-post-card .wp-block-post-title a:hover {
	color: var(--wp--preset--color--action);
}

.sb-meta {
	font-family: var(--wp--preset--font-family--body);
	font-size: var(--wp--preset--font-size--x-small);
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var(--wp--preset--color--muted);
}

.wp-block-query-pagination {
	font-size: var(--wp--preset--font-size--small);
	font-weight: 600;
}

/* -------------------------------------------------------------------------
   9. Forms — Gravity Forms and core inputs share one look
   ---------------------------------------------------------------------- */

input:where([type="text"], [type="email"], [type="url"], [type="tel"], [type="number"], [type="password"], [type="search"], [type="date"]),
select,
textarea,
.wp-block-search__input {
	width: 100%;
	padding: 0.8rem 1rem;
	background: var(--wp--preset--color--base);
	border: 1.5px solid var(--sb-field-border);
	border-radius: 8px;
	font-family: var(--wp--preset--font-family--body);
	font-size: var(--wp--preset--font-size--medium);
	color: var(--wp--preset--color--ink);
	transition: border-color var(--wp--custom--transition--base),
		box-shadow var(--wp--custom--transition--base);
}

input:where([type="text"], [type="email"], [type="url"], [type="tel"], [type="number"], [type="password"], [type="search"]):focus,
select:focus,
textarea:focus {
	border-color: var(--wp--preset--color--action);
	box-shadow: 0 0 0 3px color-mix(in srgb, var(--wp--preset--color--action) 16%, transparent);
	outline: none;
}

::placeholder {
	color: color-mix(in srgb, var(--wp--preset--color--ink) 55%, transparent);
	opacity: 1;
}

label {
	display: block;
	margin-bottom: 0.4rem;
	font-family: var(--wp--preset--font-family--body);
	font-size: var(--wp--preset--font-size--small);
	font-weight: 600;
	color: var(--wp--preset--color--ink);
}

/* -----------------------------------------------------------------
   Gravity Forms

   Selectors are doubled up on `.gform_wrapper.gravity-theme` where
   Gravity's own stylesheet would otherwise win on specificity.
   ----------------------------------------------------------------- */

.gform_wrapper.gravity-theme .gform_fields {
	grid-row-gap: var(--wp--preset--spacing--20);
	grid-column-gap: var(--wp--preset--spacing--20);
}

/* `.gform_fields` is load-bearing. Gravity ships
   `.gform_wrapper.gravity-theme .gfield_label` verbatim and its stylesheet is
   printed after the theme's, so an identical selector loses on source order
   and silently does nothing. */
.gform_wrapper.gravity-theme .gform_fields .gfield_label,
.gform_wrapper.gravity-theme .gform_fields legend.gfield_label,
.gform_wrapper.gravity-theme .gform_fields .gform-field-label {
	display: block;
	margin-bottom: 0.4rem;
	font-family: var(--wp--preset--font-family--body);
	font-size: var(--wp--preset--font-size--small);
	font-weight: 600;
	color: var(--wp--preset--color--ink);
	letter-spacing: 0;
}

.gform_wrapper.gravity-theme .gfield_label .gfield_required,
.gform_wrapper.gravity-theme .gfield_label .gfield_required_text,
.gform_wrapper.gravity-theme .gfield_label .gfield_required_asterisk {
	color: #a4341f;
	font-weight: 600;
}

.gform_wrapper.gravity-theme .gform_fields .gfield_description {
	padding-top: 0.35rem;
	font-family: var(--wp--preset--font-family--body);
	font-size: var(--wp--preset--font-size--x-small);
	color: var(--wp--preset--color--muted);
	line-height: 1.5;
}

/* Inputs: match the site's field styling, overriding Gravity's. */
.gform_wrapper.gravity-theme .ginput_container input[type="text"],
.gform_wrapper.gravity-theme .ginput_container input[type="email"],
.gform_wrapper.gravity-theme .ginput_container input[type="tel"],
.gform_wrapper.gravity-theme .ginput_container input[type="url"],
.gform_wrapper.gravity-theme .ginput_container input[type="number"],
.gform_wrapper.gravity-theme .ginput_container select,
.gform_wrapper.gravity-theme .ginput_container textarea {
	width: 100%;
	padding: 0.8rem 1rem;
	background: var(--wp--preset--color--base);
	border: 1.5px solid var(--sb-field-border);
	border-radius: 8px;
	font-family: var(--wp--preset--font-family--body);
	font-size: var(--wp--preset--font-size--medium);
	color: var(--wp--preset--color--ink);
	line-height: 1.5;
	transition: border-color var(--wp--custom--transition--base),
		box-shadow var(--wp--custom--transition--base);
}

.gform_wrapper.gravity-theme .ginput_container textarea {
	min-height: 9rem;
	resize: vertical;
}

.gform_wrapper.gravity-theme .ginput_container input:focus,
.gform_wrapper.gravity-theme .ginput_container select:focus,
.gform_wrapper.gravity-theme .ginput_container textarea:focus {
	border-color: var(--wp--preset--color--action);
	box-shadow: 0 0 0 3px color-mix(in srgb, var(--wp--preset--color--action) 16%, transparent);
	outline: none;
}

/* Native select needs its own chevron once the default look is replaced. */
.gform_wrapper.gravity-theme .ginput_container select {
	appearance: none;
	-webkit-appearance: none;
	background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%234A4E52' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");
	background-repeat: no-repeat;
	background-position: right 0.9rem center;
	background-size: 18px 18px;
	padding-right: 2.6rem;
}

/* Submit and page buttons — the brand pill.
   Gravity Forms renders these as <button> in current versions and <input> in
   older ones, so both are matched (see GOTCHAS). */
.gform_wrapper.gravity-theme .gform_footer :is(input, button)[type="submit"],
.gform_wrapper.gravity-theme .gform_page_footer :is(input, button):is(.gform_next_button, .gform_button, .gform_previous_button) {
	width: auto;
	background: var(--wp--preset--color--action);
	color: var(--wp--preset--color--base);
	border: 0;
	border-radius: 999px;
	padding: 0.95rem 2.1rem;
	margin: 0;
	font-family: var(--wp--preset--font-family--body);
	font-size: var(--wp--preset--font-size--small);
	font-weight: 600;
	letter-spacing: 0.03em;
	line-height: 1.2;
	text-transform: none;
	cursor: pointer;
	transition: background-color var(--wp--custom--transition--base),
		transform var(--wp--custom--transition--base);
}

.gform_wrapper.gravity-theme .gform_footer :is(input, button)[type="submit"]:hover,
.gform_wrapper.gravity-theme .gform_page_footer :is(input, button):is(.gform_next_button, .gform_button, .gform_previous_button):hover:not(:disabled) {
	background: var(--wp--preset--color--ink);
	transform: translateY(-1px);
}

.gform_wrapper.gravity-theme .gform_footer {
	padding: var(--wp--preset--spacing--20) 0 0;
	margin: 0;
	justify-content: flex-start;
}

/* Validation */
.gform_wrapper.gravity-theme .gfield_description.validation_message,
.gform_wrapper.gravity-theme .validation_message {
	margin-top: 0.4rem;
	padding: 0.5rem 0.75rem;
	background: #fdf3f1;
	border: 0;
	border-left: 3px solid #a4341f;
	border-radius: 6px;
	font-size: var(--wp--preset--font-size--x-small);
	color: #8f2d1b;
}

/* These restate the base field selector's shape with `.gfield_error` added.
   Written as `.gfield_error input` alone they are LESS specific than the base
   rule, which carries an [type="..."] attribute selector, so an invalid field
   keeps its normal border and never looks wrong. */
.gform_wrapper.gravity-theme .gfield_error .ginput_container input[type="text"],
.gform_wrapper.gravity-theme .gfield_error .ginput_container input[type="email"],
.gform_wrapper.gravity-theme .gfield_error .ginput_container input[type="tel"],
.gform_wrapper.gravity-theme .gfield_error .ginput_container input[type="url"],
.gform_wrapper.gravity-theme .gfield_error .ginput_container input[type="number"],
.gform_wrapper.gravity-theme .gfield_error .ginput_container select,
.gform_wrapper.gravity-theme .gfield_error .ginput_container textarea,
.gform_wrapper.gravity-theme .gfield_error .gchoice {
	border-color: #a4341f;
	box-shadow: 0 0 0 3px rgba(164, 52, 31, 0.1);
}

.gform_wrapper.gravity-theme .gform_validation_errors {
	border-radius: 10px;
	border: 0;
	border-left: 3px solid #a4341f;
	background: #fdf3f1;
	box-shadow: none;
	padding: 1rem 1.25rem;
}

.gform_wrapper.gravity-theme .gform_validation_errors > h2 {
	font-family: var(--wp--preset--font-family--body);
	font-size: var(--wp--preset--font-size--small);
	font-weight: 600;
	color: #8f2d1b;
	margin: 0;
}

.gform_wrapper.gravity-theme .gform_validation_errors > h2::before {
	display: none;
}

/* Inline confirmation, for any form not routed to a Thank You page. */
.gform_confirmation_message {
	padding: var(--wp--preset--spacing--30);
	background: var(--wp--preset--color--surface);
	border-left: 3px solid var(--wp--preset--color--action);
	border-radius: 10px;
	font-size: var(--wp--preset--font-size--large);
	font-family: var(--wp--preset--font-family--heading);
}

/* -------------------------------------------------------------------------
   9b. Photo and video covers (inc/media-blocks.php)

   Full-bleed media with text set directly on it. The scrim is a gradient
   from ink, darkest behind the text, so the photo stays bright elsewhere and
   white text still clears 4.5:1 over any part of the image it covers.
   ---------------------------------------------------------------------- */

.sb-cover {
	color: var(--wp--preset--color--base);
}

.sb-cover .wp-block-cover__inner-container {
	padding-top: var(--wp--preset--spacing--50);
	padding-bottom: var(--wp--preset--spacing--50);
	padding-left: var(--wp--style--root--padding-left);
	padding-right: var(--wp--style--root--padding-right);
}

/* Stops are measured, not eyeballed: white text needs at least 72% ink
   behind it to clear 4.5:1 even over a pure white patch of photo. Every stop
   that sits behind text is 75% or more. */
.sb-cover.sb-scrim > .wp-block-cover__background {
	opacity: 1 !important;
	background: linear-gradient(
		to top,
		color-mix(in srgb, var(--wp--preset--color--ink) 88%, transparent) 0%,
		color-mix(in srgb, var(--wp--preset--color--ink) 75%, transparent) 50%,
		color-mix(in srgb, var(--wp--preset--color--ink) 15%, transparent) 100%
	) !important;
}

/* Hero, page hero and CTA: text column sits in the left 58%. */
.sb-cover--hero.sb-scrim > .wp-block-cover__background,
.sb-cover--page.sb-scrim > .wp-block-cover__background,
.sb-cover--cta.sb-scrim > .wp-block-cover__background {
	background: linear-gradient(
		to right,
		color-mix(in srgb, var(--wp--preset--color--ink) 85%, transparent) 0%,
		color-mix(in srgb, var(--wp--preset--color--ink) 75%, transparent) 58%,
		color-mix(in srgb, var(--wp--preset--color--ink) 20%, transparent) 100%
	) !important;
}

/* Phones: text runs the full width, so the scrim does too. */
@media (max-width: 781px) {
	.sb-cover--hero.sb-scrim > .wp-block-cover__background,
	.sb-cover--page.sb-scrim > .wp-block-cover__background,
	.sb-cover--cta.sb-scrim > .wp-block-cover__background {
		background: linear-gradient(
			to top,
			color-mix(in srgb, var(--wp--preset--color--ink) 85%, transparent) 0%,
			color-mix(in srgb, var(--wp--preset--color--ink) 75%, transparent) 100%
		) !important;
	}
}

.sb-cover :where(h1, h2, h3, p, .sb-eyebrow) {
	color: var(--wp--preset--color--base);
}

.sb-cover .sb-eyebrow {
	color: var(--wp--preset--color--tint);
}

.sb-cover__lead {
	font-size: var(--wp--preset--font-size--large);
	line-height: 1.55;
}

.sb-cover .wp-block-buttons {
	margin-top: var(--wp--preset--spacing--30);
}

.sb-cover :where(a, button):focus-visible {
	outline-color: var(--wp--preset--color--base);
}

/* Reduced motion: hide the video and show its poster frame instead. */
.sb-cover {
	background: var(--sb-poster, none) center / cover no-repeat;
}

@media (prefers-reduced-motion: reduce) {
	.sb-cover .wp-block-cover__video-background {
		display: none;
	}
}

/* Band: the photo carries the section, a solid panel carries the words. */
.sb-band {
	display: flex;
	width: 100%;
}

.sb-band--right {
	justify-content: flex-end;
}

.sb-panel {
	padding: var(--wp--preset--spacing--40);
	border-radius: 16px;
	box-shadow: var(--wp--preset--shadow--lifted);
	color: var(--wp--preset--color--ink);
}

.sb-panel :where(h2, h3, p) {
	color: var(--wp--preset--color--ink);
}

.sb-panel .sb-eyebrow {
	color: var(--wp--preset--color--action);
}

.sb-panel :where(a, button):focus-visible {
	outline-color: var(--wp--preset--color--action);
}

/* Tiles: the whole photo is the link, the label sits on the image. */
.sb-tile {
	border-radius: 16px;
	overflow: hidden;
	height: 100%;
}

.sb-tile .wp-block-cover__inner-container {
	padding: var(--wp--preset--spacing--30);
}

.sb-tile__title a {
	color: inherit;
	text-decoration: none;
}

.sb-tile__title a::after {
	content: "";
	position: absolute;
	inset: 0;
	z-index: 1;
}

.sb-tile__title a::before {
	content: "\2192";
	display: inline-block;
	margin-right: 0.5rem;
	transition: transform var(--wp--custom--transition--base);
}

.sb-tile:hover .wp-block-cover__image-background {
	transform: scale(1.04);
}

.sb-tile .wp-block-cover__image-background {
	transition: transform 0.6s ease;
}

.sb-tile:hover .sb-tile__title a::before {
	transform: translateX(4px);
}

@media (max-width: 781px) {
	.sb-cover--hero {
		min-height: 78vh !important;
	}

	.sb-cover--band {
		min-height: 0 !important;
		padding-top: 40vh;
	}

	.sb-band--right {
		justify-content: flex-start;
	}
}

/* Partner logos: single-color marks, muted until hovered. */
/* A grid, not flex-wrap, so six logos land 2x3, 3x2 or 6x1 and never strand one on a line. */
.sb-logo-row.sb-logo-row {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	justify-items: center;
	align-items: center;
	gap: var(--wp--preset--spacing--30) var(--wp--preset--spacing--20);
}
@media (min-width: 600px) {
	.sb-logo-row.sb-logo-row {
		grid-template-columns: repeat(3, minmax(0, 1fr));
	}
}
@media (min-width: 1200px) {
	.sb-logo-row.sb-logo-row {
		grid-template-columns: repeat(6, minmax(0, 1fr));
	}
}
.sb-logo-row .wp-block-image {
	margin: 0;
	max-width: 100%;
}
.sb-logo-row img {
	opacity: 0.7;
	transition: opacity 0.2s ease;
}
.sb-logo-row img:hover {
	opacity: 1;
}

/* -------------------------------------------------------------------------
   10. Utilities
   ---------------------------------------------------------------------- */

/* Let a wide/full block bleed to the viewport edge on small screens. */
@media (max-width: 600px) {
	.sb-bleed-mobile {
		margin-left: calc(var(--wp--preset--spacing--20) * -1);
		margin-right: calc(var(--wp--preset--spacing--20) * -1);
		border-radius: 0;
	}
}

/* Overlay text needs a scrim to stay readable over artwork. */
.sb-scrim::before {
	content: "";
	position: absolute;
	inset: 0;
	background: linear-gradient(
		180deg,
		rgba(74, 78, 82, 0.55) 0%,
		rgba(74, 78, 82, 0.2) 45%,
		rgba(74, 78, 82, 0.5) 100%
	);
	pointer-events: none;
}

.sb-scrim > * {
	position: relative;
	z-index: 1;
}

/* A monochrome logo can serve both the light header and the dark footer by
   being inverted, rather than needing a separate reversed asset. Only sound for
   single-color marks — a full-color logo must have its own reversed file. */
.sb-footer__logo--invert img {
	filter: invert(1) brightness(1.9);
}

/* -------------------------------------------------------------------------
   11. Motion

   Paired with assets/js/reveal.js. The `sb-js` flag is set by an inline
   script in the head, BEFORE paint, so without JavaScript everything stays
   visible rather than being hidden behind an animation that never runs.
   ---------------------------------------------------------------------- */

.sb-reveal {
	opacity: 0;
	transform: translateY(14px);
	transition: opacity 640ms cubic-bezier(0.16, 1, 0.3, 1),
		transform 640ms cubic-bezier(0.16, 1, 0.3, 1);
}

.sb-reveal.is-visible {
	opacity: 1;
	transform: none;
}

/* Without JavaScript nothing is ever revealed, so the content must start
   visible and the animation must be the enhancement. */
html:not(.sb-js) .sb-reveal {
	opacity: 1;
	transform: none;
	transition: none;
}

@media (prefers-reduced-motion: reduce) {
	.sb-reveal {
		opacity: 1;
		transform: none;
		transition: none;
	}
}

/* -----------------------------------------------------------------
   Gravity radios, checkboxes and the datepicker

   Gravity renders the choice input as a SIBLING of its label, not
   inside it, so the card has to be the row. Styling the label instead
   leaves the native control floating outside the bordered box.
   ----------------------------------------------------------------- */

.gform_wrapper.gravity-theme .gfield_radio,
.gform_wrapper.gravity-theme .gfield_checkbox {
	display: flex;
	flex-direction: column;
	gap: 0.5rem;
	margin: 0;
	padding: 0;
	list-style: none;
}

.gform_wrapper.gravity-theme .gchoice {
	display: flex;
	align-items: flex-start;
	gap: 0.75rem;
	margin: 0;
	padding: 0 0.9rem;
	background: var(--wp--preset--color--surface);
	border: 1.5px solid var(--sb-field-border);
	border-radius: 10px;
	transition: background-color var(--wp--custom--transition--base),
		border-color var(--wp--custom--transition--base);
}

.gform_wrapper.gravity-theme .gchoice:hover,
.gform_wrapper.gravity-theme .gchoice:has(input:checked) {
	background: var(--wp--preset--color--tint);
	border-color: var(--wp--preset--color--action);
}

.gform_wrapper.gravity-theme .gchoice:has(input:focus-visible) {
	outline: 3px solid var(--wp--preset--color--action);
	outline-offset: 2px;
}

.gform_wrapper.gravity-theme .gchoice input[type="radio"],
.gform_wrapper.gravity-theme .gchoice input[type="checkbox"] {
	flex: none;
	width: 20px;
	height: 20px;
	margin: 0.85rem 0 0;
	accent-color: var(--wp--preset--color--action);
	cursor: pointer;
}

/* The label carries the vertical padding so the whole row height is a tap
   target, not just the text. `.gform_fields` for specificity: Gravity sets 600
   here, which otherwise renders UNCHECKED options bolder than the chosen one. */
.gform_wrapper.gravity-theme .gform_fields .gchoice label {
	flex: 1 1 auto;
	display: flex;
	align-items: center;
	min-height: 44px;
	margin: 0;
	padding: 0.7rem 0;
	background: none;
	border: 0;
	font-family: var(--wp--preset--font-family--body);
	font-size: var(--wp--preset--font-size--small);
	font-weight: 400;
	line-height: 1.45;
	color: var(--wp--preset--color--ink);
	cursor: pointer;
}

.gform_wrapper.gravity-theme .gform_fields .gchoice:has(input:checked) label {
	font-weight: 600;
}

/* Gravity Forms 3.0 ships its OWN datepicker, not jQuery UI, so
   `#ui-datepicker-div` selectors match nothing. */
.gform-datepicker-calendar {
	border-radius: 12px;
	box-shadow: var(--wp--preset--shadow--lifted);
	font-family: var(--wp--preset--font-family--body);
}

.gform-datepicker-calendar td.day {
	border-radius: 999px;
	color: var(--wp--preset--color--ink);
}

.gform-datepicker-calendar td.day:hover {
	background: var(--wp--preset--color--tint);
	color: var(--wp--preset--color--action);
}

.gform-datepicker-calendar td.day.selected,
.gform-datepicker-calendar td.day[aria-selected="true"] {
	background: var(--wp--preset--color--action);
	color: var(--wp--preset--color--base);
	box-shadow: none;
}

.gform-datepicker-calendar td.day.dayToday {
	color: var(--wp--preset--color--action);
	font-weight: 600;
}

/* The honeypot is the whole anti-spam mechanism; it must stay hidden. */
.gform_wrapper.gravity-theme .gform_validation_container,
.gform_wrapper.gravity-theme .gfield--type-honeypot {
	display: none !important;
}
