/*
 * QOQO Productions — supplemental site CSS.
 *
 * theme.json already carries every token-level decision (colors, type
 * scale via clamp(), spacing scale, radii, button states). This file exists
 * ONLY for behavior theme.json cannot express: responsive section padding,
 * the sticky mobile CTA, focus-visible treatment, reduced-motion handling,
 * safe-area insets, the FAQ accordion chevron, and mobile nav overlay
 * styling. Per DL-107 (Sitewide Design System) and DL-129 (Prompt 10
 * closure) — do not introduce new colors, typography, or decorative
 * patterns here that aren't already approved.
 *
 * Breakpoints (DL-107 Section 11): mobile up to 767px, tablet 768-1023px,
 * desktop 1024px and up.
 */

/* ---------------------------------------------------------------------
   1. Section vertical padding (DL-107 Section 5)
   Mobile: --space-5 (48px) top/bottom. Desktop: --space-7 (96px).
   Page-content patterns (a later batch) apply the .qoqo-section class to
   their outermost wrapper to pick this up.
--------------------------------------------------------------------- */
:root {
	--qoqo-section-padding: var(--wp--preset--spacing--5);
}
@media (min-width: 1024px) {
	:root {
		--qoqo-section-padding: var(--wp--preset--spacing--7);
	}
}
.qoqo-section {
	padding-block: var(--qoqo-section-padding);
}

/* ---------------------------------------------------------------------
   2. Reduced motion (DL-107 Section 14) — REQUIRED sitewide, not optional,
   not left to individual page implementation. Applies to every transition
   declared anywhere on the site, present or future.
--------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
	*,
	*::before,
	*::after {
		animation-duration: 0.001ms !important;
		animation-iteration-count: 1 !important;
		transition-duration: 0.001ms !important;
		scroll-behavior: auto !important;
	}
}

/* Default (motion-safe) transition timing for interactive elements
   (DL-107 Section 14): 150-250ms, ease-out, no bounce/spring/elastic. */
a,
button,
.wp-block-button__link,
.qoqo-faq-item summary,
.qoqo-sticky-cta {
	transition: color 200ms ease-out, background-color 200ms ease-out,
		border-color 200ms ease-out, box-shadow 200ms ease-out,
		transform 200ms ease-out;
}

/* ---------------------------------------------------------------------
   3. Focus-visible treatment (DL-107 Sections 3, 4, 15) — 2px gold-hover
   outline, 3px offset, plus the gold glow as a secondary focus cue. Applies
   sitewide, not just to buttons, so no interactive element ever relies on
   browser-default (often invisible-on-black) focus styling.
--------------------------------------------------------------------- */
:focus-visible {
	outline: 2px solid var(--wp--preset--color--gold-hover);
	outline-offset: 3px;
	box-shadow: 0 0 0 6px var(--wp--custom--focus-glow);
	border-radius: 2px;
}

/* ---------------------------------------------------------------------
   4. FAQ accordion (DL-107 Section 6) — core/details block styling.
   Gold chevron via ::marker-adjacent pseudo-element, rotates on [open].
   Native <details>/<summary> is keyboard-operable with zero JS.
--------------------------------------------------------------------- */
.qoqo-faq-item {
	border: 1px solid var(--wp--preset--color--border);
	border-radius: 8px;
	padding: var(--wp--preset--spacing--3);
	margin-bottom: var(--wp--preset--spacing--2);
}
.qoqo-faq-item summary {
	list-style: none;
	cursor: pointer;
	font-family: var(--wp--preset--font-family--heading);
	font-weight: 700;
	display: flex;
	align-items: center;
	justify-content: space-between;
	min-height: 44px;
}
.qoqo-faq-item summary::-webkit-details-marker {
	display: none;
}
.qoqo-faq-item summary::after {
	content: "";
	width: 12px;
	height: 12px;
	margin-left: var(--wp--preset--spacing--2);
	flex-shrink: 0;
	border-right: 2px solid var(--wp--preset--color--gold);
	border-bottom: 2px solid var(--wp--preset--color--gold);
	transform: rotate(45deg);
	transition: transform 200ms ease-out;
}
.qoqo-faq-item[open] summary::after {
	transform: rotate(-135deg);
}

