/*
 * CRATE — custom effects layered on top of theme.json.
 * Everything here resolves through theme.json tokens (no raw hex/px sizing
 * beyond the effect geometry itself).
 */

/* --- The .crate-fullbleed calc(50vw) trick below measures against `vw`,
   which includes the scrollbar gutter, while the actual document width
   (clientWidth) doesn't reserve that gutter on browsers with classic
   (non-overlay) scrollbars. That mismatch overflows the banner ~7-15px
   past the right edge, producing a real horizontal scrollbar — confirmed
   via a real 375px-viewport iframe test (mobile devices mostly use
   overlay scrollbars so this rarely shows there, but Windows/some Android
   Chrome builds don't). Standard pairing for any vw-based full-bleed
   trick.

   Scoped to `main`, NOT `html` (2026-08-05): `overflow-x: hidden` on `html`
   computes to `overflow: hidden auto` (any overflow value on one axis
   forces the other axis off "visible"), which makes `html` a scroll
   container — and on real mobile Chrome that demotes it from being the
   page's root scroller, which silently breaks `position: sticky` for the
   header (confirmed via a real Android Chrome recording: the sticky nav
   never engaged at all on scroll, though it worked fine in desktop
   testing). Every `.crate-fullbleed` element lives inside `<main>` in every
   template (header/footer never contain one), so clipping there instead
   contains the same overflow without html/body ever leaving
   `overflow: visible`. --- */
main {
	overflow-x: hidden;
}

/* --- Restore a visible keyboard-focus ring on links and buttons. theme.json
   already declares the intended style under styles.elements.link.:focus
   (2px solid sage-700, 3px offset), but a keyboard Tab test showed no ring
   at all on interactive elements — the parent Twenty Twenty-Five theme
   resets it somewhere upstream of where theme.json's generated rule can
   win. Restating it directly here, scoped to :focus-visible so it only
   shows for keyboard users, not every mouse click. --- */
a:focus-visible,
button:focus-visible,
.wp-element-button:focus-visible {
	outline: 2px solid var(--wp--preset--color--sage-700);
	outline-offset: 3px;
}

/* --- Lantern hover: a soft warm light that follows the cursor across a button --- */
.wp-element-button {
	position: relative;
	overflow: hidden;
}

.wp-element-button::after {
	content: "";
	position: absolute;
	inset: 0;
	pointer-events: none;
	opacity: 0;
	transition: opacity 0.3s ease;
	background: radial-gradient(
		circle 80px at var(--mx, 50%) var(--my, 50%),
		color-mix(in srgb, var(--wp--preset--color--paper) 60%, transparent),
		transparent 65%
	);
}

.wp-element-button:hover::after,
.wp-element-button:focus-visible::after {
	opacity: 1;
}

/* Respect users who prefer reduced motion: no travelling glow. */
@media (prefers-reduced-motion: reduce) {
	.wp-element-button::after {
		display: none;
	}
}

/* --- Case-study rows: give the alternating Media & Text rows room to breathe.
   Core's grid has no default column-gap ("normal" resolves to 0px), so image
   and text sit flush against each other unless we set one explicitly. --- */
.wp-block-media-text {
	margin-top: var(--wp--preset--spacing--xl);
	margin-bottom: var(--wp--preset--spacing--xl);
	column-gap: var(--wp--preset--spacing--xl);
}

.wp-block-media-text .wp-block-media-text__content {
	padding-top: var(--wp--preset--spacing--xs);
	/* Core's default media-text CSS puts ~8% horizontal padding on the
	   content side. Harmless when media is on the left, but when media
	   is on the right (text on the left) it shifts the text's actual
	   left edge ~22px right of every plain paragraph's left edge on the
	   same page — small enough to read as a rendering mistake rather
	   than an intentional gap. Zero it and let column-gap (set above)
	   carry all the spacing instead, so text always lines up with the
	   rest of the page's text column regardless of media position. */
	padding-left: 0;
	padding-right: 0;
}

/* --- Eyebrow label: small-caps section label, semantically H2 but styled like the h4 element style --- */
.eyebrow-label {
	font-family: var(--wp--preset--font-family--body);
	font-size: var(--wp--preset--font-size--small);
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.1em;
	line-height: 1.4;
	color: var(--wp--preset--color--ink-muted);
}

/* --- Sticky nav: stays pinned via CSS `position: sticky` from page load
   (JS only toggles the color swap below, see assets/sticky-nav.js), so it's
   always available on longer case-study pages without a jarring
   appear/disappear. Flips to a sage/white "you're navigating" state past a
   small scroll threshold, so the color pop reads as an active state change
   rather than a permanently green header competing with the sage CTA
   buttons elsewhere on the page. --- */
