/*!
Theme Name: Zach Lahn for Governor
Theme URI: https://www.zachlahn.com/
Author: Tag Strategies
Author URI: https://tagstrategies.co/
Description: Campaign theme for Zach Lahn for Iowa Governor (2026). Built on a custom underscores-based starter, with the design ported from Webflow and section content driven by ACF.
Version: 1.0.0
Tested up to: 6.7
Requires PHP: 7.4
License: GNU General Public License v2 or later
License URI: LICENSE
Text Domain: theme
Tags: custom-logo, custom-menu, featured-images

The design (CSS in /assets/css/) is exported from Webflow. This stylesheet only
carries the theme header plus small overrides that glue WordPress, Gutenberg, and
Gravity Forms output into the Webflow look. Edit /assets/css/zach-lahn.css for
design changes.
*/

/* --------------------------------------------------------------------------
 * WordPress body-class collision fix
 *
 * WordPress adds a `page` class to the <body> of every Page, which collides
 * with the Webflow design class `.page { background-color: var(--color-base--green) }`,
 * turning the whole page dark green and hiding the (dark green) headings.
 * Restore the intended Webflow body background. (.home/.blog etc. do not collide.)
 * ------------------------------------------------------------------------ */
body.page,
body.blog,
body.archive,
body.search,
body.error404 {
	background-color: var(--color-base--white);
}

/* --------------------------------------------------------------------------
 * Fixed header stacking
 *
 * The timeline slider sets z-index:99999, which painted over the fixed nav
 * (.w-nav defaults to z-index:1000). Keep the header above the slider but
 * below the Webflow lightbox (z-index:9999999).
 * ------------------------------------------------------------------------ */
.navbar,
.navbar.is-v2 {
	z-index: 100000;
}

/* --------------------------------------------------------------------------
 * Home offer cards — reveal the subtext on hover (Webflow behaviour)
 * ------------------------------------------------------------------------ */
/*
 * Hover-reveal the offer subtext. Earlier versions animated height (max-height,
 * then grid-template-rows), which reflowed the vertically-centred content — the
 * heading and buttons shifted as the details grew, reading as "jumpy" (and
 * grid-row transitions aren't smooth in every browser). Instead the details
 * keep their space reserved at all times (zero reflow) and simply fade + slide
 * in on hover. Nothing moves; it's smooth everywhere.
 */
.home1_offer_item .offer_details {
	opacity: 0;
	transform: translateY(6px);
	transition: opacity 0.5s ease, transform 0.5s cubic-bezier(0.22, 0.61, 0.36, 1);
	pointer-events: none;
	will-change: opacity, transform;
}
.home1_offer_item .offer_details_inner {
	display: flex;
	justify-content: center;
	column-gap: 32px;
}
.home1_offer_item:hover .offer_details,
.home1_offer_item:focus-within .offer_details {
	opacity: 1;
	transform: none;
	pointer-events: auto;
}
@media (prefers-reduced-motion: reduce) {
	.home1_offer_item .offer_details {
		transition: none;
		transform: none;
	}
}

/*
 * Split-panel hover expand. Webflow grows the hovered panel via width:150% on
 * `transition: all .4s` — but percentage-width transitions DON'T interpolate on
 * flex items (the flex algorithm resolves the size, so it snaps). Drive the
 * expand with flex-grow instead, which animates smoothly. Desktop only (the
 * panels stack on mobile, where the base rule already disables the grow).
 */
@media (min-width: 992px) {
	.home1_offer_item {
		flex: 1 1 0%;
		width: auto;
		transition: flex-grow 0.65s cubic-bezier(0.22, 0.61, 0.36, 1);
	}
	.home1_offer_item:hover {
		flex-grow: 1.6;
		width: auto;
	}
}
.home1_offer_overlay {
	transition: background-color 0.65s ease;
}
@media (prefers-reduced-motion: reduce) {
	.home1_offer_item { transition: none; }
	.home1_offer_item:hover { flex-grow: 1; width: auto; }
}

/* --------------------------------------------------------------------------
 * Policy philosophy bullets — green check icon
 * (the Webflow export shipped an empty image URL for this).
 * ------------------------------------------------------------------------ */
.comparison-positive {
	background-image: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2024%2024'%3E%3Ccircle%20cx='12'%20cy='12'%20r='10.5'%20fill='none'%20stroke='%231a422b'%20stroke-width='1.5'/%3E%3Cpath%20d='M7.5%2012.3l3%203%206-6.3'%20fill='none'%20stroke='%231a422b'%20stroke-width='1.8'%20stroke-linecap='round'%20stroke-linejoin='round'/%3E%3C/svg%3E");
	background-repeat: no-repeat;
	/* Size in em + vertical-center + a min-height floor so the icon never
	 * overflows the text box (single-line rows are only ~1 line tall, and the
	 * mobile rule shrinks the font to .8rem — a fixed 24px icon got clipped). */
	background-size: 1.5em 1.5em;
	background-position: left center;
	min-height: 1.7em;
}

