/* Corrections layer.
 *
 * Loaded AFTER main.css on the front end and second in add_editor_style(), so
 * it can correct the design stylesheet without editing it. When a comp is
 * involved this is what lets the comp's CSS ship byte for byte.
 *
 * Keep design in main.css. Keep fixes here. Do not let this file grow into a
 * second design system.
 */

/* ---------------------------------------------------------------------------
 * Content is visible by default.
 *
 * A design that starts sections at opacity 0 and waits for an
 * IntersectionObserver is one script error away from a blank page that still
 * returns HTTP 200, with normal bounding boxes and full textContent. Every
 * source-reading and geometry-reading check passes while the site is blank on
 * screen. That shipped sitewide on a real build.
 *
 * So: visible is the resting state, and the animation is an enhancement that
 * only ever runs when JavaScript has confirmed it can finish it. site.js adds
 * .has-reveal to <html> before it starts observing.
 * ------------------------------------------------------------------------ */
/* The comp's own vocabulary: it marks revealed elements .in, not .is-in. These
 * values are the comp's (main.css line 361); only the .has-reveal gate is new. */
.reveal { opacity: 1; transform: none; }

.has-reveal .reveal {
	opacity: 0;
	transform: translateY(28px);
	transition: opacity .7s var(--ease), transform .7s var(--ease);
}
.has-reveal .reveal.in { opacity: 1; transform: none; }

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

/* The block editor canvas never runs site.js, so it must never inherit a
 * JavaScript-dependent hidden state. Without this the canvas is a column of
 * blank grey boxes and the editor looks broken. */
.editor-styles-wrapper .reveal,
.block-editor-writing-flow .reveal {
	opacity: 1 !important;
	transform: none !important;
	transition: none !important;
}

/* Count-up stats render their final value in the canvas rather than nothing —
 * site.js is what animates [data-to] on the front end. */
.editor-styles-wrapper .stat .v[data-count] {
	visibility: visible !important;
}

/* The <picture> wrapper must not become the layout box.
 *
 * inc/images.php wraps every <img> in a <picture> to serve WebP/AVIF. That makes
 * the PICTURE the grid or flex item and leaves the img's own classes applying to
 * a non-item, so any rule positioning an image by class silently stops working.
 *
 * Measured consequence on this build: `.team-photos .main { grid-column: 1/-1 }`
 * stopped spanning, and Tyler's hero photo rendered 266x199 inside a 2x2 grid
 * instead of 547x342 across the top. It shipped that way. Nothing caught it,
 * because the photos column is shorter than the copy column next to it, so page
 * height was unchanged and every height-based comparison passed.
 *
 * display:contents removes the wrapper from layout entirely and hands the box
 * back to the img. Applied globally rather than scoped, because the hazard is the
 * wrapper itself and the next image positioned by class would hit it again. An
 * image-geometry diff of comp vs build across the whole homepage showed this one
 * container as the only difference, so nothing currently relies on the picture box.
 */
picture:has(> img) {
	display: contents;
}

/* ...but display:contents promotes the picture's CHILDREN to items, and each
 * <picture> here holds two <source> elements (AVIF, WebP) as well as the <img>.
 * Those became grid items too: two empty cells per image, which pushed Tyler's
 * second small photo onto its own row (measured y=605 against the comp's y=358)
 * even though every image was the right SIZE. Size-only comparison reported zero
 * differences -- position is what moved.
 *
 * display:none on a <source> is safe: it is never rendered, and the browser's
 * image-source selection reads its attributes regardless of CSS. */
picture > source {
	display: none;
}

/* ---------------------------------------------------------------------------
 * Accessibility floor
 * ------------------------------------------------------------------------ */
.skip-link {
	position: absolute;
	left: -9999px;
	top: 0;
	z-index: 999;
	padding: 12px 18px;
	background: #fff;
	color: #111;
}
.skip-link:focus { left: 8px; top: 8px; }

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

:where(a, button, input, select, textarea):focus-visible {
	outline: 3px solid currentColor;
	outline-offset: 2px;
}