/* position:sticky has to live on the outer <header> landmark, not the inner
   .crate-site-header flex div — confirmed via direct testing that sticky
   silently fails to engage (computed style reports "sticky" correctly, but
   the element never pins on scroll) when applied to the inner div, and
   works immediately when moved one level up to the semantic <header>. */
header.wp-block-template-part {
	position: sticky;
	top: 0;
	z-index: 100;
}

.crate-site-header {
	background-color: var(--wp--preset--color--paper);
	transition: background-color 0.25s ease, box-shadow 0.25s ease, color 0.25s ease;
}

/* Logo mark (crate_logo_black.png, media id 3246): solid black on a
   transparent PNG, so the sage-scrolled state is one CSS filter rather than
   a second uploaded asset — brightness(0) first flattens any anti-aliased
   edge pixels to pure black before invert(1) flips it white, so edges stay
   clean instead of turning muddy gray. Same transition-on-base,
   override-in-.is-scrolled pattern as the nav link color just below. */
.crate-logo-link {
	display: inline-flex;
	align-items: center;
}

.crate-logo-mark {
	display: block;
	height: 40px;
	width: auto;
	transition: filter 0.25s ease;
}

.crate-site-header.is-scrolled .crate-logo-mark {
	filter: brightness(0) invert(1);
}

.crate-site-header.is-scrolled {
	background-color: var(--wp--preset--color--sage-500);
	color: var(--wp--preset--color--paper);
	box-shadow: 0 2px 12px rgba(20, 18, 15, 0.15);
}

.crate-site-header.is-scrolled .wp-block-site-title a,
.crate-site-header.is-scrolled .wp-block-navigation-item__content {
	color: var(--wp--preset--color--paper) !important;
}

.crate-site-header.is-scrolled .wp-block-navigation-item__content:hover {
	opacity: 0.8;
}

/* The mobile responsive dialog always renders on its own white/paper sheet,
   regardless of whether the top bar behind it is scrolled to sage — but it's
   still a DOM descendant of .crate-site-header, so the white-on-scroll link
   color above was leaking into it too, producing white text on a white
   overlay (confirmed via a real screen recording: legible header, invisible
   menu). Reset it back to ink specifically inside the dialog.

   Correction (2026-08-10): `.wp-block-navigation__responsive-dialog` is NOT
   mobile-only — core's Navigation block renders that wrapper in the DOM at
   every viewport width; only its visibility/positioning changes. The
   original selector below therefore matched the always-visible DESKTOP nav
   too, and because it has one more class than the paper-color rule above, it
   quietly won everywhere — leaving dark ink nav links on the sage-500
   scrolled header on desktop (confirmed live: bg sage-500, logo paper, nav
   links still rgb(38,36,31)). The actual "is this the open mobile overlay"
   signal is the `.is-menu-open` class core's nav view script adds to
   `.wp-block-navigation__responsive-container` only while the popup is open
   (confirmed by dispatching a click on the open button and inspecting the
   resulting classList: "has-modal-open is-menu-open"). Scope to that instead
   so this rule only fires for the real mobile popup, never the desktop bar. */
.crate-site-header.is-scrolled .wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation-item__content {
	color: var(--wp--preset--color--ink) !important;
}

@media (prefers-reduced-motion: reduce) {
	.crate-site-header,
	.crate-logo-mark {
		transition: none;
	}
}

/* --- Mobile nav overlay: core's responsive menu content has zero horizontal
   padding, so the right-justified links sit flush against the screen edge
   (confirmed via a 390px iframe test) — add breathing room to match the
   spacing used everywhere else on the site. --- */
.wp-block-navigation__responsive-container-content {
	padding-left: var(--wp--preset--spacing--m);
	padding-right: var(--wp--preset--spacing--m);
}

/* The close (X) button is a sibling of the content above, not a child, so
   the padding on that rule doesn't reach it — core positions it with a
   flush `top: 0; right: 0`, leaving it sitting in the literal corner while
   the nav links below it are inset. Offset it to match, so it lines up
   with the links' right edge instead of hanging out past them. */
.wp-block-navigation__responsive-container-close {
	top: var(--wp--preset--spacing--m) !important;
	right: var(--wp--preset--spacing--m) !important;
}

/* --- Jetpack sharing buttons: icon only. The default "icon + text" style
   doubles up visually on X, whose icon glyph is already the letter X. --- */
.sd-content a.share-icon span:not([hidden]) {
	display: none;
}