/* --------------------------------------------------------------------------
 * Scroll-reveal entrance animations
 *
 * Mimics the Webflow "fade + slide up" entrance. Gated behind html.wf-anim
 * (added by assets/js/theme.js) so content is always visible if JS is off,
 * and disabled under prefers-reduced-motion.
 * ------------------------------------------------------------------------ */
html.wf-anim .wf-reveal {
	opacity: 0;
	transform: translateY(1.5rem);
	transition: opacity 0.7s cubic-bezier(0.22, 0.61, 0.36, 1), transform 0.7s cubic-bezier(0.22, 0.61, 0.36, 1);
	will-change: opacity, transform;
}

html.wf-anim .wf-reveal.wf-in {
	opacity: 1;
	transform: none;
}

@media (prefers-reduced-motion: reduce) {
	html.wf-anim .wf-reveal {
		opacity: 1 !important;
		transform: none !important;
		transition: none !important;
	}
}

/* --------------------------------------------------------------------------
 * Page-load entrance (nav + hero)
 *
 * The scroll-reveal above only animates reliably for below-the-fold content.
 * The fixed nav and the above-the-fold hero were already painted by the time
 * the footer JS ran, so they showed no entrance (in fact a late flash as the
 * IntersectionObserver hid then re-showed them). These run as pure CSS
 * animations at first render — animation-fill-mode:both holds the hidden state
 * through the stagger delay — so the nav and hero cascade in on load with no
 * JS and no flash. Inert in browsers without CSS animations (content just
 * shows), and disabled under prefers-reduced-motion.
 * ------------------------------------------------------------------------ */
@keyframes zl-enter-up {
	from { opacity: 0; transform: translateY(1.5rem); }
	to   { opacity: 1; transform: none; }
}
@keyframes zl-enter-down {
	from { opacity: 0; transform: translateY(-0.75rem); }
	to   { opacity: 1; transform: none; }
}
.wf-load {
	animation-name: zl-enter-up;
	animation-duration: 0.85s;
	animation-timing-function: cubic-bezier(0.22, 0.61, 0.36, 1);
	animation-fill-mode: both;
	will-change: opacity, transform;
}
.wf-load-nav {
	animation-name: zl-enter-down;
	animation-duration: 0.7s;
	animation-timing-function: ease;
	animation-fill-mode: both;
}
.wf-delay-1 { animation-delay: 0.15s; }
.wf-delay-2 { animation-delay: 0.28s; }
.wf-delay-3 { animation-delay: 0.41s; }
.wf-delay-4 { animation-delay: 0.52s; }
.wf-delay-5 { animation-delay: 0.64s; }
@media (prefers-reduced-motion: reduce) {
	.wf-load,
	.wf-load-nav {
		animation: none;
	}
}

/* --------------------------------------------------------------------------
 * Events page image strips
 *
 * The Webflow export uses Splide markup for the "ageless-infinite-scroll"
 * carousels but never ships Splide's JS, so the strips are driven here with a
 * pure-CSS marquee (the markup duplicates each slide list for a seamless loop).
 * ------------------------------------------------------------------------ */
.ageless-infinite-scroll {
	overflow: hidden;
}
.ageless-infinite-scroll .splide__track {
	display: flex;
	width: max-content;
}
.ageless-infinite-scroll .splide__list {
	display: flex;
	flex: 0 0 auto;
}
.image-carousel .splide__track {
	animation: zl-marquee 60s linear infinite;
}
.image-carousel2 .splide__track {
	animation: zl-marquee 70s linear infinite reverse;
}
.ageless-infinite-scroll:hover .splide__track {
	animation-play-state: paused;
}
@keyframes zl-marquee {
	from { transform: translateX(0); }
	to { transform: translateX(-50%); }
}
@media (prefers-reduced-motion: reduce) {
	.ageless-infinite-scroll .splide__track { animation: none; }
}

/* Events-only nav announcement banner close button. */
.exit-banner-nav-button {
	cursor: pointer;
}

/* --------------------------------------------------------------------------
 * Events list "pill" (Events , Appearances , & Townhalls)
 *
 * Recreates the Webflow tab-menu pill the original site showed above the events
 * grid. It was purely decorative there too, so this is an inert element (no
 * .w-tabs wrapper -> the Webflow runtime doesn't touch it). The gradient/shape
 * come from the ported .tab-link-tab-2-2.w--current class; this only sets the
 * label typography and a non-interactive cursor.
 * ------------------------------------------------------------------------ */