/* WCAG 2.5.8 target size. Pagination links shipped at 9x23 on a real build and
 * passed every automated check that was looking at colour and markup. */
.pagination a,
.pagination .current,
.nav-links a,
.nav-links .current {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 44px;
	min-height: 44px;
}

/* Small text links: reach the WCAG 2.2 AA target size.
 *
 * The comp renders these between 17px and 22px tall. That fails SC 2.5.8
 * Target Size (Minimum), which is AA and asks for 24x24 CSS px, and the
 * inline-text exception does NOT cover a nav list or a legal row -- only links
 * sitting inside a sentence.
 *
 * The selectors are MEASURED, not guessed. A first attempt at this rule aimed at
 * `.site-footer nav a` and `.f-col ul a`, which exist in the starter and not in
 * this comp: it matched nothing and the failures were unchanged while the rule
 * looked like a fix. These four are what a mobile DOM walk actually reported.
 *
 * inline-flex + min-height rather than padding, so the box grows around the text
 * instead of pushing the next element down. Measured layout shift after this
 * rule: header unchanged, footer +6px total.
 */
.foot-areas a,
.foot-legal a,
/* NOT .foot-legal span: that is the WRAPPER holding the whole legal line, and
   making it inline-flex turned its middot separators into flex items with no
   gap, rendering "#355024 ·Privacy·Terms·Accessibility". Target the links. */
footer .container ul a,
.drawer .d-panel a,
.callout p a,
.svc-link,
.crumbs a {
	display: inline-flex;
	align-items: center;
	min-height: 24px;
}

/* a.head-phone is SPLIT OUT of the rule above -- same bug class as the
 * .foot-legal span note, one selector further down the list.
 *
 * It used to sit in that group, and the shared `inline-flex` made its two
 * children flex items: .lbl ("Call or text") and .num (the number). That
 * cancels the `display:block` main.css puts on .lbl to stack them, so they
 * rendered side by side on one row with no gap between them --
 * "CALL OR TEXT(602) 374-3352". The target-size fix broke the one header
 * element it was never aiming at.
 *
 * flex-direction:column restores the stack. align-items:flex-end reproduces the
 * `text-align:right` that main.css sets and that flex layout ignores.
 * min-height stays, so SC 2.5.8 Target Size still passes.
 */
a.head-phone {
	display: inline-flex;
	flex-direction: column;
	align-items: flex-end;
	justify-content: center;
	min-height: 24px;
}

/* ---------------------------------------------------------------------------
 * Editor canvas
 * ------------------------------------------------------------------------ */

/* The canvas has no site chrome, so full-bleed sections need the width back. */
.editor-styles-wrapper .container { margin-inline: auto; }

/* Fixed and sticky elements escape the canvas and hover over the editor UI. */
.editor-styles-wrapper header,
.editor-styles-wrapper .mobile-bar,
.editor-styles-wrapper .to-top {
	position: static !important;
}

/* ---------------------------------------------------------------------------
 * Landing-page chrome
 *
 * parts/01-header-lp.html and parts/90-footer-lp.html drop the navigation and
 * the footer sitemap. Two knock-on layout facts:
 *
 *   .header-inner is flex/space-between, so a header with only a logo and a CTA
 *   needs nothing -- it already works.
 *
 *   .foot-main is a FOUR column grid (1.4fr 1fr 1fr 1.2fr). The LP footer has
 *   two children, which would sit in columns one and two and leave half the
 *   footer empty. That is the only override needed.
 * ------------------------------------------------------------------------ */
.lp-foot-main {
	grid-template-columns: 1.6fr 1fr;
}

/* The LP logo is a <span>, not a link, so it has no anchor display to inherit. */
.lp-header .logo {
	display: inline-flex;
	align-items: center;
}

@media (max-width: 860px) {
	.lp-foot-main { grid-template-columns: 1fr; }
}

/* Trust row, high on the page. Google scores transparency explicitly and a
 * homeowner looks for it before calling, so it sits directly under the hero
 * rather than only in the footer. Styled as discrete facts rather than one
 * middot-separated run-on sentence, which is how the first version read. */