/* ---------------------------------------------------------------------
   5. Sticky mobile CTA (DL-107 Section 10) — mobile only. Toggled by
   assets/js/site.js once the visitor scrolls past the page's own hero CTA.
   All six owner-directed constraints from DL-107 are implemented below;
   see the inline comments against each one.
--------------------------------------------------------------------- */
.qoqo-sticky-cta {
	display: none;
	position: fixed;
	left: 0;
	right: 0;
	bottom: 0;
	z-index: 90;
	background: var(--wp--preset--color--background);
	border-top: 1px solid var(--wp--preset--color--border);
	/* Constraint: accommodates mobile safe-area insets. */
	padding: var(--wp--preset--spacing--2) var(--wp--preset--spacing--3)
		calc(var(--wp--preset--spacing--2) + env(safe-area-inset-bottom));
}
.qoqo-sticky-cta.is-visible {
	display: block;
}
.qoqo-sticky-cta .wp-block-button__link {
	display: block;
	width: 100%;
	min-height: 44px;
	text-align: center;
}
/* Constraint: never covers page content — reserve matching bottom padding
   on the document body while the bar is visible, so the footer/last
   section is never hidden underneath it. Toggled by site.js in lockstep
   with .qoqo-sticky-cta.is-visible. */
body.qoqo-sticky-cta-active {
	padding-bottom: 76px; /* approximate bar height; refined once the real
		button/typography are in place and can be measured. */
}
/* Constraint: does not obscure the footer — site.js removes .is-visible
   (and the body padding above) once the footer's top edge scrolls into
   view, via an IntersectionObserver on the footer template part. */
/* Constraint: never blocks form controls — the Request a Quote page
   suppresses the bar entirely (see site.js); on every other page, if a
   future on-page form's fields would sit in the bar's band, apply the
   .qoqo-sticky-cta--yield class (added by site.js on field focus) to
   shrink/hide the bar rather than overlap the field. */
.qoqo-sticky-cta--yield {
	transform: translateY(100%);
}
@media (min-width: 1024px) {
	/* Constraint (implicit): no sticky bar on desktop — the header's
	   persistent CTA (parts/header.html) already stays visible without
	   scroll-triggered behavior. */
	.qoqo-sticky-cta {
		display: none !important;
	}
	body.qoqo-sticky-cta-active {
		padding-bottom: 0;
	}
}

/* ---------------------------------------------------------------------
   6. Mobile navigation overlay (DL-107 Section 8) — full-screen/slide-in
   black-background overlay, large 44px+ tap targets, Poppins for menu
   headings, Inter for sub-items. WordPress core's Navigation block
   provides the open/close mechanics and focus trap for its own overlay;
   this only restyles it to match the approved brand.
   Defect correction (staging mobile-nav QA): because the wp:navigation
   block in parts/header.html carries no textColor attribute, it never
   gets WP core's own "has-text-color" class — which means core's default
   fallback rule (wp-includes/blocks/navigation/style.min.css) applies
   color:#000 to the open overlay. That combined with the background-color
   override below (correctly black, per brand) produced black text and a
   black close-button icon on a black background — a fully rendered but
   completely invisible menu. Only a background override existed here
   before; the color override below is the actual fix. Both need
   !important — core's own #000 fallback rule has higher selector
   specificity (.wp-block-navigation:not(.has-text-color) ... :not(
   .disable-default-overlay)) than a plain .is-menu-open selector would
   carry without it.
--------------------------------------------------------------------- */
.wp-block-navigation__responsive-container.is-menu-open {
	background-color: var(--wp--preset--color--background) !important;
	color: var(--wp--preset--color--text) !important;
}
.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation-item > a,
.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation-submenu > a {
	font-family: var(--wp--preset--font-family--body);
	min-height: 44px;
	display: flex;
	align-items: center;
	color: var(--wp--preset--color--text);
}
.wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__responsive-container-close {
	color: var(--wp--preset--color--text) !important;
}
/* Defect correction (staging mobile-nav QA, second pass) — the Primary
   nav (parts/header.html) sets layout.justifyContent:"right" so its
   *desktop* row sits flush against the header's right edge, next to the
   logo. WordPress core's Navigation block reuses the SAME custom
   property for two unrelated purposes: --navigation-layout-justify
   drives the desktop horizontal justify-content (still correctly
   "right" — desktop is unaffected by this fix and needs no change), but
   --navigation-layout-justification-setting ALSO drives align-items on
   the *mobile overlay's* vertical column (see
   wp-includes/blocks/navigation/style.min.css:
   ".is-menu-open ... .wp-block-navigation__responsive-container-content
   { align-items: var(--navigation-layout-justification-setting) }").
   Both properties are set together by the same ".items-justified-right"
   class, so the desktop-appropriate "right" leaked into the mobile
   overlay as align-items:flex-end — right-edge-aligning every menu row
   independently by its own text width (short items like "Home" pushed
   far right, longer items less so), producing a staggered column with
   no shared left edge. The Footer nav has no justifyContent override
   (defaults to left/flex-start) and was never affected — hence it
   already rendered correctly. Fix: re-declare the custom property back
   to flex-start, scoped to the Primary nav's mobile overlay only
   (.qoqo-primary-nav), so every row and the Events submenu share one
   left edge while the desktop layout (a completely separate variable)
   is untouched. */