.events-tab-pill .tab-link-tab-2-2 {
	font-family: "Funnel Sans", Arial, sans-serif;
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.06em;
	font-size: 0.9rem;
	line-height: 1.2;
	cursor: default;
}

/* --------------------------------------------------------------------------
 * "99 County Tour Progress" map section
 *
 * The Webflow rule sized the county map with `background-size: cover`, so it
 * filled the box from the very top and the heading (anchored top) sat on top of
 * it. Size the map by HEIGHT and anchor it to the bottom instead — that always
 * reserves a top band for the heading, at any viewport width. (Overrides the
 * base + responsive `cover` rules, which is why background-position/repeat are
 * restated here too.)
 * ------------------------------------------------------------------------ */
.team-section {
	background-size: auto 72%, auto;
	background-repeat: no-repeat;
	background-position: 50% 100%, 0 0;
}
/* On desktop the section is a tall 80vh, so let the map fill more of it (still
 * clears the heading); the smaller breakpoints keep the safer 72%. */
@media (min-width: 992px) {
	.team-section {
		background-size: auto 80%, auto;
	}
}

/* --------------------------------------------------------------------------
 * "99 County Tour Progress" heading
 *
 * On the Webflow original this title is an <h1 class="heading-18"> — so it picks
 * up the H1 base (3.5rem / line-height 1.1) and reads large and centered. Our
 * port renders it as an <h2> (to avoid a second page <h1>, the hero already
 * being the H1), which left it at the smaller 2.5rem H2 size and left-aligned —
 * the "looks a bit different than ours" the client flagged. Restore the Webflow
 * desktop size + centering on the <h2> so it matches. The tablet (2.5rem) and
 * mobile (1.5rem) sizes already match via the exported .heading-18 breakpoints;
 * this only adds the centering they inherit and the desktop H1-sized step.
 * ------------------------------------------------------------------------ */
.heading-18 {
	text-align: center;
}
@media (min-width: 992px) {
	.heading-18 {
		font-size: 3.5rem;
		line-height: 1.1;
	}
}

/* --------------------------------------------------------------------------
 * Events loop grid + card sizing
 *
 * The Webflow export used a rigid 2-column grid (`1fr 1fr`), so an odd number
 * of upcoming events (e.g. 3) left an empty cell against the dark background.
 * Use a centred flex-wrap instead: cards keep a sensible max width, so the
 * Webflow 16/9 banner image (aspect-ratio + object-fit:cover) stays a modest
 * ~360x202 thumbnail — no crude max-height crop that squished it — and any
 * partial final row centres rather than leaving a gap. Scoped to :not(.is-v2)
 * so the single-event "Next Upcoming Event" block (single column) is untouched.
 * ------------------------------------------------------------------------ */
.projects_list_grid:not(.is-v2) {
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	gap: 1.25rem;
	width: 100%;
}
.projects_list_grid:not(.is-v2) > .w-dyn-item {
	flex: 1 1 300px;
	max-width: 360px;
	margin: 0;
}
/*
 * the_post_thumbnail() emits width/height HTML attributes (the 'card' size is
 * 800x600), and the presentational height="600" overrode the Webflow
 * aspect-ratio:16/9 — forcing a 356x600 tall band (the real "too narrow").
 * height:auto lets aspect-ratio drive the box again -> a ~16/9 banner (~360x202)
 * matching the live site.
 */
.projects_list_image {
	width: 100%;
	height: auto;
	aspect-ratio: 16 / 9;
	object-fit: cover;
}
/*
 * The date badge is position:absolute bottom-right of the card. On the old wide
 * 2-col cards it cleared the left-aligned "Event Details" arrow; on the narrower
 * 3-up cards it collided with it. Make the card a flex column and drop the badge
 * into normal flow as a bottom-aligned pill (the treatment the Webflow design
 * already uses at small breakpoints), so all three cards read evenly.
 */
.projects_list_grid:not(.is-v2) .projects_list_card {
	display: flex;
	flex-direction: column;
}
.projects_list_grid:not(.is-v2) .projects_list_content {
	flex: 1 1 auto;
}
.projects_list_grid:not(.is-v2) .absolute-date {
	position: static;
	inset: auto;
	align-self: flex-start;
	margin: 0 1.5rem 1.25rem;
	border-radius: var(--radius--default);
}

/* --------------------------------------------------------------------------
 * Skip link (accessibility)
 * ------------------------------------------------------------------------ */