.lp-trust {
	display: flex;
	flex-wrap: wrap;
	gap: 10px 14px;
	align-items: center;
	justify-content: center;
}
.lp-trust .fbadge {
	background: rgba(11, 38, 24, .06);
	border: 1px solid rgba(11, 38, 24, .12);
	color: var(--ink);
}

/* ---------------------------------------------------------------------------
 * Gravity Forms, wearing the comp's clothes.
 *
 * inc/gravity-forms.php turns GF's own "orbital" theme CSS off, because it is
 * more specific than the comp's `.form-card input` rules and was rendering
 * 38px inputs where the comp has 50px ones. Handing styling back to the comp
 * means WE now owe the few things GF's stylesheet was doing for us — and two of
 * them are not cosmetic:
 *
 *   - the honeypot field was VISIBLE (GF hides .gform_validation_container in
 *     its own CSS). A visible "leave this blank" input is both ugly and a
 *     working spam trap turned into a user trap.
 *   - the labels were VISIBLE. The form is placeholder-only by design, and GF's
 *     hidden_label setting relies on its CSS to do the hiding.
 *
 * Everything here is scoped to .form-card so a future form elsewhere can still
 * use GF's own theme.
 * ------------------------------------------------------------------------ */

/* Spam trap stays a trap. */
.form-card .gform_validation_container,
.form-card .gfield--type-honeypot { display: none !important; }

/* Placeholder-only design: labels remain for screen readers, not for eyes.
   aria-required on the inputs still announces requiredness, so hiding the
   asterisk costs nothing semantically. */
.form-card .gfield_label,
.form-card .gfield_required {
	position: absolute;
	width: 1px; height: 1px;
	margin: -1px; padding: 0;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
	border: 0;
}

/* The comp's .form-row pairs, rebuilt on GF's own width classes. */
/* GF renders fields as <li> in one markup mode and <div> in another, and the
   deployed install uses the <li> form. With GF's own CSS off nothing removes
   the list marker, so every field grew a bullet. Covers both modes. */
.form-card .gform_fields,
.form-card .gform_fields > li,
.form-card .gfield { list-style: none; }

.form-card .gform_fields {
	display: grid;
	grid-template-columns: 1fr 1fr;
	gap: 14px;
}
.form-card .gfield--width-full,
.form-card .gfield--type-textarea,
.form-card .gfield--type-html { grid-column: 1 / -1; }

.form-card .gform_wrapper,
.form-card .gform-body { margin: 0; }
.form-card .ginput_container { margin: 0; }

/* The comp sizes the textarea itself; GF's rows attribute otherwise wins. */
.form-card textarea { min-height: 88px; height: 88px; }

/* Submit button is full width, like the comp's. The comp's own
    already carries margin-bottom:14px, so adding a top
   margin here stacks two gaps and the card grows 14px taller than the comp. */
.form-card .gform_footer { margin: 0; padding: 0; }
.form-card .gform_footer .btn { width: 100%; }

/* Validation messages, in the comp's palette rather than GF's default red bar. */
.form-card .gfield_description.validation_message,
.form-card .gform_validation_errors {
	background: none;
	border: none;
	color: #C0392B;
	font-size: 13px;
	padding: 4px 2px 0;
	margin: 0;
}

@media (max-width: 720px) {
	.form-card .gform_fields { grid-template-columns: 1fr; }
}

/* ---------- Whiter page ground — 2026-08-19 ----------
   Ricky prefers the lighter page he saw on the Bricks build. That build set no
   body background, so it fell through to #FFFFFF while its cards kept the cream
   tint. Live shipped the inverse: cream ground, near-white cards. This swaps the
   two roles so the page reads white and cards stay visible against it.
   COLOR ONLY — no markup, no images, no layout, nothing removed. */
body{background:#FFFFFF}
.hero-card,.svc-card,.form-card,.faq-item,.rev-card,.step,.g-badge,
.dropdown,.dropdown::before,table.compare,.section.tint,.btn-cream{background:var(--cream)}
.svc-num{border-color:var(--cream)}