.qoqo-primary-nav .wp-block-navigation__responsive-container.is-menu-open {
	--navigation-layout-justification-setting: flex-start;
}

/* Defect correction (staging mobile-nav QA, third pass) — the custom-
   property reset above was correct in principle but not sufficiently
   robust: WordPress core also switches every .wp-block-navigation-item
   (including the Events parent LI and its submenu's own LIs) to
   flex-direction:column inside the open overlay, and several of those
   items' cross-axis sizing still resolved inconsistently depending on
   which layer of core's cascade actually won on a given request/cache
   state. Rather than depend on one shared variable, this block sets
   every relevant property explicitly and defensively, scoped to the
   Primary nav's open overlay only (.qoqo-primary-nav ... .is-menu-open),
   so it cannot regress regardless of which core rule would otherwise
   apply: each top-level row spans the full menu width and left-aligns
   its own text/icon content, the Events submenu stays visually a child
   list with one consistent, modest left indent, and none of this touches
   the desktop layout (a completely different, non-overlay code path) or
   the Footer nav (different className, not matched by these selectors). */
.qoqo-primary-nav .wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__responsive-container-content,
.qoqo-primary-nav .wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__container,
.qoqo-primary-nav .wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__submenu-container {
	align-items: stretch !important;
	justify-content: flex-start !important;
	width: 100% !important;
}
.qoqo-primary-nav .wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation-item {
	width: 100% !important;
	justify-content: flex-start !important;
	margin: 0 !important;
}
.qoqo-primary-nav .wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation-item__content {
	width: 100% !important;
	max-width: 100% !important;
	margin: 0 !important;
	padding-left: 0;
	padding-right: 0;
	text-align: left !important;
	justify-content: flex-start !important;
}
/* Events submenu — a modest, consistent indent measured from the shared
   left edge established above, using an approved spacing token rather
   than an arbitrary value. */
.qoqo-primary-nav .wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__submenu-container .wp-block-navigation-item__content {
	padding-left: var(--wp--preset--spacing--3) !important;
}
/* Defect correction (staging mobile-nav QA, fifth pass) — root cause
   CONFIRMED via getComputedStyle()/getBoundingClientRect() in a real
   headless-browser session (not inferred from markup): two distinct
   bugs compounded on the Events row specifically.
   (1) The Events <li> (class "has-child ... wp-block-navigation-submenu")
   computed align-items:flex-end even after the --navigation-layout-
   justification-setting reset above — some other core rule scoped to
   has-child/submenu items re-asserts flex-end at a specificity this
   fix didn't account for. Plain leaf items were unaffected (confirmed
   correct at flex-start), which is why only Events and its children
   were still wrong. Fixed by forcing align-items directly on the
   Events <li> rather than depending solely on the inherited variable.
   (2) The submenu-container computed width:100% (as intended) but with
   box-sizing:content-box and core's own 2rem left+right padding, its
   rendered border-box width (422px) exceeded the <li>'s own width
   (358px) by exactly the 64px of padding. Combined with (1)'s
   align-items:flex-end, that 64px overflow was pushed entirely to the
   left, landing the whole submenu at rectLeft:-48 — clipped off-screen,
   worse for longer labels since the box's fixed RIGHT edge stayed put
   while more overflow accumulated on the left as content forced no
   additional width. box-sizing:border-box makes width:100% include the
   padding, closing the gap that flex-end was exploiting. */