.skip-link.screen-reader-text {
	background-color: #fff;
	box-shadow: 0 0 2px 2px rgba(0, 0, 0, 0.6);
	clip: rect(1px, 1px, 1px, 1px);
	clip-path: inset(50%);
	color: #21759b;
	display: block;
	font-size: 0.875rem;
	font-weight: 700;
	height: 1px;
	left: -9999rem;
	line-height: normal;
	overflow: hidden;
	padding: 15px 23px 14px;
	position: absolute !important;
	text-decoration: none;
	top: -9999rem;
	width: 1px;
	z-index: 100000;
}

.skip-link.screen-reader-text:focus {
	clip: auto !important;
	clip-path: none;
	height: auto;
	left: 1.25rem;
	top: 1.25rem;
	width: auto;
}

.screen-reader-text {
	border: 0;
	clip: rect(1px, 1px, 1px, 1px);
	clip-path: inset(50%);
	height: 1px;
	margin: -1px;
	overflow: hidden;
	padding: 0;
	position: absolute !important;
	width: 1px;
	word-wrap: normal !important;
}

/* --------------------------------------------------------------------------
 * Announcement bar (rendered by inc/site-settings.php on wp_body_open)
 * ------------------------------------------------------------------------ */
.announcement-bar {
	display: block;
	background-color: #16412c;
	color: #e8e6cf;
	text-align: center;
	text-decoration: none;
	padding: 0.5rem 1rem;
	font-family: "Funnel Sans", Arial, sans-serif;
	font-size: 0.9rem;
	letter-spacing: 0.01em;
}

.announcement-bar__text {
	color: inherit;
}

/* --------------------------------------------------------------------------
 * Gravity Forms — match the Webflow .form_input look
 * ------------------------------------------------------------------------ */
.gform_wrapper .gform_fields {
	display: block;
}
.gform_wrapper .gfield {
	margin: 0 0 0.5rem;
}
.gform_wrapper .gfield input,
.gform_wrapper .gfield select,
.gform_wrapper .gfield textarea {
	width: 100%;
	border: 0.0625rem solid var(--color-neutral--shade-200);
	border-radius: var(--radius--default);
	background-color: var(--color-base--white);
	min-height: 3rem;
	color: var(--color-base--black);
	margin-bottom: 0.5rem;
	padding: 0.875rem 1rem;
	font-size: 0.875rem;
	font-weight: 500;
	line-height: 1.4;
	font-family: "Funnel Sans", Arial, sans-serif;
}
.gform_wrapper .gfield textarea {
	min-height: 12rem;
	padding-top: 1rem;
}
/* Webflow forms showed placeholders only — keep GF labels for screen readers. */
.gform_wrapper .gfield_label {
	font-family: "Funnel Sans", Arial, sans-serif;
	font-weight: 500;
}
.gform_wrapper .gform_footer {
	padding: 0;
	margin: 0.5rem 0 0;
}
.gform_wrapper .gform_footer .gform_button {
	width: 100%;
}
.gform_wrapper .gform_required_legend {
	display: none;
}

/* Branded form confirmation (Press List + Event Request). */
.form-confirmation {
	text-align: center;
	padding: 2.5rem 1.5rem;
	border-radius: var(--radius--default);
	background-color: var(--color-base--white);
	color: var(--color-base--black);
}
.form-confirmation__check {
	width: 3.25rem;
	height: 3.25rem;
	line-height: 3.25rem;
	margin: 0 auto 1.25rem;
	border-radius: 50%;
	background-color: var(--color-base--green, #1a422b);
	color: #fff;
	font-size: 1.4rem;
	font-weight: 700;
}
.form-confirmation .text-style-badge {
	display: inline-block;
	margin-bottom: 0.75rem;
}
.form-confirmation h3 {
	margin: 0 0 0.5rem;
}
.form-confirmation p {
	margin: 0 auto;
	max-width: 32rem;
}
.gform_confirmation_message {
	width: 100%;
}

/* --------------------------------------------------------------------------
 * FAQ / policy accordions (toggled by assets/js/theme.js)
 * ------------------------------------------------------------------------ */
.faq-a {
	overflow: hidden;
	height: 0;
	transition: height 0.3s ease;
}

.faq-q {
	cursor: pointer;
}

.faq-icon-wrapper {
	transition: transform 0.3s ease;
}

.faq-accordion.is-open .faq-icon-wrapper {
	transform: rotate(180deg);
}

/* --------------------------------------------------------------------------
 * Gutenberg/editor content inside .w-richtext page bodies
 * ------------------------------------------------------------------------ */
.w-richtext img {
	max-width: 100%;
	height: auto;
}

.w-richtext .aligncenter {
	margin-left: auto;
	margin-right: auto;
	display: block;
}