/* --- Ninja Forms ships a bundled dark-theme stylesheet by default (input
   background ~rgb(40,40,40), text ~rgb(155,155,155)) that has nothing to
   do with this site's palette — found on the Contact page, low-contrast
   near-black fields on the paper background. The plugin's own light/dark
   toggle is a paid "Layouts & Styles" add-on we don't have, so overriding
   here instead, matching the rest of the site's tokens. --- */
.nf-form-content .list-select-wrap .nf-field-element > div,
.nf-form-content input:not([type="button"]):not([type="submit"]),
.nf-form-content textarea {
	background-color: var(--wp--preset--color--paper) !important;
	color: var(--wp--preset--color--ink) !important;
	border: 1px solid var(--wp--preset--color--rule) !important;
}

.nf-form-content input:not([type="button"]):not([type="submit"]):focus,
.nf-form-content textarea:focus {
	border-color: var(--wp--preset--color--sage-500) !important;
	outline: none !important;
}

/* Same Ninja Forms default palette, this time on the submit button
   (flat rgb(196,196,196) gray) — matching the sage button style used
   everywhere else on the site instead. */
.nf-form-content input[type="submit"] {
	background-color: var(--wp--preset--color--sage-500) !important;
	color: var(--wp--preset--color--paper) !important;
	border: none !important;
	border-radius: 2px !important;
}

.nf-form-content input[type="submit"]:hover {
	background-color: var(--wp--preset--color--sage-700) !important;
}

/* --- Testimonial carousel: one quote at a time, prev/next click-through --- */
.crate-testimonials {
	text-align: center;
}

.crate-testimonial-inner {
	max-width: var(--wp--style--global--content-size, 42rem);
	margin-left: auto;
	margin-right: auto;
}

.crate-testimonial-carousel {
	margin-top: var(--wp--preset--spacing--l);
}

.crate-testimonial {
	display: none;
	margin: 0;
	font-family: var(--wp--preset--font-family--display);
	font-size: var(--wp--preset--font-size--lead);
	line-height: 1.4;
	color: var(--wp--preset--color--ink-deep);
	text-align: left;
}

.crate-testimonial.is-active {
	display: block;
}

.crate-testimonial p {
	margin: 0 0 var(--wp--preset--spacing--s);
}

.crate-testimonial cite {
	display: block;
	font-family: var(--wp--preset--font-family--body);
	font-size: var(--wp--preset--font-size--small);
	font-style: normal;
	color: var(--wp--preset--color--ink);
}

.crate-testimonial-nav {
	display: flex;
	align-items: center;
	justify-content: center;
	gap: var(--wp--preset--spacing--m);
	margin-top: var(--wp--preset--spacing--l);
}

.crate-testimonial-prev,
.crate-testimonial-next {
	background: transparent;
	border: 1px solid var(--wp--preset--color--ink-deep);
	color: var(--wp--preset--color--ink-deep);
	width: 2.5rem;
	height: 2.5rem;
	border-radius: 50%;
	cursor: pointer;
	font-size: 1.1rem;
	line-height: 1;
	transition: background-color 0.2s ease, color 0.2s ease;
}

.crate-testimonial-prev:hover,
.crate-testimonial-next:hover,
.crate-testimonial-prev:focus-visible,
.crate-testimonial-next:focus-visible {
	background-color: var(--wp--preset--color--ink-deep);
	color: var(--wp--preset--color--paper);
}

.crate-testimonial-dots {
	display: flex;
	gap: var(--wp--preset--spacing--xs);
}

.crate-testimonial-dot {
	width: 0.5rem;
	height: 0.5rem;
	border-radius: 50%;
	background: var(--wp--preset--color--sage-500);
	opacity: 0.4;
	transition: opacity 0.2s ease, transform 0.2s ease, background-color 0.2s ease;
}

.crate-testimonial-dot.is-active {
	background: var(--wp--preset--color--ink-deep);
	opacity: 1;
	transform: scale(1.25);
}

/* --- Full-bleed color-blocked sections must sit flush against each other.
   WordPress applies a standard block-gap margin between siblings, which is
   invisible between pale sections but shows as a visible strip of the page's
   base background between the more saturated sage/black bands. Kill it here. --- */
main.wp-block-group > .crate-featured-work,
main.wp-block-group > .crate-testimonials,
main.wp-block-group > .crate-contact-cta {
	margin-top: 0 !important;
	margin-bottom: 0 !important;
	margin-block-start: 0 !important;
	margin-block-end: 0 !important;
}

/* A ~35px gap persists specifically between .crate-featured-work and
   .crate-testimonials even with all measured margins/padding at 0 on both
   sides (confirmed via computed styles and getBoundingClientRect) — the
   source wasn't identifiable in the cascade. Closing it directly. */
main.wp-block-group > .crate-testimonials {
	margin-top: -36px !important;
}