.qoqo-primary-nav .wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation-item.has-child {
	align-items: flex-start !important;
}
.qoqo-primary-nav .wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__submenu-container {
	position: static !important;
	left: auto !important;
	right: auto !important;
	box-sizing: border-box !important;
}
.qoqo-primary-nav .wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__submenu-container .wp-block-navigation-item {
	position: static !important;
}

/* ---------------------------------------------------------------------
   7. Form baseline (DL-107 Section 4) — generic hooks so the eventually-
   chosen form plugin's markup can pick up the approved visual system with
   minimal per-field overrides. Refined once the specific plugin (Prompt 11
   Batch 1 decision item) is installed and its actual markup is known.
--------------------------------------------------------------------- */
input[type="text"],
input[type="email"],
input[type="tel"],
input[type="date"],
input[type="number"],
textarea,
select {
	background: var(--wp--preset--color--surface-1);
	border: 1px solid var(--wp--preset--color--border);
	border-radius: 8px;
	color: var(--wp--preset--color--text);
	min-height: 44px;
	padding: 0 var(--wp--preset--spacing--2);
}
input::placeholder,
textarea::placeholder {
	color: var(--wp--preset--color--text-muted);
}
input:focus-visible,
textarea:focus-visible,
select:focus-visible {
	border-color: var(--wp--preset--color--gold-hover);
}
.qoqo-field-error {
	border-color: var(--wp--preset--color--error) !important;
}
.qoqo-field-error-message {
	color: var(--wp--preset--color--error);
	font-size: var(--wp--preset--font-size--small);
	display: flex;
	align-items: center;
	gap: 4px;
}
.qoqo-field-error-message::before {
	content: "\2715"; /* the same "X" glyph already used in the Style
		Guide's prohibited-treatment lists, per DL-107 Section 4 — error
		identification never relies on color alone. */
}

/* ---------------------------------------------------------------------
   8. Prompt 11 Batch 2 page-layout patterns (DL-114 desktop wireframes) —
   hero split, card/process grids, package-card cap, split CTA row, compact
   form fields. Layout only; no new colors/typography/decorative systems.
   Desktop overrides use the same 1024px desktopMin breakpoint as Section 6.
--------------------------------------------------------------------- */

/* Two-column Hero variant (Home, Photo Booth Rentals): stacked on mobile,
   ~58/42 split on desktop. */
.qoqo-hero-split {
	display: grid;
	grid-template-columns: 1fr;
	gap: var(--wp--preset--spacing--4);
	align-items: center;
}
@media (min-width: 1024px) {
	.qoqo-hero-split {
		grid-template-columns: 58fr 42fr;
		gap: var(--wp--preset--spacing--5);
	}
}

/* Event-type cards (Home) and lightweight icon+link rows (Photo Booth
   Rentals "Perfect for Any Celebration") — 1 column on mobile, 3 or 4 on
   desktop depending on section. */
.qoqo-grid-3,
.qoqo-grid-4 {
	display: grid;
	grid-template-columns: 1fr;
	gap: var(--wp--preset--spacing--3);
}
@media (min-width: 1024px) {
	.qoqo-grid-3 {
		grid-template-columns: repeat(3, 1fr);
	}
	.qoqo-grid-4 {
		grid-template-columns: repeat(4, 1fr);
	}
}

/* How It Works step: icon beside text on mobile, icon above text on
   desktop (DL-114 Home desktop adaptation). */
.qoqo-process-step {
	display: flex;
	align-items: flex-start;
	gap: var(--wp--preset--spacing--2);
}
@media (min-width: 1024px) {
	.qoqo-process-step {
		flex-direction: column;
	}
}

/* Featured Package Card (Photo Booth Rentals): full-width on mobile,
   capped/centered at 640px so the single package never visually implies
   more choices exist than the approved one (DL-107 Section 7 / DL-114). */
.qoqo-package-card-wrap {
	max-width: 640px;
	margin-inline: auto;
}

/* Closing CTA sections (Home, Photo Booth Rentals): centers the heading and
   the buttons row via plain classes rather than a Group "layout"/"style"
   block attribute — those attributes aren't ones the Group block actually
   serializes for text-alignment, and hand-authoring them caused a
   block-validation mismatch on staging (Prompt 11 Batch 2 defect fix). */
.qoqo-cta-center {
	text-align: center;
}
.qoqo-cta-center .wp-block-buttons {
	justify-content: center;
}

/* Lightweight icon+link row (Photo Booth Rentals "Perfect for Any
   Celebration") — plain flex via a custom class rather than the Group
   block's native "layout" attribute, for the same block-validation reason
   as .qoqo-cta-center above. */
.qoqo-icon-link {
	display: flex;
	align-items: center;
	gap: var(--wp--preset--spacing--1);
}

/* "Questions Before You Book?" split row (Photo Booth Rentals): stacked on
   mobile, text-left/button-right on desktop. */
.qoqo-split-cta {
	display: flex;
	flex-direction: column;
	gap: var(--wp--preset--spacing--2);
}
@media (min-width: 1024px) {
	.qoqo-split-cta {
		flex-direction: row;
		align-items: center;
		justify-content: space-between;
		gap: var(--wp--preset--spacing--4);
	}
}

/* ---------------------------------------------------------------------
   9. Fluent Forms styling (DL-140, free version) — Request a Quote and
   Contact embed Fluent Forms via shortcode (see the patterns' build-spec
   comments); this reskins its front-end output to the QOQO input/button
   styling already established in Section 7, rather than a page builder or
   the plugin's own default look. Selectors below (ff-el-group,
   ff-el-form-control, ff-el-input--label, ff-btn-submit, etc.) are
   verified against Fluent Forms 6.2.13's actual PHP rendering source
   (BaseComponent::getDefaultContainerClass()/buildElementMarkup(),
   Text::compile()) — not guessed from documentation. A live visual check
   on staging is still worthwhile once forms are placed, but these class
   names are confirmed correct, not provisional. site.css is
   enqueued at a later priority than default (functions.php,
   qoqo_enqueue_assets) specifically so these overrides win the cascade
   against the plugin's own stylesheet. */
.fluentform .ff-el-group {
	margin-bottom: var(--wp--preset--spacing--2);
}
.fluentform label,
.fluentform .ff-el-input--label label {
	font-family: var(--wp--preset--font-family--body);
	font-size: var(--wp--preset--font-size--small);
	font-weight: 600;
	color: var(--wp--preset--color--text);
}
.fluentform input[type="text"],
.fluentform input[type="email"],
.fluentform input[type="tel"],
.fluentform input[type="date"],
.fluentform input[type="number"],
.fluentform textarea,
.fluentform select,
.fluentform .ff-el-form-control {
	background: var(--wp--preset--color--surface-1);
	border: 1px solid var(--wp--preset--color--border);
	border-radius: 8px;
	color: var(--wp--preset--color--text);
	min-height: 44px;
	padding: 0 var(--wp--preset--spacing--2);
	width: 100%;
}
.fluentform textarea.ff-el-form-control {
	min-height: 120px;
	padding-top: var(--wp--preset--spacing--1);
}
.fluentform input:focus-visible,
.fluentform textarea:focus-visible,
.fluentform select:focus-visible,
.fluentform .ff-el-form-control:focus-visible {
	border-color: var(--wp--preset--color--gold-hover);
}
.fluentform .ff-el-form-help,
.fluentform .ff_help_message {
	font-size: var(--wp--preset--font-size--small);
	color: var(--wp--preset--color--text-muted);
}
.fluentform .error,
.fluentform .text-danger,
.fluentform .ff-el-is-error .ff-error-message {
	color: var(--wp--preset--color--error);
	font-size: var(--wp--preset--font-size--small);
}
.fluentform .ff-el-form-check-label,
.fluentform .ff_agree_label {
	display: flex;
	align-items: flex-start;
	gap: var(--wp--preset--spacing--1);
	font-size: var(--wp--preset--font-size--small);
	color: var(--wp--preset--color--text-muted);
}
.fluentform input[type="checkbox"] {
	margin-top: 4px;
	width: 18px;
	height: 18px;
	flex-shrink: 0;
}
.fluentform button[type="submit"],
.fluentform .ff-btn-submit {
	display: block;
	width: 100%;
	min-height: 44px;
	background: var(--wp--preset--color--gold);
	color: var(--wp--preset--color--button-text-on-gold);
	border: none;
	border-radius: 8px;
	font-family: var(--wp--preset--font-family--body);
	font-size: var(--wp--preset--font-size--small);
	font-weight: 600;
	cursor: pointer;
	transition: background-color 200ms ease-out;
}
.fluentform button[type="submit"]:hover,
.fluentform .ff-btn-submit:hover {
	background: var(--wp--preset--color--gold-hover);
}
.fluentform button[type="submit"]:active,
.fluentform .ff-btn-submit:active {
	background: var(--wp--preset--color--gold-active);
}