/* --- True full-bleed regardless of nesting depth. WordPress's native
   alignfull relies on a per-instance CSS rule generated against the
   nearest constrained-layout ancestor's content-size custom property.
   That works for template-level markup (front-page.html) but silently
   fails for blocks saved inside wp:post-content on the generic "Pages"
   template — the custom property isn't available at render time, so
   alignfull's calc() resolves to 0 and the block stays column-width.
   This class escapes any parent with the classic viewport-relative
   trick instead, independent of WP's layout-support system.

   Gotcha (found 2026-07-31): the old width:100vw + margin-left:50% +
   translateX(-50%) version measures its 50% shift against its own box,
   ignoring how far the containing block (here, the ~672px .entry-content
   column on the "Pages" template) sits from the viewport edge — it left
   the banner shifted left with a visible gap on the right on every
   case-study page. margin:calc(50% - 50vw) is self-correcting: it nets
   out the containing block's own offset as long as that block is itself
   centered in the viewport (true here), so it holds regardless of
   nesting depth or column width. Also added top/bottom padding — the
   old rule had none, so heading/buttons sat flush against the block's
   edges. All properties need !important: core generates a per-instance
   alignfull rule (a unique .wp-container-core-group-layout-* class) with
   higher specificity than a single custom class, which otherwise wins
   and resets margin back to 0 — confirmed by inspecting computed styles
   after a plain (non-!important) version silently lost the cascade. --- */
/* Scrollbar-width centering correction (2026-08-10): calc(50vw) includes the
   scrollbar gutter, but the visible page area (clientWidth) doesn't — on
   classic (non-overlay) scrollbars this left every .crate-fullbleed section
   shifted ~7.5px left of true center (confirmed by measuring a real page:
   15px scrollbar, exactly 7.5px = half-scrollbar drift). Doesn't show on
   overlay-scrollbar systems (Mac, most mobile), where the correction term is
   just 0px and the calc is a no-op. --crate-scrollbar-width is set by a tiny
   inline script in parts/header.html (must run on DOMContentLoaded, not
   synchronously — see that file's comment for why). */
.crate-fullbleed {
	width: auto !important;
	margin-left: calc(50% - 50vw + (var(--crate-scrollbar-width, 0px) / 2)) !important;
	margin-right: calc(50% - 50vw + (var(--crate-scrollbar-width, 0px) / 2)) !important;
	padding-top: var(--wp--preset--spacing--xl) !important;
	padding-bottom: var(--wp--preset--spacing--xl) !important;
	padding-left: var(--wp--preset--spacing--m) !important;
	padding-right: var(--wp--preset--spacing--m) !important;
	box-sizing: border-box;
}

/* --- Selected-work preview cards: real thumbnails so the homepage shows the work, not just describes it --- */
.crate-work-grid {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
	gap: var(--wp--preset--spacing--m);
	margin-top: var(--wp--preset--spacing--m);
	margin-bottom: var(--wp--preset--spacing--m);
}

.crate-work-card {
	display: block;
	text-decoration: none;
	color: inherit;
}

.crate-work-card img {
	display: block;
	width: 100%;
	/* Was 160px — too short a crop window for these particular photos: most
	   have a logo mark, wordmark, and a tagline all stacked vertically, so a
	   short landscape crop left almost no headroom/footroom around them
	   (confirmed 2026-08-05 via a real mobile screenshot showing the Nurture
	   card's mark and "MASSAGE" text sitting right at the crop edges).
	   200px reveals more of the actual photo above/below that content on
	   every card, not just Nurture. */
	height: 200px;
	object-fit: cover;
	border-radius: 2px;
	margin-bottom: var(--wp--preset--spacing--s) !important;
}

/* Cint booth photo: the tagline ("...you crave them most") is on the
   counter front panel, about 70-80% down the source photo. A center
   crop (and an earlier top-anchored attempt) both missed it. Anchor
   low enough to keep the full tagline in frame; this trades away the
   ceiling/neon sign, which matters less than the readable line. */
.crate-work-card-img-top {
	object-position: 50% 70%;
}

.crate-work-card h3 {
	font-family: var(--wp--preset--font-family--display);
	font-size: var(--wp--preset--font-size--body);
	font-weight: 700;
	line-height: 1.25;
	margin: 0 0 var(--wp--preset--spacing--3xs);
	color: var(--wp--preset--color--ink-deep);
}

.crate-work-card p {
	font-size: var(--wp--preset--font-size--small);
	color: var(--wp--preset--color--ink);
	margin: 0;
}

.crate-work-card:hover h3,
.crate-work-card:focus-visible h3 {
	text-decoration: underline;
}