/* ---------------------------------------------------------------------
   10. Template/part structural classes (Prompt 11 Batch 1 defect
   correction) — replaces native Group-block "layout"/"style" attributes
   on templates/page.html, index.html, page-thank-you.html,
   page-long-form.html, page-form.html, 404.html, parts/header.html, and
   parts/footer.html with deterministic classes. Those attributes required
   WordPress-auto-generated companion classes/inline styles that the
   hand-authored markup didn't include, causing the same block-validation
   mismatch fixed in the Batch 2 page patterns. Values here reproduce the
   exact approved widths/spacing those templates already had — this is a
   packaging-mechanism change, not a visual or behavioral one.
--------------------------------------------------------------------- */
.qoqo-content-1080 {
	max-width: 1080px;
	width: 100%;
	margin-inline: auto;
}
.qoqo-content-740 {
	max-width: 740px;
	width: 100%;
	margin-inline: auto;
}
.qoqo-content-640 {
	max-width: 640px;
	width: 100%;
	margin-inline: auto;
}
.qoqo-pt-5 { padding-top: var(--wp--preset--spacing--5); }
.qoqo-pb-5 { padding-bottom: var(--wp--preset--spacing--5); }
.qoqo-pt-6 { padding-top: var(--wp--preset--spacing--6); }
.qoqo-pb-6 { padding-bottom: var(--wp--preset--spacing--6); }
.qoqo-pt-7 { padding-top: var(--wp--preset--spacing--7); }
.qoqo-pb-7 { padding-bottom: var(--wp--preset--spacing--7); }
.qoqo-text-center {
	text-align: center;
}
.qoqo-text-center .wp-block-buttons {
	justify-content: center;
}

/* Sticky header (parts/header.html) — same sticky/width/border behavior
   theme.json's Group "position" + "layout" block supports were declaring,
   now applied directly instead of relying on their auto-generated markup. */
.qoqo-site-header {
	position: sticky;
	top: 0;
	z-index: 100;
	border-bottom: 1px solid var(--wp--preset--color--border);
	max-width: 1200px;
	margin-inline: auto;
}
.qoqo-header-inner {
	display: flex;
	align-items: center;
	justify-content: space-between;
	flex-wrap: nowrap;
	padding: var(--wp--preset--spacing--2) var(--wp--preset--spacing--3);
}

/* Footer (parts/footer.html) — same width/border/padding the Group
   "layout"/"style" attributes were declaring, applied directly. The
   .qoqo-site-footer class is also site.js's DL-134 footer-intersection
   selector — unchanged, only these rules were added under it. */
.qoqo-site-footer {
	max-width: 1200px;
	margin-inline: auto;
	border-top: 1px solid var(--wp--preset--color--border);
	padding: var(--wp--preset--spacing--5) var(--wp--preset--spacing--3);
}

/* Full logo lockup (owner correction) — the site-wide Site Logo setting
   now points at the complete icon+QOQO+PRODUCTIONS artwork rather than
   the icon mark alone, everywhere .wp-block-site-logo is used (header,
   footer). That artwork's natural shape is tall (icon stacked over two
   text lines), so its HEIGHT is what needs controlling for a sane header
   — the Site Logo block itself only exposes a width attribute, which
   would otherwise drive an oversized height. Overriding height directly
   and letting width follow (width:auto) keeps the lockup's real
   proportions intact (no stretch/distortion) while fitting each context:
   compact enough on mobile to leave the hamburger and CTA room, a bit
   more breathing room on desktop, and larger still in the footer where
   DL-107 already allows a bigger treatment.
   Desktop softness defect correction: confirmed via real headless-browser
   captures (not upscaled screenshots) that the source crop is already
   full native resolution from the only approved logo file in the project
   (1448x1086 original; the 728x856 crop is a lossless 1:1 pixel crop of
   it, not a downscale) — at true integer device-pixel ratios (1x, 3x)
   the logo rendered crisp even at 118px. The softness the owner saw was
   reproduced specifically at fractional device-pixel ratios (1.5x, the
   common Windows default), where any small raster text unavoidably picks
   up some anti-aliasing blur during resampling — not a resolution
   shortfall. Sizing up from 118px to 144px measurably improved
   legibility at 1.5x without a higher-res source (none exists) and
   without making the header excessively tall. */
.qoqo-site-header .custom-logo {
	height: 144px;
	width: auto;
	max-width: none;
}
.qoqo-site-footer .custom-logo {
	height: 132px;
	width: auto;
	max-width: none;
}
@media (max-width: 767px) {
	.qoqo-site-header .custom-logo {
		height: 52px;
	}
}

/* Header phone number (owner-approved 2026-08-28) — sits directly below
   the Check Availability CTA, right-aligned to match it, in smaller
   supporting text so it doesn't compete with the primary CTA. The wrap
   stacks button-then-phone in a column; the row's own height already
   grows to fit the 144px logo, so this adds no extra header height on
   desktop. On mobile the same column stack sits under the CTA without
   requiring extra horizontal room — verified visually to not crowd the
   logo/hamburger row. */
.qoqo-header-cta-wrap {
	display: flex;
	flex-direction: column;
	align-items: flex-end;
	gap: 4px;
}
.qoqo-header-phone {
	margin: 0;
	text-align: right;
	font-size: var(--wp--preset--font-size--small);
}
.qoqo-header-phone a {
	color: var(--wp--preset--color--text-muted);
	text-decoration: none;
}
.qoqo-header-phone a:hover {
	color: var(--wp--preset--color--gold);
}

/* Contact page phone line (owner-approved 2026-08-28) — plain body text,
   modest top margin for separation from the preceding paragraph; no new
   visual treatment beyond the existing design system's default link
   color. */
.qoqo-contact-phone {
	margin-top: var(--wp--preset--spacing--2);
}

/* ---------------------------------------------------------------------
   11. Image placeholders (Prompt 11 Batch 2, second defect-correction
   pass) — replaces empty-src core/image blocks sitewide. The real Image
   block only renders an <img> when its url attribute is non-empty; an
   empty src="" in hand-authored markup can never match that block's real
   save() output, which was the actual root cause of the persisting
   "unexpected or invalid content" warnings. These are plain Group blocks
   (already a proven-safe block type) styled as a placeholder box —
   replace the class list with a real core/image block once an approved
   media asset exists; nothing here should be mistaken for final art.
--------------------------------------------------------------------- */
.qoqo-image-placeholder {
	display: block;
	background: var(--wp--preset--color--surface-1);
	border: 1px solid var(--wp--preset--color--border);
	border-radius: 8px;
}
.qoqo-image-placeholder--hero {
	width: 100%;
	aspect-ratio: 4 / 3;
}
.qoqo-image-placeholder--icon {
	width: 32px;
	height: 32px;
	flex-shrink: 0;
}
.qoqo-image-placeholder--icon-sm {
	width: 24px;
	height: 24px;
	flex-shrink: 0;
}

/* Real hero photography (replaces .qoqo-image-placeholder--hero once an
   approved asset exists for a given page) — same footprint (full width,
   4:3, 8px radius) as the placeholder it replaces, so no layout shift
   between pages that have a photo and any that still don't. object-fit
   cover + object-position keep the subject centered without distortion
   across the hero-split's fluid width on both desktop and mobile stacked
   layouts; no filters/overlays applied per the approved brief. */
.qoqo-hero-image {
	width: 100%;
	aspect-ratio: 4 / 3;
	border-radius: 8px;
	overflow: hidden;
}
.qoqo-hero-image img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
	object-position: center top;
}
