/*
Theme Name: LBF Theme
Version: 32.0.30
Author: Ray Russell Design
Author URI: https://www.rayrusselldesign.com
Theme URI: https://lexingtonblueberryfestival.com
Description: The Lexington Blueberry Festival WordPress theme. Built by Ray Russell Design.
Text Domain: lbf

— v32.0.30 — FIX (the real one): the ampersand in an entertainer title broke the schedule dedup match, keeping "Kaitlyn Schmit & Friends" off the schedule (changing & to "and" made her appear immediately). Root cause: the schedule dedup used a raw strtolower/trim title as its key, but WordPress can return a title with an HTML entity (&amp;) on one side and a literal & on the other, so the two never compared equal and the entertainer was wrongly skipped (or the wrong row won). Added _lbf_title_dedup_key(): decodes HTML entities, treats "&" and "and" as the same word, collapses whitespace, lowercases. Applied it to every title dedup/match point in data/schedule.php — event rows, entertainer dedup, attraction dedup, and the picks bridge matcher. Now a title can keep its ampersand ("Kaitlyn Schmit & Friends") and still match correctly. (The lookup-table builders for featured-flag/link resolution were intentionally left as-is to avoid regressing working behavior.) Cache buster 32.0.30. Files touched: style.css, functions.php (version only), data/schedule.php.

— v32.0.29 — FIX: an entertainer (e.g. "Kaitlyn Schmit & Friends") showing on the homepage + entertainer page but NOT on the schedule, while OTHER entertainers with the same setup do appear on the schedule. NOT the ampersand. Root cause: the schedule's _lbf_date_to_day_slug() required the entertainer day meta to be an EXACT YYYY-MM-DD string matching a festival date; the entertainer page (data/performers.php) tolerates loose formats and displays the entertainer regardless. So an entertainer whose day was stored loosely (e.g. "8/22/2026", "2026-8-22", "Aug 22, 2026", or a bare weekday like "Saturday") showed everywhere except the schedule, which dropped it (empty slug → skipped). Fix: _lbf_date_to_day_slug() is now tolerant — exact ISO match first, then strtotime() normalization to Y-m-d, then a weekday-name fallback (Thursday/Friday/Saturday/Sunday → the matching festival day). Verified against ISO, slash, no-leading-zero, written-date, and weekday-name inputs; still rejects empty/out-of-range/garbage. Also (defensive, from earlier in this fix) the schedule now reads _lbfc_ent_* with a fallback to _lbf_ent_* for day/time/stage/etc. in the inclusion loop, _lbf_normalize_entertainer, and the day-tab builder. Cache buster 32.0.29. Files touched: style.css, functions.php (version only), data/schedule.php.

— v32.0.28 — Corrected the schedule event→page slugs to match the ACTUAL published page slugs (the v32.0.27 map guessed wrong slugs for two of them). Car & Bike Show now → bike-and-car-show-page (was car-show); Blue Lights & Bubbles Parade now → blue-lights-and-bubble-parade (was blue-lights-bubbles-parade); Sunday Funday Parade (sunday-funday-parade) and Fireworks (fireworks) were already correct. Updated both the exact title map and the case-insensitive keyword fallback, and added a few extra keyword variants (bubble, bike & car, bike show). With these slugs, get_page_by_path() now resolves the published pages and the "View [event] →" links render on the schedule. Cache buster 32.0.28. Files touched: style.css, functions.php (version only), data/schedule.php (slug corrections).

— v32.0.27 — Schedule events Fireworks, Car & Bike Show, and both parades now link to their individual pages. The schedule already renders a "View [event] →" link when lbf_get_event_link_url() resolves a URL; its title→page slug_map had the parades, pageant, and car show but was MISSING fireworks. Added fireworks (with several title variants) mapping to the /fireworks/ page. Also added a case-insensitive keyword fallback (blue lights / bubbles / sunday funday / car & bike / car show / fireworks) so these signature events still link even if their title differs from the exact strings (e.g. "Grand Finale Fireworks", "Car & Bike Show 2026"). Each link only renders if a PUBLISHED page with that slug exists (fireworks, car-show, blue-lights-bubbles-parade, sunday-funday-parade). Cache buster 32.0.27. Files touched: style.css, functions.php (version only), data/schedule.php (slug_map + keyword fallback).

— v32.0.26 — Homepage hero green "Support The Festival" button now scrolls to the on-page #donate section at the bottom of the homepage (was /support-the-festival/). Changed the btn3 default URL to #donate (the existing donate anchor at the bottom of the sponsors section, which already has scroll-margin-top:120px). Added a dedicated smooth-scroll click handler for .v3-btn-hero-green so it scrolls smoothly with the sticky-header offset and is not affected by the inline editor url-key data attributes; if the button points anywhere other than #donate (e.g. a custom Customizer URL) the handler stays out of the way and normal link behavior applies. Note: if lbf_hero_btn3_url was saved in the Customizer it overrides this default — set it to #donate there if so. Cache buster 32.0.26. Files touched: style.css, functions.php (version only), front-page.php (btn3 default URL + scroll handler).

— v32.0.25 — Aug 8 "Miss Blueberry Pageant" mini-schedule card now links to /about-our-pageant/ (was /pageant/), and its hover label updated from "View Saturday\'s Full Schedule" to "Learn About the Pageant" to match the destination. The four festival-day cards (Thu/Fri/Sat/Sun) still deep-link to /schedule/?day=… with the v32.0.23 scroll-to-day behavior. Note: if a per-card link was saved via the inline editor for this card, that saved value still overrides this default. Cache buster 32.0.25. Files touched: style.css, functions.php (version only), front-page.php (Aug 8 card link + hover label).

— v32.0.24 — Reverted the Aug 8 "Miss Blueberry Pageant" mini-schedule card back to /pageant/ (per Tim — leave the pageant card alone). The schedule-scroll behavior from v32.0.23 is unchanged: the four festival-day cards (Thu/Fri/Sat/Sun) still deep-link to /schedule/?day=… and the schedule page now scrolls down to the selected day on load. Only the pageant card's link was reverted. Cache buster 32.0.24. Files touched: style.css, functions.php (version only), front-page.php (Aug 8 card link back to /pageant/).

— v32.0.23 — Homepage mini festival-schedule day cards now SCROLL to the day on the schedule page. The day cards link to /schedule/?day=thu (etc.) and the schedule page already selected the right day server-side, but the browser landed at the TOP of the schedule page — the active day was selected far below, unseen. Added an initial-load scroll in page-schedule.php: when the URL has a ?day= param, after load it smooth-scrolls to #s3-schedule-main (the day tabs), offset by the sticky header height. Only fires when ?day= is present, so a normal visit to /schedule/ is unaffected. Also pointed the Aug 8 "Miss Blueberry Pageant" mini-schedule card at /schedule/?day=sat-aug-8 (its real pageant day on the schedule) so all five day cards open their day on the schedule page consistently (was /pageant/). Per-card link overrides saved via the inline editor still win over this default. Cache buster 32.0.23. Files touched: style.css, functions.php (version only), page-schedule.php (init scroll), front-page.php (Aug 8 card link default).

— v32.0.22 — Removed the last hardcoded "Park National Bank" placeholder from page-sponsors-v2.php ($pres_name now defaults to empty, not the literal name). IMPORTANT FINDING: traced the sponsor data path end to end — lbf_get_sponsors_for_tier() in the LBF Content plugin returns ONLY real lbf_sponsor posts; it does NOT inject the tier "fallbacks" config. So a Park National Bank that still appears on the wall is a REAL published lbf_sponsor post in the database, not a theme/plugin default. To remove a duplicate: edit/delete the post at /wp-admin/edit.php?post_type=lbf_sponsor — look for either two Park National Bank posts, or one post tagged into two tiers (sponsor_tier taxonomy or _lbfc_spn_tier meta). The theme no longer contributes any phantom name. Cache buster 32.0.22. Files touched: style.css, functions.php (version only), page-sponsors-v2.php (removed fallback string).

— v32.0.21 — HOMEPAGE: sections now EXPANDED by default on mobile. The .v3-collapsible cards (Experience, Entertainers, Pageant, Sponsors) auto-collapsed on phones via if(isMobile) card.classList.add(v3-collapsed) in the front-page collapse script, plus a resize handler that re-collapsed them when crossing into mobile width. Removed both: sections now render expanded by default. The collapse chevron stays, so a visitor can still tap to collapse any section manually — it just no longer starts collapsed. (CSS already hides .v3-section-body only under .v3-collapsed, so with the class no longer auto-added, content shows.) Note: the separate .lbf-col-wrap/.lbf-col-toggle collapse system in main.v2.js is dead code — no template uses it — so it was left untouched. Cache buster 32.0.21. Files touched: style.css, functions.php (version only), front-page.php (collapse script).

— v32.0.20 — FIX: "Park National Bank" appearing twice on the sponsors page with no post behind it. Two independent causes in page-sponsors-v2.php data layer: (1) the sponsor WALL loop iterated ALL tiers including 'presenting', so the presenting sponsor rendered in BOTH the dedicated "Currently Presenting" hero card AND the wall grid = shown twice. The wall now SKIPS the presenting tier (continue) since the presenting sponsor has its own hero spotlight. (2) The hero presenting name had a hardcoded fallback: $pres_name = $presenting ? $presenting[name] : "Park National Bank" — so when no presenting sponsor post existed, the page invented "Park National Bank" as a placeholder. The hero "Currently Presenting" card is now wrapped in if($presenting), so it only renders when a real presenting sponsor post exists — no phantom placeholder. Net: presenting sponsor shows exactly once (hero only), and nothing shows if there is no presenting post. Note: if Park National Bank still appears in the wall, a real lbf_sponsor post tagged presenting exists at /wp-admin/edit.php?post_type=lbf_sponsor (the sponsor admin menu is hidden). Cache buster 32.0.20. Files touched: style.css, functions.php (version only), page-sponsors-v2.php (wall presenting-tier skip + hero card if($presenting) guard).

— v32.0.19 — SPONSORS PAGE CONTENT-HIDDEN-ON-MOBILE: DEFINITIVE FIX (visible by default). Line-by-line trace using the live rendered DOM proved: all sections + 58 sponsor tiles ARE in the DOM; the ONLY thing hiding them was opacity:0 from the .sv2-rv reveal animation, which the IntersectionObserver had only un-hidden for 2 of 9 sections (hero + stats). Root flaw: the reveal made content invisible BY DEFAULT and depended on JS to show it, so any observer/JS hiccup left sections hidden forever. Fixed by inverting the dependency: .sv2-rv is now opacity:1 (VISIBLE) by default in CSS. The hidden start-state only applies under body.sv2-js-reveal, a class the JS adds to <body> only when it is confirmed running. So: JS disabled or errors before reveal → class never added → sections simply visible (no animation, fully shown). JS present → arms animation, observer + first-paint check + 1.2s hard fallback animate them in. Hash landing → un-arms and reveals immediately. Reduced-motion → forced visible with !important. Content can no longer be hidden by any JS/observer/timing failure. Also: noted that page-mobile-fix.css contains stale sv2 rules (.sv2-tier-row/.sv2-pkg-grid/.sv2-hero-grid) targeting a PRIOR sv2 template; the current template (.sv2-wall/.sv2-impact) is fully covered by sponsors-v2.css own media queries, so the stale rules are harmless no-ops (left for a later cleanup). Cache buster 32.0.19. Files touched: style.css, functions.php (version only), assets/css/sponsors-v2.css (reveal default-visible + arming + reduced-motion), page-sponsors-v2.php (reveal JS arming + failsafe).

— v32.0.18 — FIX: SPONSORS PAGE CONTENT INVISIBLE ON MOBILE. The sponsors-v2 page reveals every section via an IntersectionObserver that adds .sv2-rv--in (sections start at opacity:0). If the observer didn't fire for a section on mobile, that section stayed permanently invisible — which is what hid the sponsors content. Made the reveal FAIL-SAFE: (a) a hard fallback reveals ALL sections after 1.2s and again 200ms after window.load, no matter what; (b) observer now uses threshold:0.01 + rootMargin so sections reveal slightly before entering view; (c) on first paint, any section already at/above the fold is revealed immediately; (d) the hash-landing pre-reveal path is unchanged. Net: nothing can stay hidden. Also hardened the v32.0.17 global mobile overflow guard — scoped it to body only (dropped html) and kept overflow-x:hidden, so it can't interact with any fixed/sticky positioning on inner pages. Cache buster 32.0.18. Files touched: style.css, functions.php (version only), page-sponsors-v2.php (reveal JS), assets/css/page-mobile-fix.css (guard scope).

— v32.0.17 — MOBILE AUDIT + ENTERTAINMENT HERO FIX. Full audit of all 44 templates for mobile-overflow patterns. Found and fixed: (1) ENTERTAINMENT HERO — the .lbf-bs-block "Presented By" sponsor block uses grid-template-columns:max-content with a width:100% Brightspeed SVG logo; on phones the max-content column blew out to the SVG's intrinsic width, overflowing the hero and pushing the layout sideways. Since page-entertainment.php is locked, the fix lives in page-mobile-fix.css: caps .lbf-bs-block to minmax(0,1fr) and .lbf-bs-logo to max-width:180px on <=767px, with a body-scoped !important selector to win over the template's inline <style>. (2) GLOBAL OVERFLOW GUARD — only the home page had body{overflow-x:hidden}; the other 43 templates had no document-level guard, so any single over-wide element could scroll the whole page sideways. Added html,body{overflow-x:hidden;max-width:100%} at <=767px in page-mobile-fix.css — intentional horizontal-scroll regions (schedule day strips, sponsor rows) are unaffected because they scroll on their own inner elements. Audit confirmed clean: all hero grids (contact, pageant, volunteer, sponsors-v2, car-show) collapse to single column via max-width media queries; no raw <table> elements; all fixed widths >=400px are decorative absolute-positioned glows/orbs clipped by overflow:hidden or capped by max-width; schedule pageant ticker column-stacks <600px; front-page tier logos re-constrained to 120x72 on mobile by home-mobile-fix. Cache buster 32.0.17. Files touched: style.css, functions.php (version only), assets/css/page-mobile-fix.css (entertainment hero block + global guard).

— v32.0.16 — THE ACTUAL FIX: HOMEPAGE SPONSOR BUTTONS NOW POINT AT THE LIVE SPONSORS PAGE'S REAL ANCHORS. Root cause finally identified from the live rendered HTML: the sponsors page (page-id-1707) renders from page-sponsors-v2.php (body class page-template-page-sponsors-v2), which uses sv2- prefixed section IDs — NOT page-sponsors.php (which is parked/unused and uses spn- IDs). Every prior fix targeted the wrong template, so the homepage buttons linked to #spn-wall / #spn-inquiry / #spn-inq-pills which DO NOT EXIST on the live page, meaning clicks scrolled nowhere. Fixed: homepage CTA buttons now link to #sv2-wall (sponsor wall), #sv2-inquiry (Start Your Sponsorship form), #sv2-impact (Choose Your Sponsorship Impact / levels) — all three confirmed present in the live rendered HTML. Also ported the hash-anchor landing fix (kill .sv2-rv reveal transitions + pre-reveal + scrollIntoView on window.load) into page-sponsors-v2.php and added scroll-margin-top:100px on the three sv2 targets in sponsors-v2.css so they land below the sticky header. Cache buster 32.0.16. Files touched: style.css, functions.php (version only), front-page.php (3 button hrefs), page-sponsors-v2.php (hash-landing JS), assets/css/sponsors-v2.css (scroll-margin block).

— v32.0.15 — HOMEPAGE PRESENTING-SPONSOR LOGO VERTICAL CENTERING. The OhioHealth logo in the homepage Presenting Sponsor card was sitting off-center (low) in its white box. Cause: the desktop rule in lbf-home-v3.css for .lbf-spd25-pres-logo used width:100% + height:100% + max-height:100px, which stretched the <img> element to fill the box and — combined with the intrinsic width/height attributes get_the_post_thumbnail() stamps on the tag — threw off vertical centering. Fixed by switching to width:auto + height:auto + max-height:96px + margin:auto (the same approach the mobile rules in home-mobile-fix.css already used correctly). Also applied the identical fix to the sponsors-page featured-partner logo panel (.spn-fp-logo-panel img) which had the same latent issue. Cache buster 32.0.15. Files touched: style.css, functions.php (version only), assets/css/lbf-home-v3.css (.lbf-spd25-pres-logo), assets/css/sponsors.css (.spn-fp-logo-panel img).

— v32.0.14 — ROOT-CAUSE FIXES: sponsor CTA buttons (removed orphaned data-lbfs-type editing attrs that let the inline editor hijack clicks for logged-in admins) + pageant ticker time (authoritative — strips any existing pageant entry, injects clean Sat, Aug 8 · 9:00 AM entry).

— v32.0.13 — Schedule pageant ticker + sponsors hash anchor (superseded by 32.0.14 for both — pageant time wasn't authoritative, buttons were being hijacked by the inline editor which this version didn't catch).

— v32.0.10 — HOMEPAGE SPONSOR CTA ROW: four buttons reduced to three (Sponsor Benefits removed), all --solid style, deep-linking to /sponsors/#spn-wall, #spn-inquiry, #spn-inq-pills.

— v32.0.9 — SCHEDULE PAGE: first version of Coming Up ticker pageant injection.

— v32.0.8 — FRONT PAGE SPONSORS: Bronze tier hidden, remaining tier logos bumped 15%.

— v32.0.10 — HOMEPAGE SPONSOR CTA ROW: UNIFIED STYLE + ANCHOR LINKS. Per Tim (with explicit one-time waiver on the front-page.php lock). The four CTA buttons below the sponsor tier grid (View All Sponsors / Become a Sponsor / Sponsor Levels / Sponsor Benefits) reduced to three: Sponsor Benefits removed entirely. The remaining three all use the --solid blue-purple gradient style (previously Sponsor Levels was a --ghost variant). Each button now scroll-deep-links to a specific section on /sponsors/ rather than landing on the page top: View All Sponsors → #spn-wall (sponsor logo wall), Become a Sponsor → #spn-inquiry (Start Your Sponsorship form), Sponsor Levels → #spn-inq-pills (tier picker with per-level helper text). sponsors.css adds scroll-margin-top:calc(var(--header-h,120px)+16px) on the three targets so the section lands below the sticky header instead of under it. Cache buster 32.0.10. Files touched: style.css, functions.php (version only), front-page.php (sponsor CTA row only, 16 lines), assets/css/sponsors.css (3-selector block appended).

— v32.0.9 — SCHEDULE PAGE: COMING UP TICKER INCLUDES PAGEANT WITH REAL DATE/TIME. The "Coming up" ticker beneath the festival countdown on /schedule/ now always shows the Blueberry Pageant entry first (Sat, Aug 8 · 9:00 AM · 2026 Miss Blueberry Pageant) while the pageant date is still in the future. Date pulled live from BPM (bpm_setting('pageant_date')); pageant name pulled from bpm_setting('pageant_name'). Falls back to canonical August 8, 2026 + 2026-derived name if BPM settings aren't configured yet. Skips injection if a pageant item is already in $cd_ticker from the schedule manager (no duplicate). Auto-disappears once the pageant date has passed (with 6-hour grace window so it stays visible through pageant morning). Cache buster 32.0.9. Files touched: style.css, functions.php (version only), page-schedule.php.

— v32.0.8 — FRONT PAGE SPONSORS: HIDE BRONZE TIER + BUMP REMAINING LOGOS 15%. Per Tim. Bronze tier (data-tier-idx="4" / .tier-label.tf) hidden from the homepage sponsor grid via CSS-only display:none in homepage-polish.css — the underlying tier data, /sponsors page, and admin tool are unchanged so bronze sponsors remain managed normally and still appear publicly on the sponsor page. Presenting (sp-xl), Platinum (sp-lg), Gold (sp-md), and Silver (sp-sm) tier-card heights bumped ~15% (Presenting 72→83px + width 180→207px, Platinum 72→83px, Gold 56→64px, Silver 46→53px) along with proportional padding/font-size increases so logos read more clearly. front-page.php intentionally untouched (locked file); the change is achieved entirely through CSS overrides loaded after lbf-home-v3.css. Cache buster 32.0.8. Files touched: style.css, functions.php (version only), assets/css/homepage-polish.css.

— v31.2.43 — ENTERTAINMENT PAGE: REMOVED ANT-LIKE SVG PULSES FROM SECTIONS 2 + 3. The traveling-pulse SVG layer added in v31.2.42 to the card grid and dark band looked like ants marching due to dasharray distortion from preserveAspectRatio=none stretching. Removed entirely: .lbf-section-fiber-pulse CSS rules + the SVG markup blocks from both .lbf-section-wrap--grid and .lbf-section-wrap--dark. The CSS gradient shimmer ring (.lbf-section-wrap::before with the lbf-fiber-shimmer animation) is retained on both sections as the always-on subtle border treatment. Hero is fully untouched, still has its dasharray=120 pulses guaranteeing two visible at all times. Cache buster 31.2.43. Files touched: style.css, functions.php (version only), page-entertainment.php.

— v31.2.42 — ENTERTAINMENT PAGE: TRAVELING PULSES ON SECTION RINGS + HERO PULSE LENGTH BUMP. Per Tim. (1) Hero pulse stroke-dasharray bumped 60 -> 120 so each visible pulse dash lingers at any spot twice as long, guaranteeing two pulses are always clearly on-screen at the same time (the two pulses are exactly half a cycle apart on a 14s loop, so they're always ~diagonally opposite on the circuit). (2) Added real SVG traveling pulses on top of the existing CSS shimmer ring for the card grid and dark band sections. New .lbf-section-fiber-pulse layer sits inset:-3px over the section, contains a small SVG using viewBox=100x100 + preserveAspectRatio=none + vector-effect:non-scaling-stroke + pathLength=100 so the stroke width and pulse length stay consistent regardless of how the SVG is stretched to fit the section's actual dimensions. The path traces a rounded rect perimeter normalized to pathLength=100, so stroke-dasharray:4 100 = one visible 4-unit pulse per 100-unit perimeter. (3) Each section gets 2 pulses on its perimeter, offset by half a cycle (-7s on grid's 14s, -8.5s on dark's 17s). Different cycle speeds per section so they don't visually sync. (4) The CSS gradient shimmer ring underneath is retained as the always-on perfect-shape base (Tim asked to keep it). The SVG pulse layer sits on top at z-index:3 so the moving gold dots ride along the ring. Slight elliptical-corner distortion in the SVG layer is hidden by the perfectly-shaped CSS ring beneath and the glow of the pulse dot. (5) Reduced-motion guards on both layers. Cache buster 31.2.42. Files touched: style.css, functions.php (version only), page-entertainment.php.

— v31.2.41 — ENTERTAINMENT PAGE: SECTION RINGS REBUILT WITH CSS PSEUDO-ELEMENTS. v31.2.40's SVG-based rings on the card grid and dark band were misaligned because the SVG used viewBox 1000x500 with preserveAspectRatio=none stretched to fill wrappers of vastly different aspect ratios than the hero. The 22px rx rounded corners became flattened ellipses that bulged way past the actual section's 22px border-radius, especially on the tall card grid section. Replaced both section's SVG fiber frames with a CSS pseudo-element approach: .lbf-section-wrap::before is positioned inset:-3px with border-radius:25px (matches the section's 22px + 3px offset) and uses padding + mask-composite:exclude to render only a 1.5-1.7px gradient border around the actual section perimeter. The gradient is 300% sized and animated via background-position shift over 14s (grid) / 18s (dark band) for a subtle traveling-light shimmer effect. This guarantees the ring perfectly traces the section's actual shape regardless of section height. SVG markup removed from both wrapper divs (no longer needed). Hero treatment is fully untouched. Reduced-motion guard retained. Cache buster 31.2.41. Files touched: style.css, functions.php (version only), page-entertainment.php.

— v31.2.40 — ENTERTAINMENT PAGE: REVERTED TO OPTION A (CLEAN). v31.2.39's Option C connectors looked sloppy in the gaps between sections. Ripped them out entirely. Card grid + dark band now each have their own INDEPENDENT fiber ring with their own 2 pulses circulating, no connectors between sections, no shared gradient IDs (each SVG has its own <defs> block). Hero treatment is fully untouched and continues to work as before (feeders into icon + 2 pulses on continuous circuit). Card grid ring: 18s cycle, 2 pulses half-cycle apart. Dark band ring: 22s cycle (slightly different speed so the two sections don't sync visually), 2 pulses half-cycle apart, slightly brighter ring (1.7 stroke, .85 opacity) so it reads against the dark photo background. All reduced-motion guarded. Cache buster 31.2.40. Files touched: style.css, functions.php (version only), page-entertainment.php.

— v31.2.39 — ENTERTAINMENT PAGE: FIBER EXTENDED TO CARD GRID + DARK BAND (Option C). Per Tim. The Brightspeed fiber treatment now spans the entire entertainment page as one connected circuit. (1) Card grid section wrapped in .lbf-section-wrap--grid with its own gold fiber ring (1.5 stroke, opacity .7, drop-shadow glow) traced around the outside of the rounded rect (rx=22 matching the section's border-radius), with 2 pulses circulating it on a 28s cycle (half-cycle apart). (2) Dark band section wrapped in .lbf-section-wrap--dark with same ring but slightly thicker/brighter (1.7 stroke, opacity .85) so it reads against the dark photo background, also with 2 pulses 28s cycle half-cycle apart. (3) Two .lbf-fiber-connector blocks placed between hero->card-grid and card-grid->dark-band: each renders short vertical fiber lines at x=26 and x=974 (matching the left/right ring positions) with their own gold pulses on a 7s cycle, offset between the two connectors. (4) Six pulses total visible on the page at any moment (2 hero + 2 grid + 2 dark + connector pulses), staggered with -4s/-9s/-18s/-23s delays so motion is always somewhere on the page. (5) Each section's SVG is independent (preserves rounded corners no matter the section height — no global viewBox stretch warping). The gradient #lbf-fiber-grad-sec is defined in the first SVG and referenced by the others via stroke attribute fallback so paths still render even if browsers don't share gradient defs across SVG roots reliably. (6) All reduced-motion guarded. Cache buster 31.2.39. Files touched: style.css, functions.php (version only), page-entertainment.php.

— v31.2.38 — ENTERTAINMENT HERO: FIBER NOW ONE CONTINUOUS CIRCUIT. Per Tim. The two feeder lines into the Brightspeed icon are now purely static glowing power cables with NO pulse on them. The pulse is one continuous flow on a single circuit path: starts at the icon end of the BOTTOM feeder (45,112), travels LEFT to the ring (4,112), DOWN the left edge of the ring, CLOCKWISE around the full perimeter, returns at the top-feeder ring end (4,88), and travels RIGHT back INTO the icon (45,88). Two gold pulses share that same continuous path, offset by half a cycle (-7s delay on the second), so the ring always has movement somewhere on it. 14s per full circuit. Reduced-motion guards retained. Cache buster 31.2.38. Files touched: style.css, functions.php (version only), page-entertainment.php.

— v31.2.37 — ENTERTAINMENT HERO: FIBER RING REPAIRED + LOGO PROPERLY SIZED TO EYEBROW. Per Tim. (1) v31.2.36 incorrectly broke the outer rectangle apart and routed branch curves into the logo; Tim wanted the ring left SOLID and unbroken. The fiber is now back to a single solid rounded rectangle (rx=22) traced around the outside of the hero with no gap. (2) Two short horizontal FEEDER lines (.lbf-fiber-feeder) branch off the left edge of the ring at y=88 (top) and y=112 (bottom) and run straight rightward to terminate cleanly at the Brightspeed icon's left edge at x=45. Feeders are thicker (2.5 stroke) and brighter (opacity .9) than the ring (1.5 stroke, opacity .7) so they read as the active power lines into the icon. (3) THREE pulses now circulate: gold #ffca0b loops the full ring continuously (12s cycle, so the ring always feels alive); red-orange #f04b2d travels INBOUND on the top feeder (ring -> icon, 3.6s); orange #f4762b travels OUTBOUND on the bottom feeder (icon -> ring, 3.6s, -1.8s delay so it's offset). All Brightspeed brand colors. (4) Logo block: the Brightspeed logo and the LEXINGTON BLUEBERRY FESTIVAL ENTERTAINMENT eyebrow pill now share the SAME grid column (display:grid; grid-template-columns:max-content), so the column auto-sizes to the eyebrow's natural rendered width and the logo (width:100%) fills exactly that width. No more hardcoded 300px guess. PRESENTED BY label sits above the logo. Stack order: Presented By -> logo -> eyebrow pill. (5) Reduced-motion guards retained. Cache buster 31.2.37. Files touched: style.css, functions.php (version only), page-entertainment.php.

— v31.2.36 — ENTERTAINMENT HERO: FIBER NOW CONNECTS INTO THE BRIGHTSPEED ICON + LOGO BLOCK RESTRUCTURED. Per Tim. (1) Logo block: added small 'Presented By' label above the Brightspeed logo (Barlow Condensed 800, .62rem, .22em tracking, blue), logo width fixed at 300px so it visually pairs with the 'LEXINGTON BLUEBERRY FESTIVAL ENTERTAINMENT' eyebrow pill below it (240px on mobile). New .lbf-bs-block flex column wraps the presented-by + logo together; eyebrow pill stays below as its own element. (2) Fiber circuit physically connects to the Brightspeed icon now instead of looping in a closed rectangle. The fiber is ONE continuous path: starts at the icon hub at ~(70,80) in the hero viewBox, sweeps UP and OUT via a right-side branch (Bezier curve) to break the top edge at (100,4), runs CLOCKWISE around the full outer rounded rectangle (rx=22 matching the hero border-radius), and returns at (40,4) via a left-side branch (matching Bezier) back DOWN into the icon. The top edge of the rectangle is broken between x=40 and x=100, so the rectangle visibly opens above the icon where the branches drop in. (3) Branches use a thicker stroke (2.5 vs 1.5) and higher opacity (.85 vs .7) per Tim's request so they read as the active part of the circuit. (4) Two pulses now circulate the same continuous path in opposite directions and occasionally cross on the far side: OUTBOUND gold pulse (#ffca0b, 12s clockwise) leaves the icon, runs all the way around, returns to the icon; INBOUND red-orange pulse (#f04b2d, 13s counter-clockwise, -2s delay) leaves the icon the other way and circles back. Both use the Brightspeed brand colors. (5) Reduced-motion guards retained. Cache buster 31.2.36. Files touched: style.css, functions.php (version only), page-entertainment.php.

— v31.2.35 — ENTERTAINMENT HERO: FIBER MOVED OUTSIDE + CLEAN LOGO. Per Tim. (1) The dark Brightspeed lockup card + 'PROUDLY POWERED BY' label are gone. The Brightspeed Fiber SVG logo now sits clean against the white hero (.lbf-bs-logo, no card, no label), 32-38px tall, centered to the left and positioned just above the existing eyebrow pill. The SVG's native black + warm fiber colors show properly against the white background now (it looked wrong inside the dark card). (2) Fiber treatment rebuilt: instead of 4 inside-lip strands, there's now ONE single strand tracing the OUTSIDE of the hero card's rounded corners (a precise rounded-rect path with rx=22 to match the hero border-radius, traced as a closed loop from top-center clockwise). (3) Two SLOW pulses travel along it: one INBOUND moving toward the logo (gold #ffca0b, 10s loop) and one OUTBOUND moving away from the logo (red-orange #f04b2d, 11s loop, -3s offset). Both ~3x slower than the previous fiber and stagger naturally. (4) Structural: hero now wrapped in new .lbf-hero-wrap with 6px padding; .lbf-fiber-frame is a sibling of .lbf-hero (not a child), so the hero's overflow:hidden no longer clips the fiber. The .lbf-ent-shell wrapper still provides outer clipping which is fine and looks intentional. (5) Reduced-motion guards retained. Cache buster 31.2.35. Files touched: style.css, functions.php (version only), page-entertainment.php.

— v31.2.34 — BRIGHTSPEED FIBER SPONSOR INTEGRATION + GLOBAL MAIN STAGE RENAME. New sponsor Brightspeed Fiber is the title sponsor of the renamed Brightspeed Stage (formerly Main Stage). (1) Saved sponsor logo at assets/images/sponsors/brightspeed-fiber.svg. (2) Entertainment page hero (page-entertainment.php) rebuilt with a fiber-optic light treatment: a full-coverage SVG (.lbf-fiber-svg, position:absolute inset:0, z-index:1) traces 4 paths along the inside lip of the hero rectangle that all converge into the Brightspeed lockup at top-left (~95,75). Each track gets a soft gold-orange-red linear gradient stroke (#ffca0b -> #f4762b -> #f04b2d) with drop-shadow glow. Each track is paired with a bold animated pulse path (stroke 3.5, dasharray 28 1000, drop-shadow blur, lbf-fiber-flow keyframe shifting stroke-dashoffset -1028 over 3.4-5s with staggered delays and color variants gold/orange/red). Lines stay subtle behind the rotating photo panel (right side untouched, lbf-hero-left given z-index:2 to sit above the fiber svg). (3) New .lbf-bs-lockup component sits at the top of the hero left: dark gradient background (#18120c -> #0d0a08), gold border with soft glow, subtle lbf-bs-pulse animation (2.8s ease-in-out), 'PROUDLY POWERED BY' eyebrow in Barlow Condensed 800 gold, Brightspeed logo 26-30px tall. Existing eyebrow + h1 + sub + pills + buttons kept. (4) Page title fallback changed: 'Main Stage Energy' -> 'Live on the Brightspeed Stage' (still overridable via _lbf_ent_page_title meta). (5) All reduced-motion guarded. (6) GLOBAL RENAME: every 'Main Stage' -> 'Brightspeed Stage', 'main stage' -> 'Brightspeed Stage', 'MAIN STAGE' -> 'BRIGHTSPEED STAGE' across all theme PHP files (22 files affected including page-entertainment, page-schedule, page-attractions, page-family-attractions, page-car-show, page-sponsors, page-sponsors-v2, page-press, page-fireworks, page-pageant-rules, page-volunteer, page-map, page-rides-and-games, page-waiver, page-faq, page-about, page-template-pageant-overview, page-template-contestant-guide, page-pageant-process, page-blue-lights-bubbles-parade, inc/pageant-v4.php, data/schedule.php). All matches are visible body copy; no CSS classes or slugs affected. All touched files lint clean. Cache buster 31.2.34. Files touched: style.css, functions.php (version only), page-entertainment.php, plus the 22 PHP files for the rename, plus the new sponsor logo asset.

— v31.2.33 — QUEEN CITY STUNT CIRCUS PAGE: AFTER DARK HEADLINE COPY. Changed the After Dark section H2 from 'Fire, and a whole lot of glow' (wrapped awkwardly) to 'Real fire. Real glow.' with 'Real glow.' in the teal/red-glow emphasis em. Tighter, balanced, and ties to the 'none of that frozen stuff' real-fire angle. Cache buster 31.2.33. Files touched: style.css, functions.php (version only), page-queen-city-circus.php.

— v31.2.32 — QUEEN CITY STUNT CIRCUS PAGE: REMOVED HERO PARALLAX. The #1 hero parallax + mouse-depth effect added in v31.2.31 wasn't working well (jittery), so it was removed entirely: the scroll-driven heroInner translateY + backgroundPositionY easing and the mousemove sun/ring/title drift are all gone. The hero is back to its stable static layout with just the staggered entrance. All other v31.2.31 additions are retained: ember cursor trail in dark sections, confetti on card flip, and easter eggs E2 (title bow), E3 (type 'fire'), E5 (clown nose), E6 (lightbox triple-click spin). Cache buster 31.2.32. Files touched: style.css, functions.php (version only), assets/js/queen-city-circus.js.

— v31.2.31 — QUEEN CITY STUNT CIRCUS PAGE: PARALLAX + EMBER TRAIL + FLIP CONFETTI + 4 EASTER EGGS. New delight layer, all reduced-motion guarded, all in assets/js/queen-city-circus.js + supporting CSS. (1) HERO PARALLAX + MOUSE DEPTH: on scroll the hero inner content drifts up slower than the photo (translateY * .18) and bg-position-y eases, for depth; on mousemove the sunburst and star-ring drift opposite the cursor and the title shifts subtly (hover devices only). (3) FIRE-EMBER CURSOR TRAIL: moving the mouse through any dark section (.qc-night/.qc-cta/.qc-divider/.qc-slider-sec/.qc-roam/.qc-meet/.qc-when) sheds small glowing embers (gold/orange/red/teal) that rise and fade; throttled to ~28ms. (9) CONFETTI ON CARD FLIP: flipping an act card to its back fires a small confetti burst from the card's x-position via a new reusable global qcConfetti(count,originX) helper (fixed .qc-confetti-global layer appended to body). EASTER EGGS: E2 click the hero title 5x within 1.5s -> title takes a bow (qc-bow keyframe) + 90-piece confetti. E3 type 'fire' anywhere -> 60 embers erupt from the bottom of the screen and rise (Web Animations API). E5 a hidden clown nose (.qc-nose, small red ball) tucked bottom-right of the divider section -> click it to honk (scale pop) and show a 'HONK! 🤡' toast. E6 while the lightbox is OPEN, triple-click the photo -> it does a 360 spin (scoped to the lightbox image so it never conflicts with the single-click-to-open behavior). Cache buster 31.2.31. Files touched: style.css, functions.php (version only), page-queen-city-circus.php (CSS), assets/js/queen-city-circus.js.

— v31.2.30 — QUEEN CITY STUNT CIRCUS PAGE: COPY + SPACING + CONTRAST + PARTICLE VISIBILITY. Per Tim. (1) Removed 'all day' from the hero ticket times: 'Two shows & roaming all day' -> 'Two shows & roaming' (they roam but not all day; the ticker/marquee 'Roaming All Weekend' kept since that is accurate). (2) Hero photo overlay lightened again (was .08->.32, now 0->.18) so the hero image reads brighter. (3) Background particles were invisible in the upper (light cream/paper) half because faint light-colored dots wash out on light backgrounds; now in the upper half (scroll progress <0.45) dots use deeper saturated tones (deep teal 10,107,120 / festival blue 0,55,167 / dark gold 184,134,11) at higher opacity (.45-.80) so they read against cream, while the lower dark half keeps brighter dots (.45-.85). (4) Container moved up tight to the menu: .qc-canvas top padding gap reduced from header+1.25rem to header+0.3rem (and matching admin-bar rules). (5) Hero badge 'NEW FOR 2026 - TWO DAYS ONLY' was hard to read (Special Elite typewriter at .72rem with .22em tracking); switched to Barlow Condensed 800 at .92rem with tighter .1em tracking for legibility. (6) Credit line spacing: added margin-bottom:3rem to .qc-cta__btns and set credit margin-top to 2rem so there is a clear gap between the buttons and the credit line. Cache buster 31.2.30. Files touched: style.css, functions.php (version only), page-queen-city-circus.php, assets/js/queen-city-circus.js.

— v31.2.29 — QUEEN CITY STUNT CIRCUS PAGE: DIVIDER, FLIP, PARTICLES, MARQUEE BADGE, SPACING. Per Tim. (1) Divider section (the sunset 'festival lights up' band): removed the .qc-divider__sun glowing orb entirely (it sat over the performer and read as a yellow blob). Made the section taller (min-height clamp 360-520px -> 520-760px) and moved the bg image down (center 40% -> center 18%) so the performer's face/upper body shows instead of the torso. (2) Act flip cards: removed the :hover flip trigger, now flip on CLICK/tap (and keyboard focus) only, no more twitchy mouseover flipping. (3) Background particle field: cap 130 -> 240, spawn 130ms -> 80ms, seed 40 -> 70; opacity lowered from .70-1.0 back down to .30-.60 (denser but fainter, the haze-of-light look Tim wanted); glow halo trimmed slightly to match. ALSO changed .qc-bg-field from position:fixed (full viewport, bled into footer) to position:absolute inside #lbf-qcsc so it physically cannot extend into the site footer; dots now spawn in page coordinates within the current viewport band and are clamped to stop 40px short of the field bottom. (4) Replaced the broken fanned 'ADMIT ONE' tickets at the CTA with a circus marquee starburst badge (.qc-marquee-badge): a slow-spinning gold star (drop-shadow glow), a ring of 12 blinking lightbulbs, and a teal/navy center disc with a gold star, all built from existing qc-spin + qc-blink keyframes. (5) Credit line spacing: margin-top 3.4rem -> 5rem so it clears the buttons. Cache buster 31.2.29. Files touched: style.css, functions.php (version only), page-queen-city-circus.php, assets/js/queen-city-circus.js.

— v31.2.28 — QUEEN CITY STUNT CIRCUS PAGE: PARTICLES CRANKED + HERO/CTA POLISH. Per Tim. (1) Background particle field was too faint: cap 26->130, spawn 520ms->130ms, seed 8->40, peak opacity .22-.52 -> .70-1.0, glow halo fattened (blur 10+size*2.5, spread=size), colors saturated (day electric teal 60,225,255; sunset hot orange 255,140,30; night bright gold 255,200,0), speed 7-14s -> 5-10s, more horizontal drift. Same small dot size per request. (2) Act flip cards now have full body copy on the back (2-3 sentences each instead of one line); back face got overflow-y:auto and slightly smaller type (.86rem body, 1.4rem title) so longer copy fits. (3) Hero tickets gap 1rem -> 2.2rem for breathing room. (4) Hero dark overlay lightened (top .18->.08, bottom .5->.32) so the photo shows brighter. (5) CTA bottom fan tickets rebuilt stronger: bigger (172x96 vs 150x78), wider fan spread (22deg + translate), gradient fill, fatter shadows, punch-hole notch ::before/::after detail, center ticket gold-accented. (6) Credit line forced to one line (white-space:nowrap, wraps on mobile) with more space above (margin-top 2.2rem -> 3.4rem). Cache buster 31.2.28. Files touched: style.css, functions.php (version only), page-queen-city-circus.php, assets/js/queen-city-circus.js.

— v31.2.27 — QUEEN CITY STUNT CIRCUS PAGE: AMBIENT BACKGROUND PARTICLE FIELD (SCROLL-MORPHING). Added a full-page ambient particle layer behind the holding card that smoothly morphs color with scroll position, reinforcing the day-to-night arc. NEW .qc-bg-field: position:fixed; inset:0; z-index:0 (behind #lbf-qcsc which is z-index:2); pointer-events:none so it can never intercept clicks (the lightbox lesson). Dots rise slowly (7-14s) via qc-bg-rise keyframe. JS (in assets/js/queen-city-circus.js) spawns one dot every ~520ms, hard-capped at ~26 live dots, and computes scroll progress 0->1 each spawn; colorFor() linearly blends a 3-stop palette: daytime teal-sky (120,205,225) -> sunset gold-orange (245,170,70) -> night gold spark (243,195,3), with occasional white motes in the day zone and teal sparks in the night zone for contrast. Subtle by design: peak opacity 0.22-0.52. To make the field faintly visible THROUGH the content (not just in the page margins), the card and its sections were given slight transparency: .qc-outer background rgba(255,253,247,.93), .qc-pocket cream layer .88, .qc-acts .86, and the three dusk/night sections (.qc-slider-sec, .qc-roam, .qc-meet) gradients dropped to ~.93 alpha. Auto-disabled at <=760px (mobile perf) and under prefers-reduced-motion. Cache buster 31.2.27. Files touched: style.css, functions.php (version only), page-queen-city-circus.php (bg-field CSS + markup + section transparency), assets/js/queen-city-circus.js (scroll-morphing spawner).

— v31.2.26 — QUEEN CITY STUNT CIRCUS PAGE: THE ACTUAL BUG. INVISIBLE LIGHTBOX WAS EATING EVERY CLICK. After repeated reports that NOTHING interactive worked (slider, flips, buttons, particles) across v31.2.22-25, ran a live in-console diagnostic on the page. Results: wrapper present, queen-city-circus.js loaded (confirmed ?ver=31.2.25 URL), script RAN (data-qc-init set), slider/lightbox/act-card elements all present. But document.elementFromPoint(viewport-center) returned <div#qc-lightbox> — the full-screen lightbox overlay (position:fixed; inset:0; z-index:99999) was sitting on TOP of the entire page and intercepting every pointer event, so clicks/drags never reached the cards, slider, or buttons underneath. The closed-state CSS used opacity:0 + visibility:hidden, but with a transition on visibility the element stayed hit-testable, and critically it never had pointer-events:none, so it blanketed the page. THE FIX (one line, the real one): added pointer-events:none to the base .qc-lightbox rule and pointer-events:auto to .qc-lightbox.is-open. The overlay now ignores clicks when closed and only captures them when actually open. This is why every prior fix (DOM-ready guard, externalizing the JS, moving the enqueue to inc/enqueue.php) appeared to do nothing: the JS was working the whole time, but the invisible overlay swallowed all interaction. Those prior fixes were still correct improvements (the JS now loads via the proven pipeline) and are retained. Cache buster 31.2.26. Files touched: style.css, functions.php (version only), page-queen-city-circus.php (lightbox pointer-events).

— v31.2.25 — QUEEN CITY STUNT CIRCUS PAGE: MOVED JS ENQUEUE TO inc/enqueue.php (REAL FIX FOR DEAD INTERACTIVITY). v31.2.24 externalized the QCSC interactive JS to assets/js/queen-city-circus.js but enqueued it from a wp_enqueue_scripts closure INSIDE the page template file (page-queen-city-circus.php). Interactivity was still dead live. Root cause confirmed by re-reading inc/enqueue.php: this theme/host has a documented production quirk (see the car-show block comment, v29-era) where inline body-level <style>/<script> is suppressed AND all page-scoped assets are reliably loaded only from the central lbf_enqueue() function in inc/enqueue.php, matched via is_page_template(). The per-template wp_enqueue_scripts closure was not reliably firing/being served under WP Super Cache. FIX: removed the wp_enqueue_script call from page-queen-city-circus.php and added the QCSC script enqueue to inc/enqueue.php inside lbf_enqueue() (the function hooked at line 346), immediately after the car-show-page-v2.js block, using the identical proven pattern: is_page_template('page-queen-city-circus.php') guard, get_template_directory_uri().'/assets/js/queen-city-circus.js', deps array(), LBF_THEME_VERSION cache-buster, true (footer). The fonts stylesheet enqueue stays in the page template (unchanged). No feature/markup/CSS logic changed. IMPORTANT: after upload, PURGE WP SUPER CACHE (Delete Cache) and hard-refresh. Cache buster 31.2.25. Files touched: style.css, functions.php (version only), page-queen-city-circus.php (removed the in-template script enqueue), inc/enqueue.php (added QCSC script enqueue in lbf_enqueue()).

— v31.2.24 — QUEEN CITY STUNT CIRCUS PAGE: JS EXTERNALIZED TO BEAT WP SUPER CACHE. The interactive features (slider, flip cards, particles, sticky CTA, lightbox) were proven to work in the rendered HTML export (particles spawning as live spans, slider handle JS-positioned at left:50%, day-image clip-path JS-set, data-qc-init flag set, all sections is-in) yet Tim reported clicks/drags doing nothing on the LIVE page. Root cause: the site runs WP Super Cache (admin bar shows Maintenance On / Delete Cache / Purge Current Page; 58 cache refs in the render) which serves static HTML snapshots, and the fragile inline <script> combined with aggressive page caching meant stale/mangled script delivery to visitors. FIX: moved the entire inline IIFE out of page-queen-city-circus.php into a new external file assets/js/queen-city-circus.js and enqueued it via wp_enqueue_script('lbf-qcsc', .../assets/js/queen-city-circus.js, [], LBF_THEME_VERSION, true) inside the existing is_page_template('page-queen-city-circus.php') guard in functions block. Loading in the footer (true) plus the file's own DOMContentLoaded guard and retry safety-net means it binds reliably; and because the asset URL now carries ?ver=LBF_THEME_VERSION, every version bump cache-busts it past both WP Super Cache and the browser. No feature logic changed. IMPORTANT: after upload, PURGE WP SUPER CACHE (Delete Cache) and hard-refresh, or the stale cached page will persist. Cache buster 31.2.24. Files touched: style.css, functions.php (version + new enqueue is inside the page template), page-queen-city-circus.php (inline <script> removed, wp_enqueue_script added), assets/js/queen-city-circus.js (NEW, ~290 lines, the full interactive IIFE).

— v31.2.23 — QUEEN CITY STUNT CIRCUS PAGE: REMOVED STAT BAND. Tim asked to remove the count-up stat band (2 performers / 30 min / 4 shows / 100% real fire) that sat between the Pocket-Sized explainer and The Acts. Removed all three pieces: the .qc-stats markup section, the COUNT-UP STAT BAND CSS block (.qc-stats, .qc-stats__grid, .qc-stat__num, .qc-stat__label), and the Count-up stats JS block (the IntersectionObserver + requestAnimationFrame ticker). The Pocket-Sized section now flows directly into The Acts. No other features touched. Cache buster 31.2.23. Files touched: style.css, functions.php (version only), page-queen-city-circus.php.

— v31.2.22 — QUEEN CITY STUNT CIRCUS PAGE: INTERACTIVITY NOT FIRING ON LIVE PAGE (DOM-READY FIX). Tim reported that on the live page NONE of the interactive features worked: slider, card flips, particles, button clicks, lightbox. Pulled the rendered HTML export and inspected: the inline IIFE script and all CSS were present and the script was syntactically valid (node -c passed), and in a clean browser save the scroll-reveal had even applied is-in to all 10 sections and qc-entered to the hero, proving the script CAN run. The most likely live-page cause: the page's inline <script> ran with the QCSC DOM not yet available (or the script was relocated/deferred by a JS optimizer/caching layer), so the very first line var root=document.getElementById('lbf-qcsc'); returned null and the guard if(!root)return; silently bailed before binding ANY listeners, which matches the all-or-nothing symptom (slider + flips + clicks all dead at once). FIX: the entire IIFE body was wrapped in a named qcInit() function that is now invoked on DOMContentLoaded when document.readyState==='loading', or immediately if the DOM is already parsed, plus a setInterval safety-net (100ms x up to 40 tries) that retries qcInit() if #lbf-qcsc is not yet in the DOM at first run (covers deferred/late render). A root.dataset.qcInit guard prevents double-initialization. No feature logic changed; this is purely a binding-timing/robustness fix so the listeners attach regardless of where/when the script executes. Cache buster 31.2.22. Files touched: style.css, functions.php (version only), page-queen-city-circus.php.

— v31.2.21 — QUEEN CITY STUNT CIRCUS PAGE: CROP FIXES + SLIDER FIX + 8 INTERACTIVE FEATURES + PARTICLES. Major interactivity pass on page-queen-city-circus.php. CROP FIXES: every image frame matched to the photos' actual aspect ratios (21 of 24 are portrait 4:5, 02/03/13 square, 23 landscape). After Dark grid was a tall-fig + 2-stack layout that stretched/cropped portraits; flattened to three equal 4/5 figs with object-position center 35%. Meet warm images were forced to 5/4 landscape on portrait photos; changed to 4/5 with object-position center 30%. Roaming cards already 3/4; added object-position center 28%. Pocket big got object-position center 30%. SLIDER FIX: the before/after day-night wipe wasn't visibly working because the day image had no default clip (so it fully covered the night image until JS ran in exactly the right spot); added a static clip-path:inset(0 50% 0 0) default in CSS so it shows half-and-half on load regardless of JS, plus webkit prefix. EIGHT FEATURES ADDED: (1) hero entrance, hero inner children stagger-fade-and-rise on load via .qc-entered class. (2) count-up stat band (.qc-stats) between pocket and acts, four stats (2 performers, 30 min, 4 shows, 100% fire) that tick up from zero on scroll-in via IntersectionObserver + requestAnimationFrame easing. (3) marquee ticker strip (.qc-ticker) before roaming, single clean scrolling row, pauses on hover. (4) act cards converted from hover-reveal banners to 3D flip cards (.qc-flip / .qc-face front+back), flip on hover (desktop) and tap/click/Enter (touch+a11y); old ::before/::after/__txt/__b banner internals removed, overflow:hidden dropped so the flip isn't clipped. (5) photo hover-glow + scale on all .qc-zoomable images. (6) animated lightbulb-string runner divider styles (.qc-runner). (7) ignite effect, After Dark figs start dimmed (brightness .55) and brighten to full on scroll-in via .qc-lit. (8) sticky mini CTA (.qc-sticky), a Showtimes pill that docks bottom-right after the hero scrolls out of view. PARTICLES: per-section contained particle systems (.qc-particles) in hero (teal + warm sparks), divider (sunset embers), After Dark (gold/red/teal embers), and CTA finale (teal/gold/white shimmer). Each spawns only while its section is on screen (IntersectionObserver), capped, pointer-events:none, z-index below content, and fully disabled under prefers-reduced-motion. The old tilt JS on act cards was removed (flip replaces it). All animation features have reduced-motion guards. Cache buster 31.2.21. Files touched: style.css, functions.php (version only), page-queen-city-circus.php.

— v31.2.20 — QUEEN CITY STUNT CIRCUS PAGE: DAY-TO-NIGHT REWORK + PHOTO REMAP + COPY. Continued work on page-queen-city-circus.php (the Queen City Stunt Circus performer page, template slug queen-city-circus). FOUR changes. (1) DAY-TO-NIGHT, REBUILT SAFELY: the previous scroll-driven implementation used a position:fixed full-viewport overlay (.qc-sky) with opacity driven by a scroll listener; it covered content and caused a dark band plus disappearing sections. That whole system (the fixed overlay, the twinkling stars, and the roaming performer SVG silhouettes that drifted between sections, plus the scroll JS) was removed in v31.2.x prior and is now replaced by a structural approach: the page background (body.page-template-page-queen-city-circus) is a single tall vertical linear-gradient running bright sky at top through warm sunset mid into deep night at bottom, background-attachment:scroll so it maps to page position and reads as the day passing as you scroll. No overlay, no scroll JS, nothing that can mask content. To make the arc read through the card too, the back-half sections were recolored into dusk/night tones: .qc-slider-sec, .qc-roam, and .qc-meet went from cream/paper light backgrounds to dark gradient backgrounds with light text, dark translucent cards, teal/gold accents. The texture pass was updated so .qc-roam and .qc-meet moved from the light paper-grain group to the dark-vignette group. (2) DAY/NIGHT PHOTO SLIDER FIX: the .qc-slider before/after wipe wasn't working, the frame was 16:10 wide but both source photos are portrait (so they cropped/looked broken) and the interaction felt dead. Frame changed to aspect-ratio 4/5 (portrait, fits the photos), max-width reduced to 560px, recolored dark to match the section. JS hardened: clip-path now also sets webkitClipPath, values fixed to 2 decimals, and the slider now tracks on plain mousemove (hover) in addition to drag/touch/arrow-keys for a responsive before-after feel. (3) PHOTO REMAP, CROP-AWARE: all 24 performer photos (uploads/2026/05/Queen_City_Stunt_Circus_-_Photo_01..24.jpg) re-checked against frame aspect ratios. Roaming cards changed from aspect-ratio 1/1 (which sliced the tall stilt-walker shots like Photo 21) to aspect-ratio 3/4 portrait so vertical shots show full. Each of the 24 photos is used exactly once, matched to a frame that fits its orientation. Founders banner image set to Photo 19 per Tim. (4) EM DASHES REMOVED from all code comments in the page file (visible copy was already clean). Cache buster 31.2.20. functions.php LBF_THEME_VERSION resynced (was lagging at 31.2.17) to 31.2.20. Files touched: style.css, functions.php (version only), page-queen-city-circus.php.

— v31.2.17 — T-SHIRT SUBLABEL FONT-SIZE BUMP. Tim review of v31.2.16: the 7.5px sublabel was too small. Bumped to 10px in the same Barlow Condensed 800. Letter-spacing tightened to -.01em (was .02em) to give the long string a touch more horizontal headroom. white-space:nowrap kept so it stays on one row no matter what. At 10px Barlow Condensed 800 with slightly tight letter-spacing, "The Blue Lights & Bubbles Parade &" (33 chars) should fit just under the width of "T-Shirt Order Form" rendered at 13px on the line below. Cache buster 31.2.17. Files touched: style.css, functions.php (version only), assets/css/pageant-v4-pages.css (single-line change to .lbfpg-pdf-btn__sublabel rule).

— v31.2.16 — T-SHIRT SUBLABEL TYPOGRAPHY FIX. Tim review of v31.2.15: the sublabel font didn't match the main button label. v31.2.15 used Plus Jakarta Sans 600 with uppercase + .08em letter-spacing — too different from the button's Barlow Condensed 800 main label. Updated to match exactly: same font family ('Barlow Condensed'), same weight (800), no uppercase transform. Font size dropped to 7.5px so the full "The Blue Lights & Bubbles Parade &" string (33 chars) fits within roughly the same pixel width as "T-Shirt Order Form" (18 chars) on the line below — keeps the sublabel from being wider than the main label. white-space:nowrap on both sublabel and label ensures both stay on a single line. Label text in markup also gained "The" at the start per Tim's spec — now reads "The Blue Lights & Bubbles Parade &" instead of just "Blue Lights & Bubbles Parade &". Cache buster 31.2.16. Files touched: style.css, functions.php (version only), page-pageant-application.php (sublabel text), assets/css/pageant-v4-pages.css (sublabel CSS rule).

— v31.2.15 — T-SHIRT BUTTON SUBLABEL + BLUE LIGHTS COPY FIX. Two changes. (1) The "T-Shirt Order Form" button in the Printed Documents card on page-pageant-application.php now displays a small qualifier line above the main label reading "Blue Lights & Bubbles Parade &" — so the full button reads as "Blue Lights & Bubbles Parade & / T-Shirt Order Form" stacked. The button markup wraps the label in a new .lbfpg-pdf-btn__labelstack flex-column container that holds .lbfpg-pdf-btn__sublabel (the small line) above .lbfpg-pdf-btn__label (the main label). CSS added at the end of pageant-v4-pages.css: labelstack is inline-flex column with .2rem gap and flex-start alignment so multi-line label sits cleanly to the right of the icon; sublabel is 9.5px Plus Jakarta Sans 600-weight uppercase with .08em letter-spacing and .82 opacity — small but readable, doesn't overpower the main label. Both elements inherit the button's text color (white on the primary purple-gradient buttons). The other three PDF buttons in the same card (Pageant Flyer, Rules & Regulations, Pageant Application) are unchanged and still single-line — the new CSS only applies where the .lbfpg-pdf-btn__sublabel span exists in markup. (2) page-blue-lights-bubbles-parade.php closing copy: "We'll see you on Plymouth Street, Thursday at nine." → "We'll see you on Plymouth Street, Thursday at 8:45." Aligns with the 8:45 PM start time used everywhere else on the site. Cache buster 31.2.15. No JS changes. Files touched: style.css, functions.php (version only), page-pageant-application.php (one button markup), assets/css/pageant-v4-pages.css (one new ~8-line block appended), page-blue-lights-bubbles-parade.php (one line of copy).

— v31.2.14 — CONTENT CORRECTIONS. Tim review of 2026 festival data identified seven items to verify or change. Two were already correct in the codebase (Sunday Funday Parade date August 23 — already shown that way everywhere; Miss Teen Blueberry positioned below Miss Blueberry — already ordered correctly in inc/pageant-v4.php divisions array AND on page-pageant.php, page-pageant-rules.php, and page-pageant-process.php). Five required edits: (1) Carson Rose Brashers (Wee Miss Blueberry 2025): age 4 → age 5 in her full bio sentence (inc/pageant-v4.php). (2) Sophia Fisher (Miss Teen Blueberry 2025): age 13 → age 14 in her full bio sentence (inc/pageant-v4.php). The short tag-line bio on line 68 didn't include an age so no change there. (3) Blue Lights & Bubbles Parade date: page-bubble-parade.php line 62 had "Thursday, August 21 at 8:45pm" which was the wrong day — Thursday in 2026 is August 20, not 21. Changed to "Thursday, August 20 at 8:45pm". Note: page-blue-lights-bubbles-parade.php (the newer v2 template) already had Aug 20, 2026 correct. (4) Pageant prizes (page-pageant-rules.php): expanded the prize list to clarify that ALL winners across all divisions receive a crown, sash, certificate, and prize — explicitly NO trophies. Runner-ups now get a plaque AND a certificate (was: plaque only). Winner line now reads "$100.00 cash prize, crown, sash, and certificate (no trophies)". (5) Queen's Luncheon time (page-pageant-rules.php): 9:30 AM → 10:00 AM. Cache buster 31.2.14. No CSS changes. No JS changes. Files touched: style.css, functions.php (version bump only), inc/pageant-v4.php, page-bubble-parade.php, page-pageant-rules.php.

— v31.2.13 — WAVE G: CLEANUP + PARITY. Final phase of the responsive conversion project. Deletes the dead-code layer that has been sitting on disk since the v31.0.0 device router decommission, plus runs a parity sweep to confirm zero remaining references in live code. DELETIONS: (1) 40 orphan *-mobile.php page templates — page-about-mobile.php, page-accessibility-mobile.php, page-attractions-mobile.php, page-blue-lights-bubbles-parade-mobile.php, page-bubble-parade-mobile.php, page-car-show-mobile.php, page-contact-mobile.php, page-donate-mobile.php, page-entertainment-mobile.php, page-family-attractions-mobile.php, page-faq-mobile.php, page-fireworks-mobile.php, page-food-vendor-mobile.php, page-map-mobile.php, page-memories-mobile.php, page-merchandise-mobile.php, page-pageant-application-mobile.php, page-pageant-mobile.php, page-pageant-process-mobile.php, page-pageant-rules-mobile.php, page-parade-entry-mobile.php, page-past-winners-mobile.php, page-press-mobile.php, page-privacy-mobile.php, page-register-mobile.php, page-rides-and-games-mobile.php, page-schedule-mobile.php, page-sponsor-mobile.php, page-sponsors-mobile.php, page-sponsors-v2-mobile.php, page-sponsorship-packet-mobile.php, page-sunday-funday-parade-mobile.php, page-template-2026-contestants-mobile.php, page-template-contestant-guide-mobile.php, page-template-pageant-application-form-mobile.php, page-template-pageant-journey-mobile.php, page-template-pageant-overview-mobile.php, page-vendor-application-mobile.php, page-volunteer-mobile.php, page-waiver-mobile.php. None were routed to by anything — the device-detection layer was removed in v31.0.0 and the loader functions lbf_get_mobile_header()/lbf_get_mobile_footer() they called don't even exist anymore. (2) assets/css/mobile-app.css — v29-era mobile-app stylesheet, not enqueued anywhere. (3) assets/js/mobile-app.js — v29-era mobile-app script, not enqueued anywhere. (4) inc/mobile-form-shell.php — was loaded by inc/adaptive.php; both that file and the loader function are gone. PARITY SWEEP: grep for any string reference to the deleted files across all PHP/CSS/JS in the theme. Result: zero live-code references. The two cosmetic hits — functions.php line 117-119 comment block + the style.css changelog text — were left alone for the style.css history (correct documentation) and updated for the functions.php comment (now describes the actual state: deletion happened in v31.2.13, not "remains on disk for reference"). LIVE FILES PRESERVED: assets/css/home-mobile-fix.css and assets/css/page-mobile-fix.css remain in place — those ARE the responsive system built across v31.1.0 through v31.2.11. Also preserved: lbf_maybe_render_studio_template() and lbf_get_page_render_owner() stubs in functions.php (kept for LBF Content plugin compatibility per the v31.0.0 contract). FILE COUNT: theme dropped from 181 files to 138 files (-43). NO CSS rules changed. NO JS behavior changed. NO functions removed. The responsive conversion project is now structurally complete: every page renders from a single template via header.php + footer.php with viewport-driven CSS doing all the device adaptation through home-mobile-fix.css (home page) and page-mobile-fix.css (everything else). Cache buster 31.2.13. Files touched: style.css, functions.php (comment update only). Files deleted: 43 (listed above).

— v31.2.12 — WAVE F: HEADER + FOOTER CLEANUP. The v29 dual-template "mobile-app" header (header-mobile.php) and footer (footer-mobile.php) have been dead code since the v31.0.0 device router decommission — they were loaded by lbf_get_mobile_header() and lbf_get_mobile_footer() which were called only from the orphan *-mobile.php page templates (themselves no longer routed to by anything). The loader functions don't even exist anymore — if WordPress ever did try to render one of those orphan templates it would fatal on undefined function. The current header.php is already fully responsive: desktop nav + mobile hamburger bar + slide-out mobile-nav-panel with chips and CTAs, all governed by lbf-nav-v2.css breakpoints. The mobile-only design language in header-mobile.php (navy app-bar with logo + search/bell icons, where search and bell were explicitly noted as non-functional placeholders) is not part of the current visual direction. (1) Deleted header-mobile.php from theme root. (2) Deleted footer-mobile.php from theme root. (3) Updated inc/a11y.php §1 comment block: removed the reference to mobile-app.css §31 (file deleted in earlier phase) and the reference to #lbf-mobile-main being added via JS because header-mobile.php opened <main> without an id (file now gone). The skip link target is now described simply as #main-content (added by header.php) with the §2 JS as a safety net. (4) Updated inc/a11y.php §2 comment block: removed the specific reference to header-mobile.php and reframed the §2 JS injection as a defensive measure against any future template part or page builder output that opens <main> without an id. The actual JS behavior in §1 and §2 is UNCHANGED — only the comments are updated. Verified zero remaining references to "header-mobile" or "footer-mobile" anywhere in any PHP file (orphan *-mobile.php page templates still on disk; they will be deleted en masse in Wave G along with mobile-app.css, mobile-app.js, inc/adaptive.php, and inc/mobile-form-shell.php). Cache buster 31.2.12. No CSS changes. No JS behavior changes. Files touched: style.css, functions.php, inc/a11y.php (comment-only). Files deleted: header-mobile.php, footer-mobile.php.

— v31.2.11 — WAVE E: REMAINING ONE-OFFS MOBILE. Six templates audited: fireworks, merchandise, memories, press, map, accessibility. Coverage findings: (1) Press uses .sp-pg-hero + .sp-app-layout — both already Wave A covered, no new rules needed. (2) Map and accessibility pages are structural clones of the volunteer/waiver pattern (.lbf-map-*, .lbf-a11y-* with hero/eyebrow/h/btns/cta-band/cta-inner/cta-h/cta-btns sub-elements). Applying the identical Wave C treatment: hero padding 3.5rem/3rem, title flat 2rem, eyebrow tighter, btns + cta-btns full-width column stack, CTA band padding 2.5rem 1rem, CTA heading 1.75rem. Accessibility also gets feature-card padding tightened. (3) Fireworks (.fw-*) has its own inline <style id="lbf-fw-css"> with 600px + 480px breakpoints. Adding: canvas side padding, close-section padding + heading sizes, countdown big number 2.25rem, encore padding, guide grid forced 1-col with smaller gap. (4) Merchandise (.lbf-merch-*) has inline grid that already steps to 1-col at 420px. Tightening filter row (wrap + center), product grid kept at 2-col on phone (forces 2x2 on 380px), card padding + name font reduced, CTA button full-width. (5) Memories (.mem2-*) — section-pages.css has mem2 grids mobile-first (3 → 4 @640 → 5 @900) so cards are already good. Tightening hero padding, h title 2rem, sub 0.95rem, stats wrap with center, stat number 1.5rem, featured video full-width, show-more button full-width. Cache buster 31.2.11. No PHP changes. No JS changes. Only style.css, functions.php, and assets/css/page-mobile-fix.css touched.

— v31.2.10 — WAVE D: SPONSOR SINGLES MOBILE. Three sponsor-related single-page templates audited and given mobile rules. (1) page-sponsors.php uses .spn-* family; sponsors.css is fully mobile-first (all @media min-width) so base styles already target phone. Adding defensive padding/grid rules for .spn-canvas, .spn-outer-shell, .spn-hero-inner (collapse to 1-col), .spn-hero-benefits (1-col), and the featured-sponsor showcase .spn-fp-panels (collapse 2-col to 1-col with reduced padding), .spn-fp-shell (no negative margin on phone), .spn-fp-bar (wrap with gap). (2) page-sponsors-v2.php uses .sv2-* family with 126 distinct classes. Wave A already covered .sv2-canvas, .sv2-tier-row horizontal scroll, .sv2-pkg-grid stack, .sv2-btn full-width. This release extends to: .sv2-hero-inner (1-col), .sv2-hero-h1 (2rem), .sv2-hero-sub (0.95rem), .sv2-hero-ctas (full-width column stack — same pattern as car-show v31.2.7), .sv2-hero-card (full-width no margin), .sv2-funds-inner (1-col stack), .sv2-funds-list/item (tighter gap + padding), .sv2-stickybar-inner (stack column with full-width CTAs). (3) page-sponsorship-packet.php uses .sp-pg-hero (already Wave A covered) for hero and .sp-packet-* / .sp-benefit-* / .sp-demo-* for the content body. section-pages.css already collapses .sp-packet-grid to 1-col at 1023px and stacks the download banner at 767px. This release tightens .sp-packet-grid gap (3.5rem → 1.5rem), demo/benefit list gap + margin, demo/benefit row padding + alignment (flex-start so icon + multi-line copy align cleanly), and adds explicit padding + centering to the download banner. Cache buster 31.2.10. No PHP changes. No JS changes. Only style.css, functions.php, and assets/css/page-mobile-fix.css touched.

— v31.2.9 — WAVE C: REMAINING FORMS MOBILE. Audited the five Wave C templates: page-register.php, page-sponsor.php, page-parade-entry.php, page-volunteer.php, page-waiver.php. Coverage findings: (1) Sponsor and parade-entry use .sp-pg-hero for the hero (already covered in Wave A) and .sp-app-layout for the post-hero form section (already covered in Wave A), so NO new rules needed for those two pages. (2) Register page uses register-page.css which is fully mobile-first — every @media rule is min-width, base styles target phone, desktop styles only activate at 768px+. Already responsive by design. Adding only a light belt-and-suspenders rule to constrain the hero copy and stack the two hero buttons full-width on phone (.lbf-reg-hero-copy max-width 100% + right 6%, .lbf-reg-hero-btns full width with flex children). (3) Volunteer and waiver pages each have their own inline <style> block in the PHP template with breakpoints at 980/640/560px. Those inline rules don't use !important so external !important rules in page-mobile-fix.css win the cascade despite source-order disadvantage. This release adds matching blocks for both pages that: (a) tighten hero padding from 5rem/6rem top/bottom to 3.5rem/3rem; (b) drop .lbf-vol-h and .lbf-wv-h titles from clamp(2.5rem,5.5vw,4rem) to a flat 2rem on phone; (c) shrink eyebrow font + margin; (d) convert .lbf-vol-btns + .lbf-vol-cta-btns and the waiver equivalents from inline-flex pills to full-width column stack (same pattern as the car-show fix in v31.2.7); (e) tighten CTA band padding from default to 2.5rem 1rem; (f) reduce CTA heading from default ~2.5rem to 1.75rem; (g) reduce form shell padding to 1rem 0.875rem; (h) for waiver only, the agreement strip stacks column with centered text. Cache buster 31.2.9. No PHP changes. No JS changes. Only style.css, functions.php, and assets/css/page-mobile-fix.css touched. Inline <style> blocks in page-volunteer.php and page-waiver.php are NOT modified — the external !important rules ride over them cleanly.

— v31.2.8 — WAVE B: PAGEANT CLUSTER MOBILE. Adds mobile rules for the five pageant deep-link templates (page-template-pageant-overview.php, page-template-pageant-journey.php, page-template-contestant-guide.php, page-template-2026-contestants.php, page-template-pageant-application-form.php). All five share the .lbfpg-* class family from pageant-v4-pages.css, which is mobile-first and already has an @media(max-width:767px) block that collapses the main 2-col grids (shortcuts, roster, checklist, details, schedule-spotlight, generic grid-2 variants) to single column. This release tightens the parts that base CSS leaves too large for phone. Specifically: (1) .lbfpg-hero__grid padding dropped from 2.6rem/1.25rem/2.8rem to 1.5rem/1rem/2rem; compact variant 1.5rem/1rem/1.75rem. (2) .lbfpg-hero__title forced to 1.85rem line-height 1.05 — base clamps were 2.6-4.3rem which compute too large even on small phones; same treatment applied to compact and overview-exact variants. (3) .lbfpg-hero__desc 0.9rem with line-height 1.55, full width. (4) Overview hero's 3-up action button grid (.lbfpg-hero--overview-exact .lbfpg-hero__actions) keeps 3-col layout but buttons shrink to 0.7rem font, 42px min-height, 0.55rem 0.4rem padding so three buttons fit on 380px wide phones. (5) .lbfpg-overview-highlights .lbfpg-highlight min-height removed (base 170px wasted space when stacked) — auto with 0.875rem 1rem padding. (6) Timeline cards (journey page) tightened: padding 0.875rem, gap 0.75rem, step number circle 2.1rem. (7) Tables (packing + judging on guide page) get 0.75rem 0.875rem cell padding and 0.625rem gap. (8) Contestant profile modal (2026 contestants page) goes full-bleed feel: outer padding 0.5rem, inner copy padding 1rem, title 1.5rem, thumbs 3-col with 4rem heights. (9) Filter board (.lbfpg-board) padding 0.75rem, title 0.95rem. (10) Roster rail title 1.5rem, mini cards full-width. (11) Application form host stripped to 0 padding (the global .gform_wrapper mobile rules already in page-mobile-fix.css handle the Gravity Forms layout, 1-col fields, 16px input font, full-width submit). (12) Editorial title span subtitle stacks tightly under the main h2. page-pageant.php is NOT touched — that's the home page's pageant section and its mobile rules live in home-mobile-fix.css. Cache buster 31.2.8. No PHP changes. No JS changes. No changes outside style.css, functions.php, assets/css/page-mobile-fix.css.

— v31.2.7 — CAR SHOW HERO OVERFLOW FIX. Screenshot showed description paragraph, both CTA buttons, and feature image extending past the right edge of the dark hero card on phone. Root cause: base CSS at car-show-page-v2.css line 89 gives .cs-hero-feature width:min(90vw,440px) and line 93 gives .cs-hero-dashboard the same, with margin:0 auto. On a 380px phone these compute to ~342px wide, which exceeds the inner padded content area (~308px after shell padding + hero-inner padding). Because .cs-hero-inner is a CSS grid, the widest child sizes the track — so the oversized feature and dashboard inflate the grid track and push ALL siblings (paragraph, CTAs, etc.) past the inner's padding boundary. Three-part fix in page-mobile-fix.css car-show block: (1) .cs-hero-inner gets min-width:0 and every direct child gets min-width:0 + max-width:100% so grid items can shrink below intrinsic widths instead of inflating the track. (2) .cs-hero-feature and .cs-hero-dashboard forced to width:100%, max-width:100%, margin:0 with only a top margin — removes the 90vw width and the auto horizontal margins that would re-center an oversized box. (3) .cs-hero-ctas given an explicit flex-direction:column with align-items:stretch and width:100%, and .cs-hero-ctas .cs-hero-btn forced to width:100% justify-content:center. Base CSS at line 87 only stacks .cs-hero-ctas .btn — the template uses .cs-hero-btn, so the existing rule never fires. Now both pills are full-width column-stacked inside the hero. Cache buster 31.2.7. No PHP changes. No JS changes. No changes to any file except style.css, functions.php, and assets/css/page-mobile-fix.css.

— v31.1.27 — SPONSORS PRESENTING CARD REORDER + CTA STACK + DONATION SEPARATION. (1) Presenting sponsor card: on desktop the card uses a 2-column layout (left: badge+by+name+desc, right: logo). On mobile Tim wants: pill → logo → Presented by → name → description, all inside the blue gradient, centered. Achieved via flex column on .lbf-spd25-pres-inner, flex column on .lbf-spd25-pres-body, and CSS order properties: badge=order:1, logo-wrap=order:1 inside body, text-div=order:2 inside body. Logo wrapped in a 180px white frosted box with min-height 80px. "Presented by" styled as small uppercase label. Sponsor name at 1.5rem white bold. Description at 0.8rem white/88%. (2) CTA buttons changed from 2×2 grid to full-width vertical stack (display: flex; flex-direction: column; gap: 0.5rem). All 4 buttons show, each full width, 0.8rem font. (3) Donation section (#donate) separated from sponsors with margin-top: 1.5rem, padding-top: 1.5rem, border-top: 2px solid rgba(180,200,255,0.4) — gives clear visual break between the two sections even though they share a card container. Cache buster 31.1.27. No PHP changes. No JS changes.

— v31.1.26 — SPONSORS & DONORS COMPREHENSIVE FIX. Five problems identified by comparing desktop and mobile screenshots. (1) Festival stats showing only 1 of 3: the existing CSS at line 3235 of lbf-home-v3.css sets grid-template-columns: 1fr at max-width 767px. My previous overrides weren't winning consistently. New rules add flex-direction: column, align-items: center, overflow: visible, word-break: break-word on both the container and the stat cells. (2-3) Sponsor tier rows Gold/Silver/Bronze were invisible — the enormous white space after Platinum was caused by the sp-xl/sp-lg/sp-md/sp-sm/sp-xs size classes having min-width values (180px, 130px, 100px, 80px, 60px) that weren't being overridden by my generic .sp selector. When the sponsor-row was in a 5/6/7 column grid those min-widths forced the logos to overflow/squash and appear blank. Fix: target ALL size class combinations (.sp.sp-xl, .sp.sp-lg etc.) explicitly with flex: 0 0 120px, width/min-width/max-width: 120px, height/min-height/max-height: 72px — no min-width can fight back. (4) The horizontal scroll is applied to ALL tier rows using both the data-tier-idx selectors and the .v3-tier-block class. (5) CTA buttons 2×2 grid: the existing CSS sets display: flex; overflow-x: auto on .lbf-spd25-cta-row. Override to display: grid; grid-template-columns: 1fr 1fr with flex: none on each button. Cache buster 31.1.26. No PHP changes. No JS changes.

— v31.1.25 — PAGEANT PURPLE GAP FIX — FLEX APPROACH. Multiple previous versions tried to use padding-top: 220px on the hero card to create a photo zone, then let the inner block flow below it. Despite correct CSS the gap persisted at ~150px with no clear cascade explanation. v31.1.25 abandons the padding-top approach entirely and uses display:flex flex-direction:column on .lbf-pag25-hero-card instead. The photo (.lbf-pag25-hero-bg-img) becomes the first flex child with flex: 0 0 220px, position:relative, order:0. The inner (.lbf-pag25-hero-inner) becomes the second flex child with flex: 1 0 auto, order:1, padding: 0.75rem 1rem 0.875rem. With flex layout the inner starts IMMEDIATELY after the photo with zero gap — there is no padding-top on the card, no margin to collapse, no absolute positioning confusion. Card gets padding: 0. The badge stays position:absolute anchored to the card (which is position:relative) so it sits in the top-left corner of the photo zone. Title and paragraph are static in-flow children of the inner. Cache buster 31.1.25. No PHP changes. No JS changes.

— v31.1.22 — PAGEANT TITLE POSITION FIX. v31.1.21 title was appearing at the top of the purple description box rather than on the photo. Root cause: the title box was ~50-60px tall (two lines of 0.9rem text) so at top: 158px it occupied y=158 to y=218, straddling the photo/purple boundary. The frosted white background made it visually appear to be in the purple section. Fix: moved title to top: 130px so it occupies y=130 to y=180, fully within the 220px photo zone. Also set overflow: visible on .lbf-pag25-hero-card (was overflow: hidden) so the title pill isn't clipped by the card boundary — the photo image itself has overflow: hidden via object-fit. Z-index bumped to 10. Font size reduced to 0.85rem. Max-width tightened to 52% to stay well clear of the girls. Added box-shadow for depth. Paragraph text tightened: font-size from 0.825rem to 0.8rem, line-height from 1.55 to 1.45 — reduces the purple box height slightly. Cache buster 31.1.22. No PHP changes. No JS changes.

— v31.1.21 — PAGEANT TITLE + PURPLE BOX FIX. Two issues from v31.1.20 screenshot. (1) "Who will be crowned?" was appearing at the bottom of the purple description box overlapping the paragraph text. Root cause: my CSS used position: absolute; bottom: 0 which anchors to the BOTTOM of the entire .lbf-pag25-hero-card, not the bottom of the 220px photo zone. The card is taller than 220px because the purple inner box adds height below the photo. Fixed by switching from bottom: 0 to top: 158px so the title is measured from the card's top edge and stays within the 220px photo zone. Also changed from full-width spanning (left:0 right:0) to left-anchored (left: 0.75rem, max-width: 55%) so the title stays on the left side of the photo away from the seated girls. Title restyled: black text (#000000), font-size 0.9rem, semi-transparent white frosted pill background (rgba 0.78) with backdrop-filter: blur(4px) for readability on any photo color. (2) Purple box had large empty gap above the description paragraph because the title was rendering inside the inner block. Now that the title is properly in the photo zone, the inner block contains ONLY the paragraph and gets tight padding (0.75rem top, 1rem sides, 0.875rem bottom) — just enough to contain the text with no wasted space. Cache buster 31.1.21. No PHP changes. No JS changes.

— v31.1.20 — PAGEANT SECTION MOBILE REDESIGN. On desktop the pageant hero card is a purple gradient with the photo as a background image and all text overlaid on top of the gradient. On mobile Tim wants: photo zone on top with pill top-left and title bottom-left, then purple description box below the photo, then stats strip, then 4 buttons in a 2x2 grid. Same padding-top trick as the entertainer section: .lbf-pag25-hero-card gets padding: 220px 0 0 so the card has a 220px photo zone at the top. The .lbf-pag25-hero-bg-img (the photo) is absolute inset: 0 with height: 220px so it fills only the photo zone. Badge (.lbf-pag25-hero-badge) repositioned absolute top: 0.625rem left: 0.625rem z-index: 5 — small pill in the top-left corner of the photo. Title (.lbf-pag25-hero-h) repositioned absolute bottom: 0 left: 0 right: 0 with white text and a dark-to-transparent scrim gradient so it's readable on any photo. The ::before/::after decorative orbs hidden on mobile. The .lbf-pag25-hero-inner is reset to position: static so it flows below the photo as a block, given purple gradient background (linear-gradient 135deg #6a4dff to #4b2fbf) and padding 0.875rem 1rem. Description paragraph (.lbf-pag25-hero-body) restyled with white text at 0.825rem. Stats strip gets margin-top: 0.75rem. Button row (.lbf-pag25-btns) converted from horizontal scroll to display: grid with grid-template-columns: 1fr 1fr for a 2x2 layout. Each button (.lbf-pag25-btn) gets full width, centered text, min-height 44px for tap targets, font-size 0.72rem, white-space: normal so text can wrap. Cache buster 31.1.20. No PHP changes. No JS changes.

— v31.1.19 — VIEW DETAILS OPENS ENTERTAINER POPUP ON ENTERTAINMENT PAGE. Corrected the v31.1.18 approach which incorrectly linked to individual entertainer CPT pages. The entertainment page (/entertainment/) uses a card grid with a modal popup — clicking a card calls openModal(idx). The page already has a deep-link handler (page-entertainment.php line 984-1000) that reads window.location.hash on load and on hashchange, matches it against performer slug or name-as-slug, and calls openModal(). So the correct approach is to link to /entertainment/#name-slug, not to an individual page. Two edits to front-page.php: (1) Initial button href now uses home_url('/entertainment/') + '#' + sanitize_title($first['name']) so the first entertainer's modal opens when the page loads. (2) JS URL swap now builds nameSlug = e.name.toLowerCase().replace(/\s+/g, '-') and sets detailsBtn.href to /entertainment/#nameSlug. Every time the active entertainer changes (swipe, tap, auto-rotate), the View Details href updates. Tapping View Details navigates to the entertainment page and the existing hash handler fires openModal() for that performer. No CSS changes. No changes to page-entertainment.php. Cache buster 31.1.19.

— v31.1.18 — VIEW DETAILS BUTTON NOW LINKS TO ENTERTAINER PAGE. Two surgical edits to front-page.php. (1) The View Details button markup (line 739) previously hardcoded href to home_url('/entertainment/'). Changed to use $first['url'] as the initial href (falling back to /entertainment/ if no URL set), and added data-lbf-details attribute so the JS can find the button. (2) The JS set() function (line 811) previously had a comment saying "View Details always links to /entertainment/ — no per-performer URL swap." Replaced with: var detailsBtn = wrap.querySelector('[data-lbf-details]'); if (detailsBtn) { detailsBtn.href = e.url || fallback; } — swaps the href to the current entertainer's URL every time the active card changes (swipe, tap, or auto-rotate). The URL was already present in $ent_data at line 659 ($ent['url']) — it just wasn't being used. No CSS changes. Cache buster 31.1.18.

— v31.1.17 — THUMBNAIL CARD FINAL FIX. Photo fills card frame, logo overlays photo inside the frame. Root cause of logo appearing below card: .lbf-feat-card had no fixed height so it grew taller than the photo inside it, and the logo-wrap at bottom:0 landed below the photo's bottom edge in the dark background space. Fix: gave the card a hard fixed size (130x110px) with min/max constraints so nothing can expand it. Made .lbf-feat-card__img absolutely fill the card with inset:0 so it covers the full 130x110px. The logo-wrap is position:absolute inside __img at inset: auto 0 0 0 (left:0, right:0, bottom:0) so it always sits at the photo bottom, inside the frame. Added a subtle dark gradient on the logo-wrap for logo readability. The logo image itself is constrained to max 110x34px with object-fit:contain. Active card uses a border/box-shadow highlight instead of translateY lift (lift doesn't make sense on a fixed-size card). Cache buster 31.1.17. No PHP changes. No JS changes.

— v31.1.16 — PHASE 1 FEATURED ENTERTAINMENT TWO PERSISTENT FIXES. (§AP) Hero band logo still appearing large after v31.1.15's max-width: 160px reduction. New theory: the large "SORELLE" text visible in the photo may be baked into the photo file itself (not the IMG overlay element) — CSS can't control baked-in photo text. For the actual IMG logo overlay, more aggressive sizing: max-width reduced from 160px to 120px, max-height from 65px to 50px, top positioning moved from 150px to 162px (closer to bottom of 180px photo zone) so the overlay logo sits at the very bottom and doesn't compete with any photo text higher up. Added object-fit: contain as safety net. (§AQ) Thumbnail logos escaping card frames despite v31.1.15's overflow: hidden. Two-pronged approach since cascade may not be working as expected. (1) Added clip-path: inset(0 round 12px) on both .lbf-feat-card and .lbf-feat-card__img — clip-path is not affected by child stacking contexts the way overflow is, so it provides an independent layer of clipping. (2) Added contain: layout paint on the card element. (3) Changed logo max-width from percentage-based to absolute pixel values: inactive logos max 100px wide (within the 130px card), active logos max 110px. RECESS in blocky letters at 100px should comfortably fit inside the 130px card frame. Max-heights recalibrated: 32px inactive, 36px active. Cache buster 31.1.16. No PHP changes. No JS changes.

— v31.1.15 — PHASE 1 FEATURED ENTERTAINMENT POLISH from v31.1.14 review. Five fixes. (§AK) Photo zone shortened from 240px to 180px — band photos like RECESS had huge empty cream/sky gradient at the top that wasted vertical space. (§AL) Photo positioning changed from background-position: center to background-position: center bottom — anchors the bottom of each photo (where band members + their logo overlay sit) to the bottom of the visible area, so the empty top of each photo crops off naturally. (§AM) Hero band logo capped smaller: max-width from 220px to 160px, max-height from 90px to 65px. RECESS logo was nearly full-screen width before; now sits as a tasteful overlay. top: 195px → top: 150px to re-center for the shorter 180px photo zone. (§AN) Top pills gap widened from 4px to 8px — the dark photo showing through a 4px gap looked like a vertical divider line between pills; with 8px gap it reads as proper spacing. (§AO) Thumbnails were "jumping out of their frames" with logos extending below the card boundary. Root cause: existing CSS has overflow: visible on .lbf-feat-card to allow the desktop lift-shadow effect. Override to overflow: hidden on mobile. Also bumped thumbnail height from 80px to 110px so logos have actual room inside the card frame instead of being squeezed against the bottom edge. Active card lift reduced from -3px to -2px to keep things inside the parent. Logo sizes recalibrated: active 38px max-height / 78% max-width, inactive 32px / 72%. Cache buster 31.1.15. No PHP changes. No JS changes.

— v31.1.14 — PHASE 1 FEATURED ENTERTAINMENT 4-FIX from v31.1.13 review. (§AG) Top "MAIN STAGE" pill on photo hidden on mobile via [data-lbf-pill-stage] { display: none } — for some bands the text wouldn't fit alongside the other 2 pills. Now only 2 top pills on mobile (genre + accent). (§AH) Bottom "Main Stage" info pill hidden on mobile via [data-lbf-stat-stage] { display: none }. Now only DAY + TIME pills below the photo. With one less pill the remaining two can have more room: padding bumped to 0.45rem/0.75rem, value font from 0.7rem to 0.8125rem, gap between them 8px. "Saturday" and "8:30 PM" comfortably fit. (§AI) "See All Entertainers" button text was truncating. Reduced button font from 0.75rem to 0.7rem, tighter padding (0.7rem/0.5rem), and crucially set white-space: normal with line-height: 1.15 so the text can wrap to 2 lines if it still doesn't fit. (§AJ) Thumbnail card sizing: existing CSS at line 2076-2079 sets .lbf-feat-card { flex: 0 0 78%; max-width: 78% } at (max-width: 767px), making each card ~300px wide × 217px tall — far too big for a compact swipe row of band thumbnails. Override to fixed 130px wide × 80px tall (with aspect-ratio: auto to defeat the 4/2.9 existing rule). Now 2.5+ thumbnails visible at once, properly sized for swipe browsing. Active card lift reduced from -6px to -3px to fit the smaller card. Card logo sizes recalibrated: active 36px max-height / 80% max-width, inactive 30px / 75%. Cache buster 31.1.14. No PHP changes.

— v31.1.13 — PHASE 1 FEATURED ENTERTAINMENT UNIFIED DARK CARD. Tim wanted: top pills in ONE row over the photo, bottom info pills in ONE row, buttons in one row, and the background behind the info pills + buttons to match the DARK background that's behind the thumbnail strip — so the whole entertainment section reads as one unified dark card with the photo on top. (§AC) Top pills (LEXINGTON'S OWN / POP / MAIN STAGE): forced flex-wrap: nowrap on the pills container, shrunk pill font from 0.6rem to 0.5rem, shrunk padding from 0.25/0.6 to 0.2/0.45, letter-spacing tighter, white-space: nowrap with ellipsis overflow on each pill. All 3 now fit on one row. (§AD) Bottom info pills (DAY / TIME / STAGE): forced flex-wrap: nowrap and made each pill equal-width with flex: 1 1 0. Dropped the uppercase labels (font-size: 0 on .lbf-feat-stat__label so the word "DAY/TIME/STAGE" disappears but the icon remains visible). Now each pill shows only icon + value — much more compact. Pill background changed to translucent white (rgba 0.08) over the dark zone, light border (rgba 0.15), white value text. All three fit in one row. (§AE/AF) Dark info zone background: .lbf-feat-hero__content background changed from white to #040d1a (exact match for the .lbf-feat-ent wrapper). White text. Buttons restyled for dark context: solid (View Details) keeps white background with dark text and stronger shadow for readability over dark; ghost (See All Entertainers) becomes transparent with white border and white text. (Card unification) Photo card .lbf-feat-hero has its border removed and only top corners rounded (16px 16px 0 0) so it flows seamlessly into the dark info zone below, which flows into the dark thumbnail strip below that. The outer .lbf-feat-ent wrapper provides the overall card boundary. Cache buster 31.1.13. No PHP changes. No JS changes. No edits to existing CSS files.

— v31.1.12 — PHASE 1 FEATURED ENTERTAINMENT POLISH. Three fixes from v31.1.11 review. (§Z) DAY pill was truncating "Sunday" because existing CSS at line 2070 of lbf-home-v3.css sets .lbf-feat-stat { width: 5.5rem; } (88px) at (max-width: 767px) — not enough room for "Sunday" alongside the day icon and label. Override to width: auto, min-width: 0, max-width: none so pills size to their content. (§AA) "See All Entertainers" ghost button was rendering as opaque dark gray pill — the existing CSS at line 1914-1918 styles .lbf-feat-btn--ghost with background: rgba(4,13,26,0.55) which was designed for on-photo display (semi-transparent dark over photo). On the new white info zone it looked like an ugly dark gray pill. Restyled the ghost variant for white-background context: light gradient background (#f4f7ff), purple border (rgba(106,77,255,0.25)), dark navy text (#1e3a8a). Also explicitly styled the solid "View Details" button with a solid dark navy background and white text so it has clear visual hierarchy as the primary action. Both buttons have hover states without the transform translate that would feel awkward on mobile. (§AB) Tightened .lbf-feat-hero__content padding from 1rem 1rem 1.125rem to 0.875rem 1rem 1rem to reclaim a bit more vertical space. Cache buster 31.1.12. No PHP changes. No JS changes.

— v31.1.11 — PHASE 1 TWO FIXES from v31.1.10 screenshot review. (§X) Featured Entertainment had ~400px of empty white space below the buttons. Root cause: existing CSS at line 2067 of lbf-home-v3.css sets .lbf-feat-hero__content { padding: 3.5rem 1rem 1rem; min-height: 480px; } inside its own @media (max-width: 767px) block. My v31.1.10 set the content's positioning and background but forgot to override min-height: 480px. Result: content was 480px tall even though pills + buttons need only ~150px. Fix: explicit min-height: 0 !important on .lbf-feat-hero__content, plus restated padding to enforce 1rem all around. (§Y) Festival Schedule was visually fused with the Experience The Festival section above it — they share the same v3-card container, so on mobile they read as one giant blob. Schedule now wrapped in its own card-like styling: 2rem top margin for clear separation, light purple gradient background (linear-gradient from #f4f7ff to #e9eeff), 1px purple border, 18px border-radius, 1.25rem 1rem internal padding. The .lbf-exp-sched__bg decorative layer hidden since we now have proper card styling on the parent. Heading font bumped to 1.5rem dark navy. Subtitle sized for the new card context. Cache buster 31.1.11. No PHP changes. No JS changes. No edits to existing CSS files.

— v31.1.10 — PHASE 1 MOBILE FEATURED ENTERTAINMENT, take 3 (final). Cleaner approach matching the agreed mockup. v31.1.8 broke the photo (content rendered on top of it), v31.1.9 was a fragile transform hack. v31.1.10 uses padding-top: 240px on .lbf-feat-hero to reserve a photo zone at the top of the card, with .lbf-feat-hero__content sitting naturally below it in the same card with white background. Total result: ONE card containing photo zone on top + white info zone on bottom, no transform tricks. (§V) Photo card: padding: 240px 0 0 reserves photo zone, background-image fills it, two tiny genre pills positioned absolute at top-left of photo, band logo positioned absolute at top: 195px with translate(-50%, -50%) so it sits centered at the bottom edge of the 240px photo zone. Drop shadow on logo for readability on any photo. (§W) Info zone: .lbf-feat-hero__content reset to static positioning with white background and 1rem padding. .lbf-feat-about HIDDEN ENTIRELY (label, name, description — name is in the logo, description is one tap away on detail page). Stats row: 3 inline pills with subtle purple border, light fill, icon + label + value. Buttons: 2 equal-width pill-shaped buttons side by side at the bottom. v31.1.10 also REMOVES the v31.1.8 and v31.1.9 entertainment blocks from the CSS file (lines 1576-1838 of the previous file deleted) so there's no conflicting old rules. The §5 block from v31.1.2 and §D block from v31.1.3 remain but my v31.1.10 §V/§W rules at the end of the file override them via source order. Cache buster 31.1.10. No PHP changes. No JS changes. The existing JS at front-page.php lines 836-849 that handles entertainer swipe-card switching still works because we don't touch its data-attribute selectors. Switching to a different entertainer card still updates the photo background, the logo, and the stat values in real time.

— v31.1.9 — PHASE 1 MOBILE FEATURED ENTERTAINMENT, take 2 ("Option A"). v31.1.8 broke the section: I tried to make .lbf-feat-hero__content static so it would flow below the photo, but content is a CHILD of .lbf-feat-hero so it rendered INSIDE the photo card, obscuring the photo. v31.1.9 fix: keep .lbf-feat-hero__content positioned absolute at bottom: 0 of the photo card, then use transform: translateY(100%) to push it BELOW the photo visually. Photo card gets overflow: visible so the translated content can render outside its parent's box. Photo card also gets margin-bottom: 320px to reserve space (transforms don't affect layout flow). Same intended end-result as Option C: photo on top with the band logo centered at its bottom edge, white info card below with band name + Day/Time/Stage pills + 2 buttons. Logo positioned absolutely with top: -100px relative to .lbf-feat-hero__content so it sits above the content card's top edge, landing on the photo's bottom. Drop shadow on logo for readability on any photo background. Description hidden. Same JS hooks preserved (data-lbf-hero-bg, data-lbf-about-name, data-lbf-day, data-lbf-time, data-lbf-stage-val) so swipe-to-switch-entertainer still works. Cache buster 31.1.9. No PHP changes.

— v31.1.8 — PHASE 1 MOBILE FEATURED ENTERTAINMENT REDESIGN ("Option C"). Tim's complaint: on mobile the photo was being completely covered by overlay text, pills, and the description panel — same layout as desktop just crammed onto a phone. The band photo (SORELLE in current data) couldn't breathe. Solution agreed: photo gets the BAND LOGO ONLY, centered at the bottom of the photo. Everything else moves to a white info card BELOW the photo with: band name (large), 3 inline pills for Day · Time · Stage, and 2 buttons. Description text is omitted on mobile per Option C — it's one tap away on the entertainer detail page. (§R) Photo card: .lbf-feat-hero set to fixed 280px height, background-size: cover, rounded only on top corners. Overlay pills (.lbf-feat-hero__pills) hidden. Decorative top-line and glow-orb hidden. Band logo (.lbf-feat-hero__logo-img) extracted from its natural parent via position: absolute, anchored bottom: 1rem; left: 50% with transform translateX(-50%) so it centers on the bottom of the photo. Drop shadow added to the logo so it reads on light or dark photo regions. Max dimensions 220px wide x 100px tall. (§S) Info card below photo: .lbf-feat-hero__content overridden from absolute positioning to static, given white background, rounded only on bottom corners, padding 1.25rem 1rem. .lbf-feat-hero__right reordered to come first (band name on top). .lbf-feat-about restyled as plain centered text block (transparent background, no padding, no border). .lbf-feat-about__label "Why Catch This Set" hidden. Band name styled as 1.5rem Outfit bold dark navy. Description (.lbf-feat-about__copy / data-lbf-perf) display: none. (§T) Stat pills: .lbf-feat-hero__stats reset from vertical stacking to horizontal flex row with wrap, centered. Each .lbf-feat-stat styled as a pill with light gradient background, purple border, rounded 999px, icon + label + value inline. Labels are uppercase 0.6rem with SVG icons at 11x11. Values are 0.75rem dark navy bold. (§U) Button row: .lbf-feat-hero__btns made flex row with equal width buttons (flex: 1 1 0), top border separator, comfortable tap-target padding, rounded full pill shape. Cache buster 31.1.8. No PHP changes. No JS changes. The existing JS at lines 836-849 of front-page.php that handles entertainer swipe-card switching still works because we don't touch its data-attribute selectors. Switching to a different entertainer card still updates the photo, logo, stats, and name correctly — they just render in the new mobile composition.

— v31.1.7 — PHASE 1 MOBILE FESTIVAL SCHEDULE FIXES. Tim review: day cards too tall, not enough visual signal that the strip is swipeable. (§P) Shorter cards: existing CSS had min-height: 150px and padding: 1.25rem 0.5rem on .lbf-exp-day. My v31.1.2 lowered padding but didn't touch min-height. Result: cards remained 150px+ tall. v31.1.7 overrides min-height to 0 (cards auto-size to content), padding to 0.625rem 0.5rem, icon shrunk from 32x32 to 24x24, date number font from 1.65rem to 1.15rem, day-of-week font from 0.65rem to 0.55rem, label font to 0.62rem. Cards now ~75-85px tall instead of 150px+. Added subtle border + light background so each card is visually distinct on its own (not just bleeding into the background). (§Q) Scroll signal: previous version showed 2 full cards (looked like a static 2-column grid). New version shows ~2.5 cards by narrowing card width from 42% to 35% (max 130px). The half-visible card on the right edge is the universal "swipe for more" affordance. Also added a right-edge fade gradient via .lbf-exp-sched__inner::after pseudo-element — content fades from transparent to 85% white over the rightmost 30px, reinforcing that more cards exist off-screen. Cache buster 31.1.7. No other changes from v31.1.6.

— v31.1.6 — PHASE 1 MOBILE EXPERIENCE CARD TITLE FIX. v31.1.5 hero overlay and eyebrow fixes both worked, but the experience cards were still showing "Entertain ment" broken mid-word. Root cause: my v31.1.4 use of overflow-wrap: break-word told the browser it could break mid-word when needed, and despite widening the card to 68% the cumulative padding still wasn't leaving enough room. Fix: more aggressive. (1) Card width bumped from 68% to 78% of viewport (max 300px) — gives roughly 305px on a 390px phone. (2) Title font shrunk from 0.92rem to 0.85rem. (3) Strictly disable mid-word breaking: word-break: keep-all, overflow-wrap: normal, hyphens: none, -webkit-hyphens: none. Words now stay whole. (4) Reduced card body horizontal padding from 0.875rem to 0.625rem each side, giving the title more room to fit on one line. All current titles ("Entertainment" 13 chars, "Attractions" 11 chars, "Pageant" 7, "Events" 6, "Parades" 7) now fit on one line at the new font size and card width. Cache buster 31.1.6. No other changes from v31.1.5.

— v31.1.5 — PHASE 1 MOBILE HERO + EXPERIENCE FIXES. Tim section-by-section review starting at the top. (§N) Hero readability: on desktop the festival photo composition naturally has lighter colors on the left where the logo + buttons sit, making them readable. On phone the photo crops to nearly square so the logo lands over the busy middle of the photo and becomes hard to read. Fix: add a vertical white-to-transparent gradient overlay between the photo and content via .v3-hero::before pseudo-element (existing CSS had ::before disabled with content: none / display: none — we override). Overlay is stronger at top (78% white where logo + date pill sit) and bottom (78% white where buttons sit), softer in the middle (30% white where photo shows through). Result: logo + buttons readable regardless of photo crop. (§O) Experience section: two issues. First, the "Four Days of Festival Fun" eyebrow text was wrapping because its ::before and ::after decorative gradient lines were 2.5rem wide each plus 0.75rem gap, eating ~7rem of horizontal space and leaving too little for the text on a phone. Fix: shrink decorative lines from 2.5rem to 1rem on phone, reduce font from 0.65rem to 0.6rem, tighten letter-spacing from 0.2em to 0.14em, force white-space: nowrap so the text stays on one line. Second, the experience card images were showing blue bottoms (the #1a3064 fallback background of .lbf-exp-card__img-wrap was bleeding through because the image wasn't fully filling the wrap). Fix: position the image absolutely inside the wrap with width/height 100% AND min-width/min-height 100%, object-fit: cover, object-position: center. The image is now guaranteed to fill the wrap completely, no blue bleed. Card image area also bumped from 130px to 140px tall for better composition. Cache buster 31.1.5. No PHP changes. No JS changes. No edits to lbf-home-v3.css, homepage-polish.css, lbf-hero-static.css, or any other existing file.

— v31.1.4 — PHASE 1 MOBILE THREE-FIX PATCH. Targeted at remaining issues from v31.1.3 screenshot review. (§K) Experience strip "Entertainment" card title was breaking mid-word as "Entertain ment" because the 13-char word with no natural break point couldn't fit in a 60%-viewport-wide card. Fix: widen card to 68% viewport (max 270px), shrink title font from 0.95rem to 0.92rem, add hyphens: auto + overflow-wrap: break-word + word-break: normal so the word can either fit whole or break with a proper hyphen rather than mid-word. (§L) Festival stats labels inside sponsor section ("Attendees / Festival reach / Community impact") — defensive fix to force white-space: normal, overflow: visible, text-overflow: clip on both .lbf-spd25-fest-num and .lbf-spd25-fest-lbl so multi-word labels can wrap to two lines rather than truncating. Whether or not the screenshot's apparent truncation was real or thumbnail-resolution illusion, this hardens against either case. (§M) Sponsor tier rows: the BIG fix. Discovered existing CSS at lines 2877-2880 of lbf-home-v3.css uses .lbf-spd25 .tier-row[data-tier-idx="1"] .sponsor-row through [data-tier-idx="4"] selectors at the BASE state (not inside a media query), which have higher specificity than my generic .lbf-spd25 .tier-row .sponsor-row selector. That's why my horizontal scroll override was only winning for Platinum (the first tier where my rules apparently matched first by source order) but Gold/Silver/Bronze were still using the existing grid-template-columns: repeat(5,1fr) / repeat(6,1fr) / repeat(7,1fr) layouts. Heartland Church (Gold tier) was rendering at wrong size for that reason. Fix: my new override selectors explicitly match each tier index (data-tier-idx="1" through "4") so they win on specificity AND source order. Same horizontal scroll behavior applied to all four tiers. Also hard-capped sponsor box dimensions to width: 130px / height: 80px regardless of which tier or which logo, with object-fit: contain so wide logos (Heartland Church's horizontal format) and tall logos all sit centered within the uniform box. Cache buster 31.1.4. No PHP changes. No JS changes. No edits to existing CSS files. Fixes are appended INSIDE the existing @media (max-width: 767px) block in home-mobile-fix.css after the v31.1.3 fixes (which remain).

— v31.1.3 — PHASE 1 MOBILE TARGETED FIXES. 10 specific issues from screenshot review of v31.1.2. (§A) Hero logo clipped at top — gave .v3-hero an explicit min-height of 520px so the photo background + logo + buttons all fit without clipping. (§B) Stats band labels at 0.52rem were unreadable — bumped to 0.6rem for labels and 0.92rem for numbers. (§C) Experience carousel was starting on card 5 instead of card 1 — added scroll-padding-left: 1rem, scroll-snap-align: start, explicit direction: ltr, removed negative margin bleed. Card width narrowed from 75% to 60% so 2 cards visible at once. (§D) Featured Entertainment hero photo was being cut off at bottom and the thumbnail strip was bleeding into hero — bumped hero min-height from 360px to 440px, added margin-bottom: 1rem before thumbnails, removed thumbnail strip's negative margin bleed. (§E) OhioHealth presenting card logo was invisible — the wrapper was collapsing. Added min-height 70px on .lbf-spd25-pres-logo-wrap, min-width 180px, min-height 40px on the image itself, and forced .lbf-spd25-pres-logo-link to flex-center. (§F) Festival stats strip rendered as empty cells — existing CSS at line 3235 of lbf-home-v3.css set grid-template-columns: 1fr at max-width 767px and my v31.1.2 rule lacked !important. Added !important plus explicit display: block on the inner stat cells. (§G) Sponsor tier rows after Platinum rendered in chaos — existing CSS at line 3236 has grid-template-columns: repeat(2,1fr) !important which was winning over my horizontal scroll setup. Bumped specificity (.v3-card.lbf-spd25 .tier-row .sponsor-row) and added !important on every property. (§H) Donation tile descriptions were missing — .lbf-spd25-amt-row uses flex with icon + content side-by-side; the content area was collapsing or not displaying its .lbf-spd25-amt-desc child. Added explicit display: block, flex: 1 1 auto, visibility: visible, opacity: 1 on the description, plus min-width: 0 on content for proper flex shrinking. (§I) Sponsor CTA 2x2 grid was partially hidden by donation widget — added margin-top: 1.5rem and margin-bottom: 1.5rem with position: relative and z-index: 2. (§J) Generic safety: body.lbf-home-v3 and major wrapper containers got overflow-x: hidden to prevent the negative-margin bleeds in horizontal-scroll strips from triggering full-page horizontal scroll. The scroll strips themselves keep overflow-x: auto. Cache buster bumped to 31.1.3. Zero PHP changes. Zero JS changes. Zero edits to lbf-home-v3.css or any other existing CSS. The new fixes are appended INSIDE the existing @media (max-width: 767px) block in home-mobile-fix.css — the v31.1.2 base remains untouched in the same file.

— v31.1.2 — PHASE 1 MOBILE LAYOUT REWRITE. Complete rewrite of home-mobile-fix.css with a different philosophy. v31.1.1 stacked everything to single column which made the page endless to scroll and lost the visual identity of each desktop section. v31.1.2 preserves desktop composition by using HORIZONTAL SCROLL-SNAP CAROUSELS for browsable card rows, compact GRIDS where stacking would lose identity, and single column only where content is genuinely linear. (1) home-mobile-fix.css rewritten from 533 lines to 916 lines, all rules wrapped in @media (max-width: 767px), scoped to body.lbf-home-v3. (2) Hero — logo bumped from 180-260px to 280-360px so "Join Us for the 2026 / Presented by OhioHealth" text under the main logo is readable. (3) Stats band — kept as horizontal 4-column pill (matching desktop identity) instead of 2x2 grid. Compact text sizing. (4) Experience strip — horizontal scroll-snap carousel of 5 cards, swipeable. (5) Schedule strip — horizontal scroll-snap of day cards, swipeable, with section heading stacked above. (6) Featured Entertainment — preserves the big hero photo card with overlay text positioned at bottom. The 5-entertainer thumbnail strip below uses horizontal scroll-snap (the existing inline JS in front-page.php at lines 836-849 already supports swipe mode — this CSS just enables it). (7) Pageant — 2x3 grid of 6 division cards (not 1-column stack). Description / CTA buttons stack ABOVE the division grid. CTA buttons in 2x2 grid. (8) Sponsor presenting card — logo above text in a white inset box, max-height contained. Festival stats 3-across. (9) Sponsor tier logos — converted to horizontal scroll-snap. Each logo in a 130px fixed-width white box with 80px height. Full brand names visible. Bronze tier text fallbacks now show complete names (no more "MAP... / MID..." truncation). (10) Sponsor CTAs — 2x2 grid. (11) Donation widget — single-column tile stack, Gravity Forms full-width inputs, 16px font on inputs (prevents iOS zoom). (12) Section spacing standardized. The horizontal scroll pattern uses CSS scroll-snap-type: x mandatory with scroll-snap-align: center on children, scrollbar hidden, 1rem viewport bleed for cards to feel edge-to-edge. Zero PHP markup changes. Zero JS changes. Zero edits to lbf-home-v3.css or any other existing CSS. Patch is purely additive; deleting the file and removing the enqueue restores v31.1.0 behavior. Cache buster bumped to 31.1.2.

— v31.1.1 — PHASE 1 MOBILE PATCH. Comprehensive top-to-bottom mobile layout pass for the home page based on real-device screenshot review of v31.1.0. (1) NEW: assets/css/home-mobile-fix.css. 533 lines, all inside one @media (max-width: 767px) block, scoped to body.lbf-home-v3. Loads via inc/enqueue.php on is_front_page() only, after lbf-home-v3.css and homepage-polish.css so it wins the cascade. (2) Sections patched (top to bottom): §1 Hero — tighter logo (clamp 180-260px instead of 260-440px), buttons stack to single column max 320px wide, all centred, hero min-height auto. §2 Stats band — removed the negative-margin hero overlap, 2x2 grid with consistent padding and centred icon/num/label stack per card. §3 Experience strip — collapsed from 2-column to 1-column with larger 160px image areas, bigger icon badges, more readable typography. §4 Schedule strip — single-column day cards, no orphan row. §5 Featured entertainers — single-column. §6 Pageant — division cards stack to single column with left-aligned icon+text layout, CTA buttons stack full-width. §7 Sponsors Presenting Card — fixed the broken 2-column body grid that was showing the description outside the purple gradient card. Logo now sits above text in a white inset box with max-height constraint. §8 Sponsor tier logos — every logo container forced to aspect-ratio 2/1 with white background, contained images, prevents the giant CNG logo issue from the v31.1.0 screenshot. §9 Sponsor CTAs — 2x2 grid instead of awkward wrap. §10 Donation widget — Gravity Forms inputs forced full-width with 16px font (prevents iOS zoom on focus), state dropdown stacks below address, submit button full-width. Section spacing standardized: 1rem 0.75rem margins, 1.25rem 1rem padding per v3-card. (3) Zero edits to lbf-home-v3.css. Zero edits to any page template. Zero edits to any plugin. Patch is purely additive; deleting the new CSS file and removing the enqueue line restores v31.1.0 behavior exactly. (4) Tablet (768-1023px) and desktop (1024+) untouched — every rule is wrapped in (max-width: 767px). (5) Cache buster bumped to 31.1.1. Known limitation: I built this without access to the live HTML markup (sandbox couldn't reach testsite.lexblueberryfest.com), so the fix is based on reading the PHP source plus the user's screenshot. Some specific issues may remain or new issues may surface — iterate with v31.1.2 based on the next round of screenshots.

— v31.1.0 — PHASE 1: HOME PAGE RESPONSIVE-SINGLE-TEMPLATE CONVERSION. The home page is now a single template that serves every device. (1) front-page-mobile.php deleted. Every visitor, regardless of device, now sees front-page.php. (2) Dead countdown plumbing removed from front-page.php. The lbf_cd_media() function (~100 lines, photo galleries, video, Instagram, YouTube, lightbox) was a renderer that was never called anywhere in the page body — confirmed by exhaustive grep of every .cd-media class against the rendered markup region. Plus ~60 lines of $cd_* variable setup ($cd_label_text, $cd_wrap_style, $cd_box_style, $cd_photos, $cd_insta_url, $cd_vid_local, $cd_vid_ytid, $cd_captions, etc) that read theme_mod values but were never used after their assignment. Total: 157 lines of dead code removed from front-page.php (1,578 → 1,421 lines). (3) Zero changes to any rendered home page section. The hero, stats band, experience strip, entertainers section, pageant section, sponsors section, donations section, news feed, and footer all render identically to v31.0.0 on every device. (4) No CSS file changes. The existing assets/css/lbf-home-v3.css was already substantially responsive — it contained tablet (max-width 1100px) and phone (max-width 767px) breakpoints that collapsed the 4-column stats band to 2×2, the 6-column pageant grid to 2-column on phone, the 3-column entertainers grid to 1-column on phone, the hero h1 to a fluid clamp() size, and various border-radius shrinks. Those rules were never previously hit by phones (phones hit front-page-mobile.php via the v30 device router before Phase 0 retired it), but now they are. The desktop home page should render reasonably on phones, tablets, and desktops out of the box. (5) The companion stylesheets (lbf-home-v2.css, homepage-polish.css, lbf-hero-static.css) also remain unchanged — none of them needed responsive changes. (6) The Pacifico font enqueue in inc/enqueue.php is retained (used for countdown headline historically; harmless to keep — may be removed in a later cleanup pass once we confirm nothing else on the home page uses it). (7) Cache buster bumped to 31.1.0. CANONICAL BREAKPOINT CONTRACT FOR FUTURE PAGE CONVERSIONS: base styles target phone (no @media needed); tablet styles use @media (min-width: 768px); desktop styles use @media (min-width: 1024px). Min-width only. Mobile-first. New responsive code in subsequent waves follows this. Existing max-width rules in legacy stylesheets are tolerated until those stylesheets are touched. KNOWN COSMETIC RISK: this is a code-only release — I did not look at a live rendered phone screenshot before writing it. The home page may have visual issues on a phone that will need targeted fixes in 31.1.1 once Tim deploys 31.1.0 and reviews on a real device. Expected hotspots: tablet width 768–1023px where the desktop site previously had no rules and now falls under the @media (max-width: 1100px) and @media (max-width: 767px) blocks that may produce some awkward transitions; the hero on very narrow phones (under 360px) since the existing CSS was tuned for the mobile-app template; and any section that uses a fixed pixel min-height. Hot-fix path: bump to 31.1.1 with targeted CSS adjustments based on real-device review.

— v31.0.0 — PHASE 0: DEVICE ROUTER DECOMMISSIONED. The dual-codebase mobile-templates architecture (v29.8.0 through v29.15.0) is being retired in favor of a single responsive codebase. This release removes the device-detection layer so every visitor on every device class gets served the desktop templates. Phones will look wrong on most pages until each page is converted to be responsive in subsequent phases. (1) inc/adaptive.php is no longer required by functions.php. The file remains on disk for reference. The lbf_is_phone() and lbf_is_tablet() helpers, the template_include filter that swapped *-mobile.php variants, the Vary: User-Agent header emission, the ?lbf_view=mobile testing override, the phone-only mobile-app.css/.js enqueue, and the .lbf-mobile-app body class are all dormant. (2) inc/mobile-form-shell.php is no longer auto-loaded by inc/adaptive.php. File remains on disk for reference; will be examined and either absorbed or deleted during the form-page conversion phase. (3) The 85 calls to lbf_maybe_render_studio_template() in page templates have been removed. LBF Studio v5 is no longer installed, so this short-circuit always returned false and was dead code. The function definition itself remains in functions.php (returns false always) so any third-party caller is unaffected. The lbf_get_page_render_owner() ownership map and its companion helpers also remain — lbf-content's lbfc_get_page_owner() reads from them. (4) The 36 *-mobile.php page templates remain on disk. They are no longer routed to by anything. They will be deleted page-by-page as each desktop counterpart is converted to be responsive. (5) header-mobile.php and footer-mobile.php remain on disk. They will be merged into header.php and footer.php in a dedicated later phase. (6) assets/css/mobile-app.css and assets/js/mobile-app.js remain on disk but are no longer enqueued by anything. They will be deleted at project end. (7) lbf_map_route_fallback() in functions.php no longer checks wp_is_mobile() — the /map/ slug fallback always serves page-map.php now. (8) Cache buster bumped to 31.0.0 so every browser cache flushes on first visit after deployment. ZERO edits to any page-*.php template's body content, any CSS file, any JS file, or any other inc/*.php file. The only changes are: functions.php (one require removed, version bumped, map fallback simplified), the 85 page templates (one dead conditional removed each), and this style.css header.

— v29.21.1 — GLOBAL PAGE-SHELL UTILITY. Refactor instead of redo: extracted the "rounded card sits below the header" pattern into a reusable utility class so this doesn't have to be re-derived per page. Three pages previously solved the same problem three different ways (schedule with hardcoded px values + !important; about-our-pageant with the --header-h variable + bespoke .pag-v3-canvas; FAQ in v29.20.1+v29.21.0 with its own bespoke .lbf-faq-canvas). Going forward there is now ONE canonical way. (1) New global utility classes added to style.css right after .container: .lbf-page-canvas (max-width 1480px centered, with top padding calc(var(--header-h, 82px) + .5rem) so the inner card always sits below the site header regardless of header height, plus admin-bar offsets at both 782px breakpoints for logged-in editors) and .lbf-page-card (overflow:hidden, border-radius 28px desktop / 20px phone, soft 1px white-translucent border, 32px blur drop shadow at 13% brand-blue, near-white translucent rgba(255,255,255,.92) background). Usage: <div class="lbf-page-canvas"><div class="lbf-page-card">...content...</div></div>. (2) FAQ migrated to the new utility. The wrapper markup was renamed from .lbf-faq-canvas/.lbf-faq-outer to .lbf-page-canvas/.lbf-page-card. The duplicate shell CSS that lived in the page-faq.php style block (canvas padding, card radius, border, shadow, background, admin-bar offsets, mobile radius override — about 25 lines) was removed since the global utility now provides all of that. Only the FAQ-specific sticky filter bar override is retained in the page template since the sticky positioning math is FAQ-specific. (3) Pages with their own existing bespoke wrappers were left untouched: front-page.php (.v3-outer-card / .v3-canvas), page-schedule.php (.s3-outer / .s3-canvas), page-pageant.php (.pag-v3-outer / .pag-v3-canvas). Each has page-specific tuning (different header offsets, different shadows, different backgrounds) and migrating them risks breaking working code with no visible benefit. They can be migrated case-by-case in the future if/when they next need attention. (4) Going forward: any new page that wants the rounded card shell just adds two divs with the global classes — no derivation, no copy-paste, no rounded-corner dance. Total: ~50 lines added to style.css (utility definition + comment), ~25 lines removed from page-faq.php (redundant bespoke shell CSS), 2 class names renamed in page-faq.php markup, zero behavior change for the FAQ visitor.
— v29.21.0 — FAQ NEXT LEVEL: deep linking, search highlighting, ask-a-question widget, admin dashboard, em-dash cleanup, header-offset fix. Four new visitor-facing capabilities plus an admin analytics tool, plus the rounded card now sits properly below the site header. (1) Slug-based deep linking. Each accordion question gets a stable URL-friendly slug derived from sanitize_title() of the question text (with uniqueness handling if two questions sanitize to the same slug). A hidden anchor element inside each item provides the slug target. URLs like /faq/#where-can-i-park now resolve to the right question and auto-open it. The item also keeps its index-based id (lbf-faq-v3-item-N) for backward compat with the existing Most Asked jump logic. handleDeepLink JS function runs on DOMContentLoaded and on hashchange so back-button navigation between deep-linked questions also works. Reset filters before opening so the linked item is definitely visible. (2) Copy-link button on every answer. Renders next to the Helpful? reactions, copies the canonical /faq/#slug URL to clipboard using navigator.clipboard.writeText with a fallback to document.execCommand for older browsers. Visual confirmation: button briefly turns green with "Copied!" label, then reverts after 1.8 seconds. (3) Search highlighting. Every keystroke in the search input now wraps matched text in <mark> tags inside both question and answer elements. Uses TreeWalker to walk text nodes so existing inline HTML like <a> links inside answers is preserved (not double-wrapped or corrupted). Highlight styling is a gold underline gradient that doesn't change text color, applied via CSS so reduce-motion respects it. (4) Ask-a-Question section (§4.5, between accordion and dark CTA band). Visitor-facing form with name (optional, max 100 chars), email (required, validated), question (10-1000 char with live character counter that turns red near limit). Submits to the new /wp-json/lbf/v1/faq-submit REST endpoint. Endpoint validates input, rate-limits to 3 submissions per IP per hour via transients (IP is hashed, not stored raw, using md5 + wp_salt), caps stored submissions at 500 per page to keep meta blob bounded, stores submissions in _lbf_faq_submissions post meta array, and emails the site admin a notification with the submission details + edit-screen link. Form provides real-time validation, optimistic UI with disabled+spinner state during submit, success/error toast at bottom. NEW FILE: inc/faq-submissions.php (~5KB). (5) Admin dashboard meta box. When editing the FAQ page in WP Admin, a new "FAQ Insights" meta box appears with two tabs. Tab 1: Vote Analytics. Summary cards showing total votes, helpful count, unhelpful count, and "X of N" questions that have any votes. Table of all questions sorted by helpfulness ratio (low ratio first so problem answers surface to the top), with category pill, question text, big percentage indicator color-coded green/yellow/red (>=75% / >=50% / <50%), a percentage bar, raw counts, and total votes column. Separate section at the bottom for questions with zero votes. Tab 2: Visitor Submissions inbox. Summary cards showing counts by status (new / reviewed / added / dismissed), then each submission rendered as a colored card (red border for new, amber for reviewed, green for added, gray for dismissed). Each card shows submitter name + email + timestamp + question text + status pill + action buttons to change the status (forms submit to admin-post.php with nonce protection). Status updates require edit_pages capability. Tab badge shows count of "new" submissions. Meta box only loads when the page template is page-faq.php, doesn't clutter other page edit screens. NEW FILE: inc/faq-admin.php (~14KB). (6) Em-dash cleanup in FAQ content. All 24 user-visible em-dashes removed from page-faq.php (13) and page-faq-mobile.php (11). Replaced with periods, colons, or commas depending on context. Em-dashes in code comments / docblocks / section markers retained since they're programmer-facing only. Other site files not touched in this pass. (7) Rounded card header offset fix. The v29.20.1 wrapper used padding:0 on .lbf-faq-canvas which made the card slide right under the site header instead of below it. Fixed: padding-top now calc(var(--header-h,82px) + .5rem) matching about-our-pageant pattern, with admin-bar offsets for logged-in users at both 782px breakpoints. (8) Scroll-margin-top + JS scroll offset bumped from 220px to 260px to account for the site header + sticky chip bar combination. Total: 2 new inc files (~19KB), ~150 lines added to page-faq.php (slug derivation + ask section + copy-link button + new CSS + new JS), ~24 em-dashes replaced across desktop+mobile FAQ, 1 sticky-offset fix, 1 require line, version bump. Zero changes to other site pages this round.
— v29.20.1 — FAQ ROUNDED CARD SHELL. Wrapped the desktop FAQ page content in the same rounded-corner outer-card shell used by the front page, schedule page, and about-our-pageant page, so FAQ now visually fits alongside those framed pages instead of running edge-to-edge. Added two wrapper divs around all 5 FAQ sections (hero + filter bar + Most Asked + accordion + dark CTA band): outer .lbf-faq-canvas (max-width 1480px, centered, horizontal padding clamp(.75rem,2vw,1.5rem)) and inner .lbf-faq-outer (overflow:hidden, border-radius 28px desktop / 20px mobile, soft 1px white-translucent border, 32px-blur drop shadow at 13% brand-blue, near-white translucent rgba(255,255,255,.92) background). Hero gradient now clips cleanly to the rounded top corners; CTA band gradient clips to rounded bottom corners. Sticky filter bar position fix: was top:0 (overlapping the site header) — now sticks below the header at calc(var(--header-h,82px) + .5rem) matching schedule's pattern, with admin-bar offsets at viewport ≥782px (32px) and <782px (46px) for logged-in editors. Scroll-margin-top on accordion items bumped from 220px to 260px to account for header + sticky chip bar, and the matching JS smooth-scroll offset in the "Most Asked" featured card click handler bumped to -260px so anchor jumps land the question fully visible below the sticky bar. Zero changes to mobile FAQ (page-faq-mobile.php) which doesn't need a card wrapper — mobile templates are full-bleed by design in the app-style mobile layer. Total: 1 file edited (page-faq.php), ~30 lines added (1 wrapper open, 1 wrapper close, ~25 lines CSS, 2 sticky-offset tweaks), version bump.
— v29.20.0 — SITE-WIDE FACTUAL SWEEP. Content-only patches across 12 files to apply the v29.19.1 FAQ truth set throughout the entire site, fixing every page that referenced non-existent festival amenities. Files patched: (1) page-accessibility.php — physical-features default array rewritten from 10 inaccurate items (paved pathways, three stages with ADA seating reserved, mobility golf cart shuttle service, hearing loops at every stage, staffed first aid stations, accessibility map at info booths) down to 8 accurate items (accessible parking off Plymouth Street, accessible portable restrooms throughout grounds, private adult changing stations in main office, main office as quiet sensory-friendly space, service animals welcome, health paramedics on grounds, seating throughout, festival map). (2) page-accessibility-mobile.php — mirror change: 8-item features array replaced with 7 accurate items matching desktop. Removed: paved paths claim, ADA-reserved seating at every stage, mobility golf carts, ASL interpreters for the pageant, large-print schedules, audio descriptions, sensory zone near community pavilion. Added: adult changing stations in main office, main office as sensory-friendly space, paramedics on grounds. (3) page-map.php — sidebar parking/locations rewritten. Removed Overflow Lot A and Overflow Lot B references (with their fictional 8am-10pm shuttle service), removed multiple-entrance list (Main Gate/North/West — festival has no gates), removed Pavilion Stage from key locations (only Main Stage exists), removed Beer Garden entirely (no alcohol on park grounds), removed Tent C cook-off location, removed Info Booth and First Aid as separate locations, removed entire Shuttle Info card with 15-minute shuttle interval claim. Added: accurate parking (festival lot across from grounds + designated Lexington Community Park lots, accessible parking off Plymouth Street), Main Office as single hub for info/help/lost+found/paramedics, ATM next to main office, single Main Stage. (4) page-fireworks.php — three corrections: removed shuttle reference from Getting There card (was "the festival shuttle runs throughout the night"), corrected parking FAQ answer to describe actual lots instead of "festival shuttle runs to overflow lots", corrected family tips card to reference portable restrooms throughout the festival instead of nonexistent restrooms near Main Stage and entrance. (5) page-press.php — two corrections: detail summary card changed from "3 live music stages, carnival, pageant, car show, parade" to "Live music on the Main Stage, carnival, pageant, car show, parade", vendor count changed from "150+ craft, merchandise, and food vendors" to "Dozens of craft, merchandise, and food vendors", photo opportunities list line changed from "Live music performances on 3 stages" to "Live music performances on the Main Stage". (6) page-entertainment-mobile.php — page subtitle changed from "across four days and multiple stages" to "across four days on the Main Stage". (7) page-attractions.php — attractions data array corrections: food vendors "50+ vendors serving every kind of food" → "A dozen-plus vendors serving classic festival fare", craft vendors "150+ arts, crafts, and artisan vendors" → "Dozens of arts, crafts, and artisan vendors", Kids Zone description "face painting, inflatables, carnival games, supervised activities" → "Laser tag, train rides, entertainment, and family-friendly events all festival long" with location corrected to "Kids Zone", Beer Garden entry REMOVED entirely (was "Local craft beers, wines, and seltzers. 21+ with valid ID"). (8) page-vendor-application.php — vendor space stat default "150+" changed to "Dozens", info body "hosts 150+ vendors" changed to "hosts dozens of vendors". (9) page-about.php — "The festival runs on the energy of hundreds of volunteers and community supporters" softened to "The festival runs on the energy of our volunteers and community supporters". (10) page-volunteer-mobile.php — stat strip rewritten: removed fictional "200+ Volunteers" stat, removed inaccurate "All Ages" claim, replaced with "Crew Roles" and "16+ Solo" stats matching v29.19.1 FAQ minimum-age guidance. (11) page-vendor-application-mobile.php — vendor spaces stat "150+" changed to "Dozens". (12) page-food-vendor-mobile.php — vendor stat "50+" changed to "Dozen+". Items intentionally NOT changed: parade-entry vehicle list including "golf carts" in page-sunday-funday-parade.php (these are decorated parade-entry vehicles people drive, not mobility-aid golf carts), Lions Club pancake breakfast reference in same file (third-party Lions Club fundraiser tradition, separate from festival food vendor offerings — was flagged for organizer verification before changes), interpret/interpreted language in WCAG accessibility content (technical content about screen-reader interpretation, semantically correct as-is). NOTE: Many of these changes affect default-fallback content displayed only when the corresponding _lbf_* post meta or theme mod has not been customized by an admin. If admin has already customized these in WP Admin, that custom content takes precedence and these defaults are invisible — the changes ensure that future fresh installs or empty customizations don't display outdated info. Total: 12 files patched, zero new files, zero template/CSS/JS structural changes — content-correction patch only. Version bump.
— v29.19.1 — FAQ FACTUAL CORRECTIONS. Content-only update to the default FAQ question set in both page-faq.php (desktop) and page-faq-mobile.php (mobile fallback). 23 factual corrections applied based on event-organizer review, reducing the question count from 30 to 27 (3 questions removed). Removed entirely: "Is there a shuttle?" (no shuttle service), "Can I ride my bike?" (no bike parking), "Are ASL interpreters available?" (not currently offered). Corrections per question: (1) "When is the festival?" — removed gate-opening language since festival is open-grounds with no gated entry. (2) "Where is it held?" — simplified from "Downtown Lexington, spread across the park and surrounding streets" to just "Lexington Community Park in Lexington, Ohio." (3) "Is admission free?" — replaced "rides" with "the pageant" in the fees-clarification list since pageant has paid admission. (4) "Are there ATMs?" — corrected to "an ATM located next to the main office" (single ATM, single location, not three). (5) "Where can I park?" — corrected to "the lot across from the festival and in the designated Lexington Community Park parking lots" (not "multiple lots throughout downtown" — there are no downtown overflow lots and no shuttle). (6) "Is there accessible parking?" — corrected location to "on the grounds off of Plymouth Street" (not the closest entrance lot), removed reference to non-existent mobility golf carts. (7) "What food is available?" — corrected to "dozen-plus food vendors" (not 50+), removed reference to blueberry pancakes which are not served. (8) "How do I apply to be a vendor?" — replaced with "Visit our Register page to apply" since Register is the actual application hub. (9) "Is alcohol sold or allowed?" — corrected to "No alcohol is sold or allowed on park grounds" (previous answer described non-existent beer gardens). (10) "Who is performing?" — corrected to "the Main Stage" (singular — there is one Main Stage, not three). (11) "Are there kids' activities?" — corrected to describe actual offerings: laser tag, entertainment, train rides, family-friendly events all festival long (removed references to face painting and Blue Lights & Bubbles Parade in this context). (12) "How does the Miss Blueberry Pageant work?" — generalized to "multiple age divisions" (not 6 specifically since unconfirmed), updated link to the correct URL https://lexblueberryfest.com/about-our-pageant/. (13) Replaced "Can I watch without competing?" with "Can I watch the pageant?" with accurate ticketed-event details: held August 2026 at Heartland Church, admission $3 per individual or $10 per family, tickets sold at the door. (14) "When is the pageant application deadline?" — updated link to correct about-our-pageant URL. (15) "How do I volunteer?" — softened "hundreds of volunteers" to "We rely on all of our volunteers!" since the festival does not have hundreds. (16) "How young can volunteers be?" — corrected age threshold from 14+ solo / 10–13 with parent to 16+ solo / younger with parent or guardian. (17) "Is the festival wheelchair accessible?" — substantially trimmed to focus on accurate amenities: accessible restrooms throughout, private adult changing stations in the main office. Removed inaccurate references to paved paths covering all areas, ADA-reserved seating at every stage, mobility assistance, and the link to the Accessibility page. (18) "Quiet sensory-friendly areas" — corrected location to the main office (not a separate area near the community pavilion). (19) "First aid" question reframed as "Where do I go in an emergency?" with corrected details: health paramedics are available on festival grounds; in an emergency come to the main office. Removed reference to a staffed first aid tent at the main entrance. (20) "What if I get separated from my kids?" — corrected meeting point to "main office" (not "info booth at the main entrance"). (21) "Where do I report lost & found items?" — corrected location to "main office" (not "main info booth"). (22) "Where are the restrooms?" — simplified to portable restrooms throughout the festival at all major areas, including accessible portable units, marked on map. Removed reference to permanent restrooms at the Community Park pavilion. Mobile and desktop fallback question sets kept synchronized identically. No template, CSS, or JavaScript changes in this patch — content-only update to the empty-state defaults. If Tim has already customized _lbf_faq_items in WP Admin, his custom content takes precedence and this update is invisible to him. Total: 2 files updated (page-faq.php + page-faq-mobile.php), version bump.
— v29.19.0 — FAQ PAGE REDESIGN. Complete visual rebuild of the desktop FAQ page (page-faq.php) to match the home/entertainment/schedule design language. Dropped the sidebar, added category teasers in the hero, added Most Asked featured row, added Helpful? reactions with REST-backed vote counters, expanded default questions from 14 to 30. (1) page-faq.php REPLACED in place — only file replacement across the entire v29.8.0+ project. Old template content noted in changelog history; revert path is to restore it from prior version's git history if needed. Structure: §1 Dark mesh hero with entertainment-pattern background (mesh blobs + gold dot grid + curved SVG accents) + eyebrow chip + Barlow Condensed headline + sub + 3 pills + 2 buttons + 8 category teaser cards on right side (1 "All Questions" + 7 category cards with emoji + name + count, click jumps to filter and activates that chip). §2 Sticky filter bar with prominent search input (gold focus border, clear button) + result counter + horizontal scrollable category chip row (entertainment-pattern day-chip design with emoji + name + count badge per chip). §3 Most Asked featured row — 4 large cards with icon + category pill + question + "Tap for answer" CTA; click jumps to and opens the corresponding accordion item. Featured items selected by explicit featured:true flag in data, auto-filled from first 4 if fewer than 4 flagged. §4 Full accordion grouped by category, with each item showing 44px gradient icon box on left + question + category mini-pill + animated chevron in circular button on right; expanded state shows gold-rotated icon, blue border glow, gold-bordered answer panel with gradient top fade, and Helpful? reactions at bottom (thumbs up/down buttons that POST to REST endpoint, persist locally via localStorage to prevent spam, server stores aggregate counts in _lbf_faq_helpful_N + _lbf_faq_unhelpful_N post meta). §5 Dark CTA band with festival banner photo background + navy gradient overlay matching entertainment's closing band — eyebrow + big H2 + sub + Contact + Email buttons. Combined search + category filter (entertainment-pattern), real-time client-side, with empty state when zero matches. FAQPage JSON-LD schema emitted inline directly from the template so the page is self-contained for rich results even without inc/seo-schema.php. Backward compatible: existing _lbf_faq_items JSON still works; if no custom items configured the new 30-question default fallback covers General/Parking/Food/Entertainment/Pageant/Volunteering/Accessibility/Safety with comprehensive answers including weather policy, ATMs, shuttles, bike parking, alcohol policy, fireworks timing, ASL availability, quiet zones, first aid location, lost & found, child-separation procedure. (2) NEW inc/faq-feedback.php — REST endpoint POST /wp-json/lbf/v1/faq-feedback that accepts {post_id, idx, vote: "yes"|"no"} and increments the matching meta counter. Anonymous, validates post exists + is a page + idx is in sanity range + vote is valid. No nonce required (low-risk action). Auto-loaded via functions.php. (3) page-faq-mobile.php updated to match — added Most Asked featured row above accordion using new .lbfm-faq-featured-card design (icon + category pill + question + chevron, click jumps + opens), added Helpful? reactions inside each accordion panel using same REST endpoint, expanded mobile default fallback from 14 to the same 30 questions as desktop so phone and desktop stay synchronized even with no admin customization. Helpful votes share localStorage key lbf_faq_voted_v1 across mobile and desktop so a user can't vote twice (once mobile, once desktop) on the same item. (4) assets/css/mobile-app.css §33 — mobile FAQ featured card style (gradient icon box, category pill, blue active-state border) + helpful reaction button pill style (thumbs up/down with vote counts, voted state, thanks message). Total: 1 file replaced (page-faq.php), 1 file updated (page-faq-mobile.php), 1 new file (inc/faq-feedback.php), 1 require added, ~30KB new CSS+HTML across desktop+mobile, version bump.
— v29.18.0 — A11Y PHASE C: WCAG AA color contrast audit + fixes. Real measured-ratio audit (not guesswork) of every color pair in mobile-app.css using the WCAG relative-luminance formula. Audit found 5 sub-AA pairs out of 24 audited; all other pairs already pass AA, most at AAA level. Fixes (in §32 of mobile-app.css, additive-only — original tokens unchanged where possible): (1) --lbfm-text-3 darkened from #6b7280 → #5a6373. Was 4.34:1 on app background (AA-Large only); now 5.44:1 (AA normal text pass). (2) --lbfm-text-muted darkened from #9ca3af → #5c6470. Was 2.28:1 on app background (FAIL); now 5.37:1 (AA pass). (3) New --lbfm-gold-text token added: #7a5800. This is for use as TEXT on light backgrounds. Original --lbfm-gold (#f3c303) stays unchanged so all button backgrounds, badges, hero accents, dark-bg eyebrows, and gradients keep their brand-correct appearance. Brand gold as text on white was failing at 1.66:1; the new gold-text token achieves 6.51:1 on white. (4) Targeted overrides: .lbfm-event--live (the LIVE NOW eyebrow inside event cards on white background) and .lbfm-form-gf-wrap .gfield_required (the required-asterisk on form labels) now use --lbfm-gold-text. .lbfm-sponsor-chip-tier on white backgrounds switched to the readable variant. (5) No changes to gold-on-dark contexts: white text on blue (9.98:1), white on dark blue (15.30:1), white on darkest navy (19.89:1), white on purple (8.98:1), white on teal (5.36:1), dark navy text on gold buttons (11.95:1), dark navy on bright gold (14.13:1) — all AA or AAA, untouched. Audit results documented in the §32 CSS comment block for future reference. Total: ~2KB CSS additions. Zero edits to original CSS tokens (only additive overrides). Together with Phases A + B, the site now ships with: site-wide JSON-LD structured data, Open Graph + Twitter cards, meta descriptions, canonical URLs, breadcrumb schema, FAQPage schema, Event schema (festival + pageant + per-event schedule), Article schema for posts, Organization + WebSite schema; universal skip-to-content link, focus-visible styling for all interactive components, prefers-reduced-motion support, prefers-contrast: more support, keyboard sheet handling (Escape closes, focus trap, focus restoration), screen-reader-only utility class, runtime external-link safety (rel=noopener noreferrer auto-injection + new-window screen reader announcement); and WCAG AA color contrast compliance across all body text, secondary text, brand colors, and form states.
— v29.17.0 — A11Y PHASE B: Site-wide accessibility enhancements — skip-to-content link, focus styles, ARIA landmarks, keyboard navigation, prefers-reduced-motion support. One new file: inc/a11y.php (~6KB). All additive — zero edits to any existing template, CSS, or JS file. Audit first: desktop header.php already has role="banner", <nav role="navigation">, and <main id="main-content" tabindex="-1">, footer.php has role="contentinfo". Mobile templates already have aria-label on icon-only buttons and aria-hidden on decorative SVGs. So Phase B fills the remaining gaps: (1) Universal skip-to-content link — emitted via wp_body_open priority 1 on EVERY page (desktop + mobile). Hidden absolutely off-screen until keyboard focused, then visible at top-left with blue background + gold outline. First focusable element on every page so keyboard users can bypass header navigation and jump straight to main content. Targets #main-content (desktop already has this id; mobile gets it via runtime JS injection in §2). (2) <main> id + tabindex injection — small inline head script tags the first <main> element with id="main-content" and tabindex="-1" if it doesn't already have them. Lets the skip link target work on mobile templates without editing header-mobile.php. (3) .using-keyboard body class — added when Tab key is pressed, removed on mouse/touch. Enables focus rings only when the user is actually keyboard navigating, as a belt-and-suspenders signal for browsers that don't fully support :focus-visible. (4) the_content filter for external links — auto-adds rel="noopener noreferrer" to any target="_blank" link missing it (security + a11y best practice), and tags links with data attribute for §5 sr-only enrichment. (5) Screen-reader-only suffix script — finds links tagged in §4 and appends a sr-only " (opens in new window)" span so screen readers announce the new-tab behavior to users who otherwise lose focus context. (6) Inline CSS in wp_head priority 2 — the minimum a11y CSS (skip link + sr-only utility + :focus-visible + prefers-reduced-motion) inlined directly so it works on DESKTOP pages too, not just where mobile-app.css is loaded. (7) Updates to assets/css/mobile-app.css — §31 Accessibility utilities: full skip-link styling, sr-only utility class, comprehensive :focus-visible rules with gold outline (3px solid #f3c303, 2px offset) for all interactive components (tabs, chips, accordions, cards, tiles, sheets, contestants, sponsors, products, photos, registration cards, form fields), prefers-reduced-motion media query that kills all animations including the looping decorative ones (firework stars/bursts, live-dot pulse, event-card live indicator), prefers-contrast: more media query bumping borders to 2px for high-contrast users. (8) Updates to assets/js/mobile-app.js — §15 Keyboard sheet handling: Escape key closes any open mobile sheet (More sheet or detail sheet), MutationObserver watches for sheet hidden-attribute changes to track focus restoration (remembers element that opened sheet, returns focus to it on close, moves focus into sheet to the close button on open), focus trap inside open sheets (Tab cycles within first/last focusable element, Shift+Tab wraps backwards, prevents tabbing out into the dimmed background). Total: 1 new file + ~3KB CSS additions + ~3KB JS additions + 1 require line + version bumps. Removal: delete inc/a11y.php + the require line + the §31 CSS block + the §15 JS block — site reverts to pre-a11y state.
— v29.16.0 — SEO PHASE A: Site-wide JSON-LD structured data + Open Graph + Twitter Cards + meta descriptions. One new file: inc/seo-schema.php, hooked into wp_head at priority 4-5 (early, so plugins can override). Auto-defers to Yoast SEO, Rank Math, All in One SEO, and SEOPress if any are detected as active, to avoid duplicate/conflicting schema output. Schema emitted: (1) Organization — every page, single @id-anchored entity covering festival name, logo, address (Lexington OH), contact point, sameAs social profiles (auto-built from lbf_facebook, lbf_instagram, lbf_twitter, lbf_youtube, lbf_tiktok theme mods — only emits ones that are actually set). (2) WebSite — every page, with SearchAction for Google's sitelinks search box. (3) Festival Event — homepage only when the festival is upcoming or in progress (auto-skips emission once past, since Google penalizes stale events). Includes startDate, endDate, location with full PostalAddress, Free admission offer, event status, attendance mode. Default Aug 20-23 of active festival year, overridable via lbf_festival_start and lbf_festival_end theme mods. (4) Event[] for Schedule page — auto-built from lbf_get_all_events() data, each event becomes its own Event entity with ISO datetime, venue, address. Auto-skips when festival in past. (5) FAQPage for FAQ page — reads from _lbf_faq_items JSON meta and emits Question/Answer pairs (the exact format Google needs for FAQ rich results in search). (6) Pageant Event for Pageant page — Aug 22 2-6 PM placeholder, only when festival upcoming. (7) Article for blog posts — headline, datePublished, dateModified, author, publisher (linked to Organization @id), image from featured thumbnail. (8) BreadcrumbList — every non-homepage page, walks through page ancestors to build the breadcrumb trail Google uses to display "Home > Category > Page" in search results. All entities are emitted in a single @graph wrapper for efficiency. Meta description tag emitted on all singular content (uses excerpt, falls back to trimmed content). Open Graph tags: og:type (article for posts, website otherwise), og:site_name, og:title, og:description, og:url, og:locale, og:image (featured image → lbf_og_default_image theme mod → site logo fallback chain), og:image:alt. Twitter Card tags: summary_large_image when image present, summary otherwise, with twitter:site and twitter:creator pulled from lbf_twitter_handle theme mod. Canonical URL emitted for non-singular pages (front page, archives) where WordPress core doesn't already handle it. Never emits fabricated data — fields missing from underlying meta are simply omitted from the schema rather than filled with placeholders. Removal: delete inc/seo-schema.php + the one require line in functions.php — schema output reverts to nothing (or to Yoast/Rank Math if installed). Total: 1 new file (~14KB), 1 require line, version bump. Zero edits to any existing template, CSS, or JS file.
— v29.15.0 — PHASES 8 + 9: Fireworks mobile + tablet polish layer (final phase). Completes the 8-phase mobile-templates project: ALL 37 pages now have dedicated app-style mobile templates, AND tablets now also get the mobile templates (with a CSS layer that frames the content for tablet-sized viewports). (1) page-fireworks-mobile.php — phone-optimized fireworks event page. Night-sky aesthetic hero card (dark navy + purple gradient base with 7 animated twinkling stars + two pulsing gold/blue firework bursts on staggered loops), three live states (countdown → live → past) computed server-side from current_time vs. _lbf_fw_start and _lbf_fw_end meta (defaults to active festival year Aug 22 22:00–22:20), giant "FIRE/WORKS" Barlow Condensed display with gold accent on WORKS, formatted date + time below. When in countdown state: live ticking countdown block (days/hours/minutes) that reads its target ISO date from a DOM attribute. Show details list with date/showtime/location/cost. "Best Viewing Tips" blue gradient content card. "What to Bring" 2x2 informational tile grid (Blanket / Snacks / Sweater / Camera). Headliner credit card automatically pulls headliner photo + entertainment link from lbf_get_all_performers() data — uses _lbf_fw_headliner meta to look up performer by name (default SORELLE). Plan-Your-Night cross-link list to Schedule / Map / Entertainment. (2) inc/adaptive.php — lbf_is_phone() updated. Tablets (iPad, Android tablets, Kindle, Surface, PlayBook, Silk) now ALSO get the mobile templates instead of falling through to desktop. Function name kept for backward compat but semantically it now means "should serve mobile templates." New companion helper lbf_is_tablet() for code that needs the phone/tablet distinction (e.g. for analytics). New body class .lbf-tablet added alongside .lbf-mobile-app for tablet visitors. (3) assets/css/mobile-app.css — §29 fireworks night-sky styles: night-sky gradient with positioned twinkling stars (3px and 5px variants, staggered animation delays for organic feel), pulsing firework burst circles with 4s animation cycle, glowing gold accent on the FIREWORKS display title, live/past/countdown state badges in the hero. §30 tablet polish layer: at viewport ≥600px the mobile templates render in a centered 480px column with subtle radial-gradient wash background on the surrounding space (looks like a phone-frame floating on a desktop), shadow elevation around the column edges so it reads as a contained app surface, larger touch targets on the bottom tab bar (24px icons instead of 22px), at viewport ≥768px tile grids expand to 3-col (homepage) and 4-col (small tiles + photo grid), product grid expands to 3-col. (4) assets/js/mobile-app.js — §14 fireworks countdown init: reads target ISO from the DOM element (not the lbfMobile global, so the homepage festival countdown and the fireworks show countdown can coexist), uses different selectors than §1 to prevent collision, updates every 60 seconds with day/hour/minute display. PROJECT TOTALS: 37 of 37 pages now have app-style mobile templates. 38 total *-mobile.php files including header-mobile and footer-mobile. 105KB CSS (mobile-app.css) divided across 30 documented sections covering every UI component. 25KB JS (mobile-app.js) divided across 14 documented behavior sections. 1 require line added to functions.php, version bumps in style.css and functions.php. ZERO edits to any existing template, CSS file, or JS file across all 8 phases. Complete removal path: delete the 38 *-mobile.php files + inc/adaptive.php + inc/mobile-form-shell.php + assets/css/mobile-app.css + assets/js/mobile-app.js + the one require line in functions.php → theme reverts to byte-identical pre-mobile state.
— v29.14.0 — PHASE 7: Reference/long-form mobile pages. Four long-content pages get dedicated mobile templates with section-jump-chip navigation so visitors can navigate long documents efficiently on a phone. (1) page-pageant-rules-mobile.php — official pageant rules with H2-driven sticky section jump chips. Reads the standard WordPress page editor content (same source as desktop), parses all H2 headings via DOMDocument, auto-injects anchor IDs into each H2, and builds a horizontal scrollable chip row at the top. Tap any chip → smooth scroll to that section with 80px offset for the sticky chip bar. IntersectionObserver highlights the active chip as the corresponding section scrolls into view. 3-stat row (6 age groups / Jul 18 early bird / N sections). Bottom purple Apply CTA. (2) page-template-contestant-guide-mobile.php — same jump-chips pattern, with a comprehensive 7-section default fallback guide (Before You Apply / What to Wear / Rehearsal Day / The Pageant Day / Interview Questions / If You Win / Tips from Past Contestants) so the page reads well even before Tim customizes content. Bottom links to Rules + Process + Apply. (3) page-sponsorship-packet-mobile.php — download-oriented. 4-stat strip (attendees / years / families / tiers), prominent gold "Download Full Packet" PDF banner (uses _lbf_spn_packet_url meta or theme_mod, with graceful "coming soon" info card if not configured), demographics list (6 default demos editable via _lbf_spn_demo{1-6}_v and _l meta), sponsorship tier overview cards (auto-built from lbf_get_sponsor_tier_configs() — each tier renders as a gradient card with rank number + label + friendly blurb covering Presenting/Gold/Silver/Bronze/Friend), bottom Apply/Sponsors/Contact CTAs. (4) page-template-pageant-journey-mobile.php — year-of-service timeline for crowned queens. Royal purple hero with "12 Months of Adventure" stat, 3-stat strip, 7-stage vertical timeline (AUG crowning weekend / SEP orientation / OCT-DEC fall+holiday / JAN-APR regional circuit / MAY-JUN pre-festival / JUL festival lead-up / AUG pass the crown) using the existing Phase 6 timeline component with a new purple-pill number variant (text labels like "OCT–DEC" instead of digits), each stage editable via _lbf_pj_s{1-7}_title and _body meta with sensible defaults, "What We Provide" blue gradient content card, bottom Apply/Process/Past Winners CTAs. (5) Updates to assets/css/mobile-app.css — §28 reference/long-form styles: sticky jump chips with horizontal scroll + active state, comprehensive longform content typography (H2 with left-border accent + scroll-margin-top for sticky-chip-aware scrolling, H3/H4 hierarchy, blue-marker bullets, blockquote with gold accent border, code/table/img styling, tables with uppercase compact headers), tier overview cards in blue/gold/teal/purple gradient variants with rank badge + label + blurb, journey-variant timeline number pill (wider for text labels). (6) Updates to assets/js/mobile-app.js — §13 section jump chips behavior: smooth scroll on tap with 80px sticky-aware offset, IntersectionObserver-driven active-chip highlighting as user scrolls (rootMargin -120px/-40% so chips activate when their section reaches the top of the readable area), auto-scrolls the chip rail to keep the active chip in view. Total: 4 new templates + ~10KB CSS + ~2KB JS. Phone visitors now have app-style versions of 36 of 37 pages. Only Fireworks (Phase 8) remains.
— v29.13.0 — PHASE 6: Sectioned/accordion mobile pages. Five info-heavy pages get dedicated mobile templates using two patterns: searchable accordion (Q&A and topic lists) and stacked content cards (narrative/marketing pages). (1) page-faq-mobile.php — searchable Q&A accordion. Top sticky search bar with clear button filters all FAQ items by question + answer text. Category chips (auto-built from FAQ data) filter by topic. Search + category combine — an item shows only if it matches both. Each Q&A is a tappable accordion item with emoji icon + question; tap to expand the answer panel. Multiple items can be open at once (useful for comparing answers). Reads from the same _lbf_faq_items post meta JSON the desktop FAQ uses, with the same 14-item default fallback. (2) page-accessibility-mobile.php — sectioned commitment + features accordion + conformance + feedback. "Our Commitment" rendered as a blue gradient content card, an 8-item accordion for "What's Available" features (wheelchair / ADA parking / ADA seating / service animals / hearing / visual / quiet spaces / festival concierge), website conformance statement as a neutral content card, feedback section with email + contact CTAs. (3) page-about-mobile.php — narrative festival story. Page intro, 4-stat row (years running, annual visitors, vendors, free admission — pulled from existing _lbf_about_stat* meta), then four content card sections (Mission as blue gradient, History as neutral, Organizers as neutral, Community Impact as gold gradient — each pulls from _lbf_about_{section}_h and _lbf_about_{section}_p meta with sensible defaults), bottom Volunteer/Donate/Contact CTA card list. (4) page-pageant-process-mobile.php — vertical numbered timeline of the 5 stages from application to crown. Purple royal hero with "5 Steps to the Crown" stat, 3-stat row (6 age groups / $25 entry / Jul 31 deadline), then the timeline: each step is a 36px gold numbered circle connected by a vertical line to a content card showing icon + step title + body (all pulled from _lbf_pp_s{1-5}_title and _body meta with sensible defaults). Below: age divisions reference card listing all 6 divisions (Tiny Miss through Miss Blueberry) with editable age ranges via _lbf_pp_d{1-6}_ages meta. Bottom purple Apply CTA. (5) page-template-pageant-overview-mobile.php — pageant marketing landing. Royal hero with chips/pills from lbf_pg_v4_data()['hero']['overview'], three content card sections explaining what the pageant is + who can enter + what winners do, bottom Learn More card list linking to Process / Rules / Past Winners / Apply. (6) Updates to assets/css/mobile-app.css — §27 sectioned/accordion styles: search bar with focus-blue border and clear button, accordion items with rotating chevron + is-open state + blue glow on open + 8px gap between items, content cards in neutral/blue-gradient/gold-gradient variants with eyebrow + body typography, vertical timeline with gold numbered circles + connecting lines + per-step icon cards, no-results state for empty searches. (7) Updates to assets/js/mobile-app.js — §11 accordion expand/collapse (independent toggling, aria-expanded sync, hidden panel state) + §12 FAQ search + category combined filter (real-time client-side, search matches against data-search attr, category matches against data-cat attr, auto-closes open items that get hidden, no-results state toggle). Total: 5 new templates + ~10KB CSS + ~3KB JS. Phone visitors now have app-style versions of 32 of 37 pages. Tablets + desktops untouched throughout.
— v29.12.0 — PHASE 5: Card-grid mobile pages + More-sheet sub-page fix. (1) BUG FIX — footer-mobile.php rewritten so the More sheet now exposes EVERY page on the site, not just the original 10 hardcoded links. Strategy: try the Primary Navigation WordPress menu first (so whatever you've configured in WP Admin → Appearance → Menus shows up), with comprehensive grouped fallback if no Primary menu is assigned. Fallback groups: Pageant (Application/Rules/Process/Past Winners), Entertainment & Attractions (Entertainment/Attractions/Fireworks/Memories), Parades & Shows (Sunday Funday/Blue Lights & Bubbles/Parade Entry/Bubble Parade/Car & Bike Show), Vendors & Registration (Hub/Vendor App/Food Vendor/Merchandise), Sponsors & Support (Sponsors/Become a Sponsor/Packet/Donate/Volunteer), About & Help (About/FAQ/Contact/Press/Accessibility/Waiver/Privacy). Each link auto-skips itself if the page doesn't exist (uses get_page_by_path) so empty sections don't render. Each link picks an appropriate Lucide icon from a 35-slug icon map. Tab-bar duplicates (Home/Schedule/Map/Pageant) auto-excluded from both menu-driven and fallback paths. Added §11 CSS for .lbfm-sheet-section + .lbfm-sheet-section-h (small uppercase section headings with top borders). (2) page-sponsors-mobile.php — tier-grouped sponsor wall with gold "Thank You" hero card, tiers rendered as grids (top tier = 1-col tall card, second tier = 2-col, lower tiers = 3-col compact logos), sponsor card tap opens detail sheet with full-size logo + tier label + description + Visit Website CTA, bottom "Become a Sponsor" gold link card. (3) page-memories-mobile.php — Instagram-style 3-column photo grid with featured-video YouTube/local embed card, year filter chips at top (auto-built from configured gallery years), photo tiles tappable to open in new tab for full-size viewing with year badge overlay, additional video cards section below for extra clips. (4) page-merchandise-mobile.php — WooCommerce-aware product grid with auto category filter chips (from product_cat terms), 2-col product cards with thumbnail + name + price + Sale badge, link to full shop page when product count exceeds the visible 24, graceful "store opening soon" empty state when WooCommerce isn't loaded or no products published. (5) page-past-winners-mobile.php — purple royal hero with years-of-pageant stat, year filter chips (auto-built from contestants with contestant_year + contestant_crown meta), winners grouped by year with crown badge overlaid on each card (Miss/Junior/Princess etc.), tap a winner opens detail sheet with full bio + hometown + sponsor + crown title. (6) page-template-2026-contestants-mobile.php — current-year roster using lbf_pg_v4_data() source for parity with desktop template, royal hero with contestant count and division count, division filter chips, contestants grouped by division (filterable to single division), each card tappable for detail sheet with bio + hometown + sponsor. (7) page-press-mobile.php — press contact card (gradient blue with gold accents, large email button, request-credentials CTA), media kit download link card (gold gradient, only renders if _lbf_press_kit_url is set), Quick Facts details card (dates/location/established/attendance — editable via theme mods lbf_press_*), accreditation note info card, related coverage resources (About/Schedule/Memories). (8) Updates to mobile-app.css — §26 card-grid styles: thanks-hero gold card with white glow, sponsor grid system (1/2/3 column variants with logo-or-name display), photo grid with tile year badges, video card with 16:9 iframe wrapper, product card with sale badge and Barlow Condensed price, winner crown badge overlay, press contact card with backdrop-blur email chip. (9) Updates to mobile-app.js — §10 photo year filter (same chip pattern as schedule but targeting .lbfm-photo-tile). Total: 6 new card-grid templates + footer-mobile.php rewrite + ~9KB CSS + ~1KB JS. Phone visitors now have app-style versions of: Home, Schedule, Map, Pageant, Entertainment, Attractions, all 15 forms, Sponsors, Memories, Merchandise, Past Winners, 2026 Contestants, Press = 27 of 37 pages.
— v29.11.0 — PHASE 4: Mobile templates for all 15 form/registration pages. (1) inc/mobile-form-shell.php — shared partial defining lbfm_render_form_page($args), the rendering function every form mobile template calls. Centralizes the form-page design so all 14 form pages share consistent app-feel and future tweaks happen in ONE file. Accepts config args: eyebrow, eyebrow_icon, title, sub, hero_gradient (blue/gold/teal/purple/green), stats (1-4 stat items), details (what-you'll-need list with emoji icons), form_title (Gravity Form title for lbf_form_id lookup), form_id_fallback (numeric backup), form_intro (paragraph above form), info_cards (cards below form), related (related-link list), footer_note (small print). Renders the full app-style page including page intro chip + title, optional stat strip, optional details card, the Gravity Form card with graceful "form unavailable" + "form not configured" fallbacks, info cards, related links, footer note. (2) Auto-loaded via inc/adaptive.php so any *-mobile.php template can call lbfm_render_form_page() without its own require. (3) 13 form-page mobile templates calling the shell: page-contact-mobile.php (Contact Us), page-volunteer-mobile.php (Volunteer Application with 3-stat strip + 4-detail card), page-donate-mobile.php (Festival Donation with 2 info cards), page-sponsor-mobile.php (Sponsorship Application — NOT page-sponsors.php which is Phase 5), page-waiver-mobile.php (Festival Liability Waiver with footer legal note), page-food-vendor-mobile.php (with 3-stat + 4-detail card), page-vendor-application-mobile.php (general vendor with 3-stat + 4-detail card), page-parade-entry-mobile.php (with 4-detail card), page-bubble-parade-mobile.php (purple gradient), page-sunday-funday-parade-mobile.php (gold gradient, 4-detail card), page-blue-lights-bubbles-parade-mobile.php (purple/night theme to match desktop atmospheric design, 4-detail card), page-car-show-mobile.php (3-stat + 4-detail card), page-pageant-application-mobile.php (purple, 4-detail card, related-links to rules + process), page-template-pageant-application-form-mobile.php (alternate pageant form template). Each form template is ~20-40 lines — content-only config feeding the shared shell. (4) page-register-mobile.php — registration HUB (NOT a form). 9-card vertical list, each card is a different gradient with icon + eyebrow + title + description + chevron, linking to its respective form page. Bottom "Need help deciding? Contact the team" link card. (5) Updates to assets/css/mobile-app.css — §24 form shell styles: gradient-tinted eyebrow chips per variant, responsive stat strip (1/2/3/4 columns), what-you'll-need details card with emoji icons, form card wrapper, complete Gravity Forms restyle scoped under .lbfm-form-gf-wrap (16px iOS-zoom-safe inputs, large rounded touch-friendly fields with focus blue border, accent-color blue checkboxes/radios styled as card chips, gold gradient submit button at full width with shadow, green success confirmation styling, red validation error styling with inline messages, multi-step page navigation buttons styled as ghost-previous + filled-next), graceful "form unavailable" empty state with icon and Contact CTA, info cards below form, footer note styling. §25 registration hub list: link cards with gradient icon (blue/green/purple/gold/teal variants) + eyebrow + title + description + right chevron. Total: 15 new templates + 1 shared partial + ~12KB CSS additions. Zero edits to any existing template, CSS file, or JS file. Phone visitors now have app-style versions of: Home / Schedule / Map / Pageant / Entertainment / Attractions / + all 15 forms = 21 of 37 pages.
— v29.10.0 — PHASE 3: Mobile pageant, entertainment, and attractions templates. Three new app-style mobile pages built on the v29.8.0 foundation, completing the 6 hero-page mobile redesigns. (1) page-pageant-mobile.php — phone-optimized pageant landing with deep-purple royal hero card featuring the festival year's contestant count as a hero stat (giant Barlow Condensed number) plus gold "Apply Now" + ghost "Read Rules" CTA buttons, 2x2 quick-access tile grid (Contestants jump-link / Apply gold tile / Rules / Past Winners), contestants 2-col card grid pulling from data/pageant.php (lbf_get_pageant_contestants), each contestant card tappable to open a detail sheet showing photo + name + category + hometown + sponsor + bio, secondary "Pageant Journey" link card at the bottom routing to the pageant process page, graceful empty state when no contestants are published yet. (2) page-entertainment-mobile.php — phone-optimized lineup page with cinematic featured-headliner card (3:4 aspect ratio, full-bleed photo with dark gradient + gold "Headliner" badge + Barlow Condensed name + genre + day/time/stage meta), day filter chips (All Days / Thu / Fri / Sat / Sun — link-based filtering via ?day= query param), 2-col performer card grid each showing photo + day badge overlay + name + genre + time, tap any performer card to open detail sheet with hero photo + name + tagline + bio + day/time/stage meta + social link icons (website / Facebook / Instagram / Spotify) — data from data/performers.php (lbf_get_all_performers). (3) page-attractions-mobile.php — phone-optimized attractions browser with category filter chips (auto-built from attraction filter slugs in the data — Food/Rides/Games/Family/Crafts/Exhibits etc. with friendly label mapping), horizontal-scroll "Don't Miss" featured strip showing attractions tagged as featured, full attraction 2-col card grid below with photo or emoji icon fallback + badge + name + location, tap any card to open detail sheet with full blurb + location + "Learn More" CTA routing to the attraction's own page, bottom "View Festival Map" link card cross-linking to map page — data from data/attractions.php (lbf_get_attractions). (4) Updates to assets/css/mobile-app.css — added §19 shared components (section padding, small tile variants, gold tile for primary actions, generic link card with right-chevron in purple/teal/gold variants), §20 pageant styles (deep-purple royal hero with crown watermark + giant Barlow stat, contestant card grid 2-col, contestant cards with photo + name + category fallback), §21 entertainment styles (cinematic 3:4 featured card with gradient overlay + gold badge + cinematic typography, performer grid with day-badge photo overlay + genre pill + Barlow time), §22 attractions styles (horizontal featured strip with cards, attraction grid with emoji-fallback when no photo + gold "tag" badge + location with pin icon), §23 detail sheet styles (sheet variant with image hero at top + scrollable padded body + floating close button + cat/title/tagline/meta/bio/socials/CTA layout — reusable across all three page types). (5) Updates to assets/js/mobile-app.js — added §8 detail-sheet open/close system using event delegation (any element with data-lbfm-sheet-trigger="id" opens the sheet, cloning the matching <template id="id"> into the sheet mount point, supports backdrop tap / Escape / handle tap / close button), §9 attraction category filter (same chip-pattern as schedule but targets .lbfm-attraction-card with data-cat). Phone visitors now have app-style versions of all 6 hero pages: Home / Schedule / Map / Pageant / Entertainment / Attractions. The 31 remaining pages still use the existing responsive desktop templates (mobile polish for those comes in Phase 4). Tablets + desktops unchanged. Total: 3 new PHP templates, ~16KB added to mobile-app.css, ~4KB added to mobile-app.js. Zero edits to any existing template, CSS file, or JS file.
— v29.9.0 — PHASE 2: Mobile schedule + map templates. Two new app-style mobile pages built on the v29.8.0 adaptive foundation. (1) page-schedule-mobile.php — phone-optimized festival schedule with sticky day chips at the top (Thu/Fri/Sat/Sun with a today-dot indicator when in festival week), optional category filter chips (auto-populated from event categories present in selected day), vertical event stream where each event renders as a card with a dedicated time block on the left and title/category/venue/short-description on the right, three event states with distinct styling (LIVE NOW events get a thicker gold border + glow + pulsing-dot "Live Now" label badge, UP NEXT events get a gold left-border accent + "Up Next" label badge, PAST events fade to 50% opacity but stay visible so users can see what they missed), live state detection only fires when viewing today's tab during festival week (Aug 20–23 of active festival year), a floating "Jump to now" action button appears on today's tab during festival week and smooth-scrolls to the current live event or next upcoming event (offset 120px so the target card lands below the sticky day chips), graceful empty state when a day has no published events yet, all data reads from data/schedule.php (lbf_get_schedule_days, lbf_get_schedule_by_day) so the same events show on desktop and mobile with zero content duplication. (2) page-map-mobile.php — phone-optimized festival map with minimal page intro (no big hero), address card with one-tap Directions button opening Google Maps, filter chips (All / Stages / Food / Vendors / Restrooms / Parking — visual state only in v1, full filtering pending a places data layer), main map card embedding the Google Maps iframe from _lbf_map_embed page meta at 4:3 mobile aspect ratio with "Open full map" link in card footer, separate tappable Festival Grounds Map card if a grounds image is uploaded (_lbf_grounds_map_img — tap opens fullscreen in new tab), 2x2 stats grid (Free Parking / Entrances / Stages / Food Stalls — values editable via theme mods lbf_map_stat1_n through lbf_map_stat4_n), Getting There card list with separate Google Maps / Apple Maps / View Schedule action cards. (3) Updates to assets/css/mobile-app.css — added §15 shared page intro component (eyebrow chip + big Barlow Condensed title + sub copy, reusable across all future mobile inner pages), §16 day-chip and category-chip components (sticky day chips with today-dot indicator and is-active navy fill, category chips with horizontal scroll), §17 event stream styles (event card with time block, three states for past/live/next, jump-to-now FAB), §18 map page styles (address card, map iframe card, grounds-map card, by-the-numbers stats grid, getting-there info list). (4) Updates to assets/js/mobile-app.js — added §5 schedule category filtering (chips show/hide events client-side without page reload), §6 map chip filter placeholder (visual state toggle only — wires to real filtering when places data layer exists), §7 jump-to-now smooth scroll. Both new pages adapt automatically — phones see the mobile templates, tablets and desktops see the existing page-schedule.php and page-map.php unchanged. Total: 2 new PHP templates, ~9KB added to mobile-app.css, ~2KB added to mobile-app.js. Zero edits to any existing template, CSS file, or JS file.
— v29.8.0 — PHASE 1: Adaptive mobile foundation + app-style homepage. Phones now get a dedicated native-app-style homepage layout while tablets and desktops continue to render the existing responsive templates. Foundation pieces: (1) inc/adaptive.php — phone detector lbf_is_phone() distinguishing phones from tablets via user-agent inspection (iPad-aware, with ?lbf_view=mobile/desktop query override + cookie persistence for testing), template_include filter that swaps to *-mobile.php variants when present, helper functions lbf_get_mobile_header() / lbf_get_mobile_footer() that mobile templates call directly, conditional asset enqueue (mobile CSS/JS never load on desktop), Vary: User-Agent header for cache compatibility, .lbf-mobile-app body class. (2) header-mobile.php — branded navy sticky header with festival logo wordmark and search/notification icon buttons (icons inert in v1, to be wired in later phase). (3) footer-mobile.php — fixed bottom tab bar (Home / Schedule / Map / Pageant / More) with server-side active-state detection and Lucide icons, plus a slide-up "More" sheet containing Entertainment, Attractions, Sponsors, Vendor Registration, Volunteer, Donate, About, FAQ, Contact, Accessibility links. (4) front-page-mobile.php — full app-style mobile homepage matching the approved Phase 0 mockup: cinematic hero card with festival logo + AUG 20–23 date + gold "Plan Your Visit" CTA, live countdown strip ticking days/hours/minutes until opening day, 2x3 quick-access tile grid with gradient-colored tiles for Schedule / Map / Entertainment / Pageant / Vendors / Sponsors (each routes to the corresponding page), 3-stat row (4 Days / 60+ Vendors / FREE Parking — all editable via theme mods lbf_home_m_stat1_n etc.), festival-week-only "Today" card showing live event + up next + day label (auto-shown only during Aug 20–23 window, hidden the rest of the year), recent news feed (3 most recent posts with category tags + thumbnails), horizontal-scrollable sponsor strip pulling from existing sponsors plugin data. (5) assets/css/mobile-app.css — full mobile design system: navy + gold festival palette, Barlow Condensed display + Plus Jakarta Sans body, light blue tinted bg (#eef3fc not pure white), safe-area-inset handling for iPhone X+, deep navy fixed bottom tab bar with gold-active state and top indicator line, slide-up bottom sheet with backdrop, tap feedback on cards/tiles/buttons, dynamic viewport units (dvh) for proper height handling. (6) assets/js/mobile-app.js — sheet open/close mechanics, live countdown ticker updating every 60s, link interception (sheet closes when navigating away). Tablets + desktops: completely unchanged — they don't load any of the new CSS or JS files and use the existing templates. Architecture: every future *-mobile.php page automatically routes via the switcher (zero per-page wiring). Total: 1 require line added to functions.php, version bump in style.css. Zero edits to any existing template, CSS file, or JS file. Removal: delete inc/adaptive.php, header-mobile.php, footer-mobile.php, front-page-mobile.php, assets/css/mobile-app.css, assets/js/mobile-app.js, and the one require line — theme reverts to byte-identical v29.6.1.
— v29.6.1 — Added dark-mode Gravity Forms field styling for the Blue Lights & Bubbles Parade entry form. Form was previously rendering invisible (default dark text on the dark "Application Desk" navy panel). Now: labels white, input fields cream-fill with navy text and gold focus rings, submit button gold with navy text matching the festival CTA grammar, description/error text light-muted, required asterisks gold. Sunday Funday Parade form is unaffected (light theme renders correctly without overrides). 
— v29.6 — Restored lbf_form_id() helper in functions.php (lost in a prior release between v29.5.14 and v29.5.58). Fixed Sunday Funday Parade page lookup string to match the actual Gravity Form title 'Sunday Funday Parade Entry' (was looking up 'Sunday Funday Parade Application'). Blue Lights & Bubbles Parade page lookup string was already correct ('Blue Lights & Bubbles Parade Application' matches its plugin form). Both parade pages now render their respective Gravity Forms inline once the corresponding setup plugin (lbf-parade-setup or lbf-blb-parade-setup) has been activated and Step 1 has been run.
*/



:root {
  --header-h: 82px; /* floating card: 62px inner + 10px top padding + 10px gap */
  --blue:      #0037a7;
  --blue-dark: #002580;
  --gold:      #f3c303;
  --gold-dark: #c9a000;
  --green:     #007f00;
  --white:     #ffffff;
  --bg:        #f8faff;
  --bg2:       #eef2fc;
  --text:      #0e1525;
  --text-2:    #374151;
  --text-3:    #6b7280;
  --border:    #c8d6f5;
  --radius:    12px;
  --shadow:    0 4px 24px rgba(0,55,167,0.10);

  /* ── Blueprint §11.1: Spacing tiers ── */
  --space-xl:  6rem;
  --space-std: 4rem;
  --space-sm:  2rem;

  /* ── Blueprint §11.1: Gradient palette ── */
  --grad-blue:    linear-gradient(135deg, #001a6e 0%, #0037a7 60%, #1a4fc4 100%);
  --grad-night:   linear-gradient(135deg, #000820 0%, #001a5e 35%, #003399 100%);
  --grad-pageant: linear-gradient(135deg, #1a0050 0%, #3b0080 40%, #0037a7 100%);
  --grad-teal:    linear-gradient(135deg, #001a6e 0%, #0037a7 50%, #0e7490 100%);
  --grad-navy:    linear-gradient(135deg, #000820 0%, #001050 60%, #000820 100%);
}

*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

html { scroll-padding-top: var(--header-h);
 scroll-behavior: smooth; }

body {
  font-family: 'Plus Jakarta Sans', system-ui, -apple-system, sans-serif;
  font-size: 16px;
  line-height: 1.6;
  color: var(--text);
  background: var(--white);
}

a { color: var(--blue); text-decoration: none; }
a:hover { text-decoration: underline; }
a:focus-visible { outline: 3px solid var(--gold); outline-offset: 2px; border-radius: 3px; }

img { max-width: 100%; height: auto; display: block; }

.container { max-width: 1200px; margin: 0 auto; padding: 0 1.5rem; }


/* ──────────────────────────────────────────────────────────────────────
   GLOBAL PAGE-SHELL UTILITY  (v29.21.1)
   ──────────────────────────────────────────────────────────────────────
   Single canonical wrapper for any page that needs the rounded-card
   shell pattern (the look used by front-page, schedule, about-our-
   pageant, and now FAQ). Usage:

     <div class="lbf-page-canvas">
       <div class="lbf-page-card">
         [page content: hero + sections]
       </div>
     </div>

   The canvas handles centering, max-width, and the top padding that
   pushes the card below the site header (with admin-bar adjustments
   for logged-in editors). The card handles the radius, border, drop
   shadow, and overflow:hidden for clipping hero/CTA gradients.

   Pages with their own bespoke wrappers (v3-outer-card, s3-outer,
   pag-v3-outer) are not affected. This utility is for new pages and
   for migration of pages that don't yet have a wrapper.
   ────────────────────────────────────────────────────────────────── */

.lbf-page-canvas {
  max-width: 1480px;
  margin: 0 auto;
  padding: var(--header-h, 82px)
           clamp(.75rem, 2vw, 1.5rem)
           clamp(1.5rem, 3vw, 2.5rem);
}
.admin-bar .lbf-page-canvas {
  padding-top: calc(var(--header-h, 82px) + 32px);
}
@media (max-width: 782px) {
  .admin-bar .lbf-page-canvas {
    padding-top: calc(var(--header-h, 82px) + 46px);
  }
}

.lbf-page-card {
  overflow: hidden;
  border-radius: 28px;
  border: 1px solid rgba(255, 255, 255, .7);
  box-shadow: 0 32px 100px rgba(0, 51, 172, .13);
  background: rgba(255, 255, 255, .92);
}
@media (max-width: 640px) {
  .lbf-page-card { border-radius: 20px; }
}


.screen-reader-text {
  position: absolute !important;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0,0,0,0);
  white-space: nowrap; border: 0;
}
.screen-reader-text:focus {
  position: fixed !important;
  top: 1rem; left: 1rem;
  width: auto; height: auto;
  padding: .75rem 1.5rem;
  background: var(--blue);
  color: #fff;
  font-size: 1rem;
  font-weight: 700;
  border-radius: var(--radius);
  z-index: 99999;
  clip: auto;
  white-space: normal;
}

/* ---- BUTTONS ---- */
.btn {
  display: inline-flex; align-items: center; gap: .5rem;
  padding: .65rem 1.4rem;
  border-radius: 8px;
  font-family: 'Plus Jakarta Sans', sans-serif;
  font-size: 0.875rem; font-weight: 700; letter-spacing: 0.01em; text-transform: none;
  cursor: pointer; border: 2px solid transparent;
  transition: all .2s;
  text-decoration: none;
}
.btn:hover { text-decoration: none; transform: translateY(-1px); }
.btn-blue   { background: var(--blue); color: #fff; border-color: var(--blue); }
.btn-blue:hover { background: var(--blue-dark); }
.btn-gold   { background: var(--gold); color: var(--text); border-color: var(--gold); }
.btn-gold:hover { background: var(--gold-dark); }
.btn-green  { background: var(--green); color: #fff; border-color: var(--green); }
.btn-ghost-white { background: transparent; color: #fff; border-color: rgba(255,255,255,.5); }
.btn-ghost-white:hover { background: rgba(255,255,255,.1); }
.btn-lg { padding: .85rem 1.8rem; font-size: 1.05rem; }
.btn-full { width: 100%; justify-content: center; }

/* ---- TAGS ---- */
.tag {
  display: inline-block;
  padding: .2rem .65rem;
  border-radius: 20px;
  font-size: .75rem; font-weight: 700; letter-spacing: .04em; text-transform: uppercase;
}
.tag-blue   { background: #e8eefb; color: var(--blue); }
.tag-gold   { background: #fdf5cc; color: var(--gold-dark); }
.tag-green  { background: #e6f4e6; color: var(--green); }
.tag-purple { background: #f0e8fb; color: #6d28d9; }

/* ---- SECTION HELPERS ---- */
/* Legacy fallback — keeps old markup working while new tiers roll out */
.section { padding: 2.5rem 0 5rem; }
.section-alt { background: var(--bg); }

/* ── Blueprint §11.2: Spacing Tier Classes ── */
.sec-xl    { padding: var(--space-xl) 0 calc(var(--space-xl) + 1rem); }
.sec-std   { padding: var(--space-std) 0 var(--space-std); }
.sec-sm    { padding: var(--space-sm) 0 var(--space-sm); }
.sec-flush { padding: 0; }

/* ── Blueprint §2: Container Variants ── */
.container-narrow { max-width: 720px;  margin: 0 auto; padding: 0 1.5rem; }
.container-wide   { max-width: 1400px; margin: 0 auto; padding: 0 1.5rem; }

/* ── Blueprint §11.3: Post-Hero Lift Connector ── */
.post-hero-first {
  margin-top: -3rem;
  padding-top: 5rem;
  background: var(--white) !important;
  border-radius: 32px 32px 0 0 !important;
  position: relative;
  z-index: 2;
}

/* ── Blueprint §11.4: CTA Band Gradient Variants ── */
.sp-cta-band--blue    { background: var(--grad-blue); }
.sp-cta-band--night   { background: var(--grad-night); }
.sp-cta-band--pageant { background: var(--grad-pageant); }
.sp-cta-band--teal    { background: var(--grad-teal); }
.sp-cta-band--navy    { background: var(--grad-navy); }

/* ── Blueprint §11.5: Schedule Row Alternation ── */
.sp-sched-list .sp-sched-row:nth-child(even) { background: var(--bg); }
.sp-sched-row--featured { border-left: 3px solid var(--gold); }

/* ── Blueprint §11.6: Sponsor Logo Container ── */
.sponsor-logo-wrap {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 160px; height: 90px;
  padding: 1rem;
  border: 1px solid var(--border);
  border-radius: 8px;
  background: #fff;
  transition: box-shadow .2s;
}
.sponsor-logo-wrap:hover { box-shadow: var(--shadow); }
.sponsor-logo-wrap img { max-width: 100%; max-height: 100%; object-fit: contain; }

/* ── Blueprint §11.7: Slim Hero ── */
.sp-pg-hero--slim {
  padding: 6rem 1.5rem 3.5rem;
  min-height: 280px;
}
.sp-pg-hero--slim .sp-pg-hero__stats { display: none; }

/* ── Blueprint §11.8: Breadcrumb / Context Strip ── */
.ctx-strip {
  background: var(--bg);
  border-bottom: 1px solid var(--border);
  height: 48px;
  display: flex;
  align-items: center;
}
.ctx-strip__inner {
  display: flex;
  justify-content: space-between;
  align-items: center;
  max-width: 1200px;
  margin: 0 auto;
  padding: 0 1.5rem;
  width: 100%;
}
.ctx-strip__crumb { font-size: .82rem; color: var(--text-3); }
.ctx-strip__crumb a { color: var(--blue); }
.ctx-strip__action { font-size: .82rem; color: var(--blue); font-weight: 600; }

/* ── Blueprint §5.1: Same-background connector ── */
.sec-connector { border-top: 1px solid var(--border); }

/* ── Blueprint §4: Section header .sec-hd gap fix ── */
.sec-hd { text-align: center; margin-bottom: 2rem; }

/* ── Blueprint §9.1: Card elevation system ── */
.card-elevated {
  box-shadow: 0 4px 24px rgba(0,55,167,0.10);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  transition: box-shadow .2s, transform .2s, border-color .2s;
}
.card-elevated:hover {
  box-shadow: 0 12px 40px rgba(0,55,167,0.14);
  transform: translateY(-4px);
  border-color: transparent;
}

/* ── Blueprint §8: CTA Band base layout ── */
.sp-cta-band { padding: var(--space-sm) 0; }
.sp-cta-band__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 2rem;
  flex-wrap: wrap;
}
.sp-cta-band__text h2 { color: #fff; }
.sp-cta-band__text p  { color: rgba(255,255,255,.8); margin-top: .5rem; }
.sp-cta-band__btns    { display: flex; gap: .75rem; flex-wrap: wrap; align-items: center; }
@media (max-width: 767px) {
  .sp-cta-band__inner { flex-direction: column; text-align: center; }
  .sp-cta-band__btns  { justify-content: center; }
}

/* ── Blueprint §13.1: Transparent header on hero pages ── */
/* ── HEADER: Homepage top state (transparent, blended into shell) ──
   Applied via body.home — renders before JS so no white flash on load.
   The .lbf-top-shell in front-page.php owns the sky-blue background,
   making the header visually part of the same region as the hero.
   ── */
body.home #site-header {
  /* Background/appearance controlled by .nav-card in lbf-nav-v2.css */
  background: transparent !important;
  backdrop-filter: none !important;
  -webkit-backdrop-filter: none !important;
  box-shadow: none !important;
}
/* Text stays dark blue on light sky background */
body.home #site-header .nav-menu a,
body.home #site-header .site-logo-text strong,
body.home #site-header .site-logo-text span { color: #17357b; }
/* Plan Visit CTA: always gold box — same as scrolled state */
/* body.home .nav-cta — controlled by lbf-nav-v2.css */
/* Hamburger bars: dark blue on light shell */
body.home #site-header .menu-toggle .bar { background: #17357b; }

/* ── HEADER: Scrolled state (solid, conventional) ──
   body.is-scrolled added by JS when user scrolls past 80px.
   Uses body.home.is-scrolled to win specificity over body.home rules.
   Also covers non-home pages with body.is-scrolled alone.
   ── */
body.home.is-scrolled #site-header,
body.is-scrolled #site-header {
  /* Appearance controlled by body.is-scrolled .nav-card in lbf-nav-v2.css */
  background: transparent !important;
  box-shadow: none !important;
  --header-h: 68px;
}
/* v29.3.34 — Dark-text-on-scroll rule restructured to NOT match top-level
   nav links at all. Top-level link colors are fully controlled by
   lbf-nav-v2.css (which knows about the blue active pill and hover states).
   This rule only darkens SUB-MENU descendant links and the site logo when
   the page is scrolled. That removes the specificity battle that was
   causing active placeholder parents (like the Pageant tab) to render
   dark text against the scrolled-state white nav background. */
body.home.is-scrolled #site-header .nav-menu .sub-menu a:not(:hover):not(:focus-within):not([aria-current="page"]),
body.home.is-scrolled #site-header .site-logo-text strong,
body.home.is-scrolled #site-header .site-logo-text span,
body.is-scrolled #site-header .nav-menu .sub-menu a:not(:hover):not(:focus-within):not([aria-current="page"]),
body.is-scrolled #site-header .site-logo-text strong,
body.is-scrolled #site-header .site-logo-text span { color: var(--text) !important; }
/* v29.3.34 — Top-level nav links (direct children of .nav-menu) go dark
   on scroll ONLY when they are NOT the current section. Excludes every
   WP active-state class variant plus our is-section-current marker so
   placeholder parents like "Pageant" stay white when one of their
   sub-pages is the current page. */
body.is-scrolled #site-header .nav-menu > li:not(.current-menu-item):not(.current_page_item):not(.current-menu-parent):not(.current_page_parent):not(.current-menu-ancestor):not(.current_page_ancestor):not(.is-section-current):not(.is-open) > a:not(:hover):not(:focus-within):not([aria-current="page"]) {
    color: var(--text) !important;
}
/* is-scrolled .nav-cta — controlled by lbf-nav-v2.css */
body.home.is-scrolled #site-header .menu-toggle .bar,
body.is-scrolled #site-header .menu-toggle .bar { background: var(--text) !important; }

/* ── WordPress Admin Bar compensation ──
   When logged in, WP adds 32px (desktop) / 46px (mobile) admin bar.
   The fixed header must sit below it, not under it. ── */
.admin-bar #site-header {
  top: 32px;
}
.admin-bar .lbf-hs-date,
.admin-bar .lbf-hs-eyebrow,
.admin-bar .lbf-hs-year,
.admin-bar .lbf-hs-headline,
.admin-bar .lbf-hs-tagline-brush,
.admin-bar .lbf-hs-actions {
  /* No change needed — padding-top on hero handles clearance */
}
@media screen and (max-width: 782px) {
  .admin-bar #site-header { top: 46px; }
}


/* Legacy: keep header-transparent for interior pages that still use it */
#site-header.header-transparent {
  background: rgba(0,0,0,0);
  box-shadow: none;
}

/* ── Blueprint §6.1: Hero gradient variants ── */
.sp-pg-hero--night   { background: var(--grad-night); }
.sp-pg-hero--pageant { background: var(--grad-pageant); }

.sec-hd { text-align: center; margin-bottom: 1.5rem; }
.sec-tag {
  display: inline-block;
  padding: .3rem 1rem;
  background: rgba(0,55,167,.08);
  color: var(--blue);
  border-radius: 20px;
  font-size: .8rem; font-weight: 700; letter-spacing: .08em; text-transform: uppercase;
  margin-bottom: .75rem;
}
.sec-tag.light { background: rgba(255,255,255,.15); color: #fff; }
.sec-h {
  font-family: 'Barlow Condensed', sans-serif;
  font-size: clamp(2rem, 4vw, 2.8rem);
  font-weight: 900; text-transform: uppercase; letter-spacing: -.01em;
  color: var(--text); margin-bottom: .375rem;
}
.sec-h span { color: var(--blue); }
.sec-h.on-dark { color: #fff; }
.sec-h.on-dark span { color: var(--gold); }
.sec-p { color: var(--text-3); font-size: 1.05rem; max-width: 600px; margin: 0 auto .375rem; }
.sec-p.on-dark { color: rgba(255,255,255,.8); }
.sec-extra { color: var(--text-2); font-size: 1rem; max-width: 600px; margin: .5rem auto 0; text-align: center; }
.sec-extra.on-dark { color: rgba(255,255,255,.75); }

/* ---- HEADER ---- */
/* #site-header — fully controlled by lbf-nav-v2.css */'
#site-header { position: fixed !important; z-index: 9999; }
#site-header .nav-menu a,
#site-header .site-logo-text strong,
#site-header .site-logo-text span { color: var(--text); transition: color .3s; }

.nav-inner {
  max-width: 1200px; margin: 0 auto;
  padding: 0 1.5rem 0 0.25rem;  /* reduced left padding moves logo ~15% left */
  /* height overridden by lbf-nav-v2.css */
  display: flex; align-items: center; gap: 1.5rem;
  transition: height 0.3s ease;
  overflow: visible; /* allow logo to be taller than the nav bar */
}

.site-branding {
  display: flex; align-items: center; gap: .75rem;
  text-decoration: none; flex-shrink: 0;
  overflow: visible; /* let logo overflow nav-inner height */
}
/* Custom logo: smooth resize on scroll via height (more reliable than max-height) */
.site-branding .custom-logo-link { display: flex; align-items: center; overflow: visible; }
.site-branding .custom-logo {
  /* Base height — JS overrides this dynamically for smooth scroll animation */
  height: 64px !important;
  width: auto !important;
  max-width: none !important;
  display: block;
  object-fit: contain;
  /* No CSS transition here — JS applies transition directly on the element */
}
/* CSS fallback for scrolled state (JS is primary) */
body.is-scrolled .site-branding .custom-logo {
  height: 40px !important;
}
/* ── Bundled nav logo (lbf-nav-logo.webp) ── */
.site-branding .lbf-nav-logo {
  height: 64px !important;
  width: auto !important;
  max-width: none !important;
  display: block;
  object-fit: contain;
}
body.is-scrolled .site-branding .lbf-nav-logo {
  height: 40px !important;
}
.site-logo-mark { font-size: 2rem; line-height: 1; }
.site-logo-text strong {
  display: block;
  font-family: 'Outfit', 'Plus Jakarta Sans', sans-serif;
  font-size: 1rem; font-weight: 800; text-transform: uppercase;
  color: var(--blue); letter-spacing: .04em;
}
.site-logo-text span { display: block; font-size: .7rem; color: var(--gold-dark); }

.menu-toggle {
  display: none;
  flex-direction: column; justify-content: center; gap: 5px;
  width: 40px; height: 40px;
  background: none; border: none; cursor: pointer;
  margin-left: auto;
  padding: 6px;
}
.menu-toggle .bar {
  display: block; height: 2px; background: var(--blue); border-radius: 2px;
  transition: all .3s;
}

#primary-navigation {
  display: flex; align-items: center; gap: .25rem;
  margin-left: auto;
}
.nav-menu {
  display: flex; align-items: center; gap: .25rem;
  list-style: none;
}
.nav-menu li a {
  display: block; padding: .5rem .8rem;
  color: var(--gray);
  font-size: 0.9rem; font-weight: 600; font-family: 'Plus Jakarta Sans', sans-serif;
  border-radius: 6px;
  transition: background 0.18s ease, color 0.18s ease, box-shadow 0.18s ease;
  text-decoration: none;
}
.nav-menu li a:hover, .nav-menu li a[aria-current="page"] {
  color: var(--blue);
  background: rgba(0,55,167,0.10);
  box-shadow: inset 0 -2.5px 0 var(--blue);
  font-weight: 700;
}
/* .nav-cta — fully controlled by lbf-nav-v2.css */

/* ---- HERO ---- */
.hero-section {
  min-height: 100vh;
  background: linear-gradient(135deg, #001a6e 0%, var(--blue) 40%, #1a4fc4 70%, #0e3a9e 100%);
  display: flex; align-items: center;
  padding: 8rem 1.5rem 6rem;
  position: relative; 
}
/* v13 overrides — must come right after to win the cascade */
.hero-section.hero-v13 {
  align-items: flex-start !important;
  padding: 0 0 4rem !important;
}
/* Spacer div pushes pill content below the fixed header — immune to cascade */
.v13-header-spacer {
  display: block;
  height: calc(var(--header-h) + 2.5rem);
  width: 100%;
  pointer-events: none;
  flex-shrink: 0;
}
.hero-dots {
  position: absolute; inset: 0;
  background-image: radial-gradient(rgba(255,255,255,.06) 1px, transparent 1px);
  background-size: 32px 32px;
  z-index: 2; pointer-events: none;
}
.hero-glow {
  position: absolute; top: -200px; right: -200px;
  width: 600px; height: 600px; border-radius: 50%;
  background: radial-gradient(circle, rgba(243,195,3,.12) 0%, transparent 70%);
  z-index: 2; pointer-events: none;
}
.hero-inner {
  max-width: 1200px; margin: 0 auto; width: 100%;
  display: grid; grid-template-columns: 1fr 1fr; gap: 3rem; align-items: center;
  position: relative; z-index: 3;
}
.hero-left { display: flex; flex-direction: column; }
.hero-right { display: flex; align-items: center; justify-content: center; }
.hero-right-img-wrap {
  /* width, max-width, aspect-ratio, margin-top, border-radius, border,
     box-shadow, background all set via inline style from Customizer */
  overflow: hidden;
  position: relative;
  flex-shrink: 0;
}
.hero-right-img {
  width: 100%; height: 100%;
  display: block;
  /* object-fit and object-position set via inline style */
}
.hero-right-overlay {
  position: absolute; inset: 0;
  pointer-events: none;
  border-radius: inherit;
}
.hero-right-placeholder {
  /* width, max-width, border-radius, border, background set via inline style */
  overflow: hidden;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 1rem; color: rgba(255,255,255,.4); text-align: center;
  flex-shrink: 0;
}
.hero-right-placeholder-icon { font-size: 3rem; }
.hero-right-placeholder p { font-size: .85rem; line-height: 1.5; }
.hero-right-placeholder strong { color: rgba(255,255,255,.65); }
.hero-chip {
  display: inline-block;
  padding: .35rem 1rem;
  background: rgba(243,195,3,.15);
  border: 1px solid rgba(243,195,3,.3);
  border-radius: 20px;
  color: var(--gold);
  font-size: .8rem; font-weight: 700; letter-spacing: .08em; text-transform: uppercase;
  margin-bottom: 1.25rem;
}
.hero-title {
  font-family: 'Barlow Condensed', sans-serif;
  font-size: clamp(3rem, 8vw, 5.5rem);
  font-weight: 900; text-transform: uppercase;
  line-height: .95; letter-spacing: -.02em;
  color: #fff; margin-bottom: 1.25rem;
}
.hero-title .gold { color: var(--gold); }
.hero-sub { color: rgba(255,255,255,.8); font-size: 1.1rem; max-width: 500px; margin-bottom: 1.5rem; }
.hero-date-pill {
  display: inline-flex; align-items: center; gap: .75rem;
  padding: .5rem 1rem;
  background: rgba(255,255,255,.08);
  border: 1px solid rgba(255,255,255,.15);
  border-radius: 8px; color: rgba(255,255,255,.9);
  font-size: .9rem; margin-bottom: 2rem;
}
.hero-date-pill .sep {
  width: 1px; height: 16px; background: rgba(255,255,255,.3);
}
.hero-btns { display: flex; gap: .75rem; flex-wrap: wrap; }

/* Compact inline countdown — sits below date pill in left column */
.hero-cd-inline {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: .6rem;
  margin-top: 1.5rem;
  padding: 1rem 1.25rem 1.1rem;
  border: 1px solid transparent; /* overridden by inline style */
  width: 100%;
  box-sizing: border-box;
}
.hero-cd-label {
  font-size: .83rem; font-weight: 700; letter-spacing: .1em; text-transform: uppercase;
  flex-shrink: 0; text-align: center;
}
.hero-cd-boxes {
  display: flex; align-items: center; gap: .35rem;
}
.hero-cd-box {
  display: flex; flex-direction: column; align-items: center;
  background: rgba(0,0,0,.25); border-radius: 7px; /* overridden by inline */
  padding: .46rem .63rem; min-width: 51px;
}
.hero-cd-n {
  font-family: 'Barlow Condensed', sans-serif;
  font-size: 1.55rem; font-weight: 900; color: #fff; line-height: 1; /* +15% from 1.35rem */
}
.hero-cd-l {
  font-size: .6rem; color: rgba(255,255,255,.5);
  text-transform: uppercase; letter-spacing: .06em; margin-top: .15rem;
}
.hero-cd-sep {
  font-size: 1.27rem; font-weight: 900; color: rgba(255,255,255,.4); /* +15% from 1.1rem */
  line-height: 1; padding-bottom: .9rem;
}

/* ---- STATS ---- */
.stats-strip { background: var(--blue); padding: 2.5rem 0; }
.stats-inner {
  max-width: 1200px; margin: 0 auto; padding: 0 1.5rem;
  display: grid; grid-template-columns: repeat(4,1fr); gap: 1rem;
}
.stat-cell { text-align: center; }
.stat-n {
  font-family: 'Barlow Condensed', sans-serif;
  font-size: 2.5rem; font-weight: 900; color: var(--gold);
  line-height: 1;
}
.stat-l { font-size: .85rem; color: rgba(255,255,255,.7); text-transform: uppercase; letter-spacing: .05em; margin-top: .25rem; }

/* ---- ATTRACTIONS ---- */
.attr-grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(166px,1fr)); gap: 1rem;
  align-items: start;
}
.attr-card {
  background: #fff; border-radius: var(--radius);
  border: 1px solid var(--border);
  overflow: hidden; transition: all .2s;
  box-shadow: var(--shadow);
}
.attr-card:hover { transform: translateY(-3px); box-shadow: 0 8px 32px rgba(0,55,167,.15); }
.attr-img {
  height: 120px; background: var(--bg2);
  display: flex; align-items: center; justify-content: center;
  font-size: 2.6rem; overflow: hidden;
}
.attr-img img { width: 100%; height: 100%; object-fit: cover; }
.attr-body { padding: 0.9rem; }
.attr-body h3 { font-family: 'Barlow Condensed', sans-serif; font-size: 0.95rem; font-weight: 800; text-transform: uppercase; margin-bottom: .3rem; }
.attr-body p { font-size: .78rem; color: var(--text-3); margin-bottom: .5rem; }

/* ---- SCHEDULE ---- */
.day-tabs { display: flex; gap: .5rem; flex-wrap: wrap; margin-bottom: 1.5rem; }
.day-tab {
  padding: .75rem 1.75rem;
  background: var(--bg2); border: 2px solid var(--border);
  border-radius: 8px;
  font-family: 'Barlow Condensed', sans-serif;
  font-weight: 700; font-size: 1.1rem; text-transform: uppercase;
  cursor: pointer; transition: all .2s; color: var(--text-2);
}
.day-tab.active { background: var(--blue); color: #fff; border-color: var(--blue); }
.sched-panel { display: none; }
.sched-panel.active { display: block; }
.sched-list { display: flex; flex-direction: column; gap: .56rem; }
.sched-row {
  display: grid; grid-template-columns: 75px 1fr auto;
  align-items: center; gap: .75rem;
  background: #fff; border-radius: 8px;
  border: 1px solid var(--border);
  padding: .75rem .95rem;
}
.sched-time { font-family: 'Barlow Condensed', sans-serif; font-weight: 700; font-size: .72rem; color: var(--blue); display: flex; flex-direction: column; align-items: center; gap: .15rem; text-align: center; }
.sched-icon { font-size: 1.05rem; line-height: 1; }
.sched-info h4 { font-size: .75rem; font-weight: 700; margin-bottom: .18rem; }
.sched-info p { font-size: .64rem; color: var(--text-3); margin: 0; }
.sched-loc { display: flex; align-items: center; gap: .3rem; }
.sched-map-link { color: var(--blue); text-decoration: none; font-weight: 600; }
.sched-map-link:hover { text-decoration: underline; }
.sched-cat-badge { display: inline-block; padding: .2rem .65rem; border-radius: 20px; font-size: .75rem; font-weight: 700; border: 1px solid; white-space: nowrap; }

/* ---- PAGEANT ---- */
.pageant-section {
  background: linear-gradient(135deg, #001a6e 0%, var(--blue) 60%, #1a4fc4 100%);
  position: relative;
}
.pageant-section::before {
  content: '';
  position: absolute; inset: 0;
  background-image: radial-gradient(rgba(255,255,255,.04) 1px, transparent 1px);
  background-size: 28px 28px;
}
.cat-grid { display: flex; flex-wrap: wrap; gap: .9rem; margin: 0 auto 1.75rem; justify-content: center; align-items: stretch; width: 100%; max-width: 900px; }
.cat-card {
  background: rgba(255,255,255,.08);
  border: 1px solid rgba(255,255,255,.15);
  border-radius: 12px; padding: 1.25rem 1rem; text-align: center;
  width: 130px; flex-shrink: 0;
}
.cat-icon { font-size: 2rem; margin-bottom: .5rem; }
.cat-name { font-family: 'Barlow Condensed', sans-serif; font-weight: 800; font-size: .98rem; text-transform: uppercase; color: #fff; margin-bottom: .25rem; }
.cat-age { font-size: .8rem; color: var(--gold); font-weight: 600; }

/* ---- FORMS GRID ---- */
/* 8 cards: 4x2 on wide, 3 col medium, 2 col narrow, 1 col mobile */
.form-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1.1rem; align-items: start; }
@media (max-width: 1199px) { .form-grid { grid-template-columns: repeat(3, 1fr); gap: 1rem; } }
@media (max-width: 860px)  { .form-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 540px)  { .form-grid { grid-template-columns: 1fr; } }
.form-card {
  background: #fff; border-radius: var(--radius);
  border: 1px solid var(--border);
  border-top: 4px solid var(--blue);
  padding: 1rem;
  box-shadow: var(--shadow);
}
.form-icon { font-size: 1.3rem; margin-bottom: .35rem; }
.form-card h3 { font-family: 'Barlow Condensed', sans-serif; font-size: .9rem; font-weight: 800; text-transform: uppercase; margin-bottom: .3rem; }
.form-card p { font-size: .72rem; color: var(--text-3); margin-bottom: .5rem; }
.feat-list { list-style: none; margin-bottom: 1rem; }
.feat-list li { font-size: .78rem; color: var(--text-2); padding: .2rem 0; padding-left: 1rem; position: relative; }
.feat-list li::before { content: '\2713'; position: absolute; left: 0; color: var(--green); font-weight: 700; }

/* ---- SPONSORS ---- */
.tier-row { margin-bottom: 2.5rem; width: 100%; }
.tier-head { display: flex; align-items: center; gap: 1rem; margin-bottom: 1.25rem; }
.tier-label {
  white-space: nowrap;
  font-family: 'Barlow Condensed', sans-serif;
  font-size: .85rem; font-weight: 800; letter-spacing: .06em; text-transform: uppercase;
  padding: .3rem .9rem; border-radius: 20px;
}
.tp { background: #e8eefb; color: var(--blue); }
.tg { background: #fdf5cc; color: var(--gold-dark); }
.ts { background: #f0f0f0; color: #555; }
.tb { background: #fbe9e0; color: #b45309; }
.tf { background: #f0fdf4; color: #166534; }
.tier-div { flex: 1; height: 1px; background: var(--border); }
.sponsor-row { display: flex; flex-wrap: wrap; gap: 1rem; align-items: center; justify-content: center; }
.sp {
  display: flex; align-items: center; justify-content: center;
  background: #fff; border: 1px solid var(--border);
  border-radius: 10px; overflow: hidden;
  font-weight: 700; color: var(--text-3);
}
.sp-xxl { width: 340px; height: 160px; font-size: 1.2rem; }
.sp-xl { width: 240px; height: 110px; font-size: 1.1rem; }
.sp-lg { width: 180px; height: 80px;  font-size: 1rem; }
.sp-md { width: 140px; height: 65px;  font-size: .9rem; }
.sp-sm { width: 110px; height: 50px;  font-size: .8rem; }
.sp-xs { width:  85px; height: 40px;  font-size: .75rem; }
.sp img { width: 100%; height: 100%; object-fit: contain; padding: .5rem; }
.sp-cta {
  display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 1rem;
  background: var(--bg2); border-radius: var(--radius);
  border: 1px solid var(--border); padding: 1.5rem 2rem;
  margin-top: 1rem;
}
.sp-cta h3 { font-family: 'Barlow Condensed', sans-serif; font-size: 1.2rem; font-weight: 800; text-transform: uppercase; }
.sp-cta p { font-size: .9rem; color: var(--text-3); }

/* ---- DONATE ---- */
.donate-section {
  background: linear-gradient(135deg, #001a6e 0%, #0037a7 50%, #1a4fc4 100%);
  position: relative;
}
.donate-section::before {
  content: '';
  position: absolute; inset: 0;
  background-image: radial-gradient(rgba(255,255,255,.04) 1px, transparent 1px);
  background-size: 28px 28px;
}
.donate-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 3rem; align-items: start; position: relative; z-index: 1; }
.imp-list { list-style: none; margin: .75rem 0; display: flex; flex-direction: column; gap: .55rem; }
.imp-item { display: flex; align-items: flex-start; gap: .6rem; }
.imp-icon { font-size: 1.375rem; flex-shrink: 0; }
.imp-h4 { font-weight: 700; color: #fff; font-size: .975rem; }
.imp-p { font-size: .875rem; color: rgba(255,255,255,.65); margin-top: .08rem; }
.donate-card {
  max-width: 60%;
  margin-left: auto;
  margin-right: auto;
  background: rgba(255,255,255,.06);
  border: 1px solid rgba(255,255,255,.12);
  border-radius: 16px; padding: 1.1rem;
}
.donate-card-h { font-family: 'Barlow Condensed', sans-serif; font-size: .9rem; font-weight: 800; text-transform: uppercase; color: #fff; margin-bottom: .5rem; }
.notice { background: rgba(255,255,255,.08); border-radius: 8px; padding: .75rem 1rem; font-size: .85rem; color: rgba(255,255,255,.7); margin-bottom: 1rem; }
.amt-grid { display: grid; grid-template-columns: repeat(4,1fr); gap: .5rem; margin-bottom: 1rem; }
.amt-btn {
  padding: .45rem .35rem; border: 2px solid rgba(255,255,255,.2);
  background: rgba(255,255,255,.05);
  border-radius: 8px; color: #fff;
  font-family: 'Barlow Condensed', sans-serif;
  font-size: .85rem; font-weight: 700;
  cursor: pointer; transition: all .2s;
}
.amt-btn.active, .amt-btn:hover { background: var(--gold); color: var(--text); border-color: var(--gold); }
.cin {
  width: 100%; padding: .45rem .75rem;
  background: rgba(255,255,255,.08);
  border: 1px solid rgba(255,255,255,.2);
  border-radius: 8px; color: #fff; font-size: .8rem;
  margin-bottom: .5rem;
}
.cin::placeholder { color: rgba(255,255,255,.4); }
.recur-row { display: flex; align-items: center; gap: .5rem; color: rgba(255,255,255,.75); font-size: .9rem; margin-bottom: 1rem; cursor: pointer; }
.pay-row { display: flex; gap: .5rem; margin-top: .75rem; flex-wrap: wrap; }
.pay-chip { padding: .2rem .6rem; background: rgba(255,255,255,.1); border-radius: 4px; font-size: .75rem; color: rgba(255,255,255,.6); }

/* ---- CONTACT ---- */
.contact-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 3rem; }
.info-cards { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; margin: 1.5rem 0; }
.info-card { display: flex; align-items: flex-start; gap: .75rem; padding: 1rem; background: var(--bg2); border-radius: 10px; border: 1px solid var(--border); }
.info-icon { font-size: 1.4rem; flex-shrink: 0; }
.info-text h3 { font-size: .9rem; font-weight: 700; margin-bottom: .2rem; }
.info-text p { font-size: .85rem; color: var(--text-3); }
.info-text a { color: var(--blue); }
.map-box {
  height: 220px; border-radius: 12px; overflow: hidden;
  background: var(--bg2); border: 1px solid var(--border);
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  text-align: center; padding: 1rem; color: var(--text-3); font-size: .9rem;
}
.map-box iframe { width: 100%; height: 100%; border: none; }
.contact-custom-box {
  background: var(--bg2);
  border: 1px solid var(--border);
  border-left: 4px solid var(--blue);
  border-radius: 10px;
  padding: 1.25rem 1.5rem;
  margin-top: 1rem;
}
.contact-custom-box__title {
  font-family: 'Barlow Condensed', sans-serif;
  font-size: 1.05rem; font-weight: 800; text-transform: uppercase;
  letter-spacing: .04em; color: var(--blue);
  margin: 0 0 .5rem;
}
.contact-custom-box__body {
  font-size: .95rem; color: var(--text-2); line-height: 1.65;
}
.cf { background: var(--bg2); border-radius: var(--radius); border: 1px solid var(--border); padding: 1rem; max-width:75%; margin-left:auto; margin-right:auto; }
.cf h3 { font-family: 'Barlow Condensed', sans-serif; font-size: .95rem; font-weight: 800; text-transform: uppercase; margin-bottom: .6rem; }


/* ---- CONTACT SOCIAL CARD ---- */
.contact-social-links { display: flex; flex-direction: column; gap: .45rem; margin-top: .3rem; }
.contact-social-link {
  display: inline-flex; align-items: center; gap: .45rem;
  font-size: .82rem; font-weight: 600; color: var(--blue);
  text-decoration: none; transition: color .2s;
}
.contact-social-link:hover { color: var(--text); text-decoration: underline; }
.contact-social-link--fb { color: #1877f2; }
.contact-social-link--fb:hover { color: #1055a8; }
.contact-social-link--ig { color: #e1306c; }
.contact-social-link--ig:hover { color: #a31049; }
.contact-social-icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 22px; height: 22px; border-radius: 5px;
  background: currentColor; color: #fff !important;
  font-size: .7rem; font-weight: 900; font-style: normal; flex-shrink: 0;
}
.contact-social-link--fb .contact-social-icon { background: #1877f2; color: #fff !important; }
.contact-social-link--ig .contact-social-icon { background: linear-gradient(45deg,#f09433,#e6683c,#dc2743,#cc2366,#bc1888); color: #fff !important; }

/* Shrink GF inputs in .cf for 20% less height */
.cf .gform_wrapper input[type="text"],
.cf .gform_wrapper input[type="email"],
.cf .gform_wrapper input[type="tel"],
.cf .gform_wrapper textarea,
.cf .gform_wrapper select { font-size: .82rem !important; padding: .45rem .65rem !important; }
.cf .gform_wrapper textarea { min-height: 90px !important; }
.cf .gform_wrapper .gfield { margin-bottom: .5rem !important; }
.cf .gform_wrapper .gfield_label { font-size: .78rem !important; }
.cf .gform_wrapper input[type="submit"],
.cf .gform_wrapper button[type="submit"] { padding: .5rem 1.25rem !important; font-size: .82rem !important; }

/* Tight GF inputs in .donate-card--gf — 25% less spacing */
.donate-card--gf .gfield { margin-bottom: .34rem !important; }
.donate-card--gf .gform_fields { gap: 0 !important; }
.donate-card--gf .gfield_label { font-size: .78rem !important; }
.donate-card--gf input[type="text"],
.donate-card--gf input[type="email"],
.donate-card--gf input[type="number"],
.donate-card--gf input[type="tel"],
.donate-card--gf select,
.donate-card--gf textarea { padding: .4rem .65rem !important; font-size: .82rem !important; }
.donate-card--gf textarea { min-height: 70px !important; }
.donate-card--gf .gform_footer input[type="submit"],
.donate-card--gf input[type="submit"] { padding: .5rem 1.1rem !important; font-size: .82rem !important; }

/* ---- NEWSLETTER ---- */
/* ── NEWSLETTER / STAY IN THE LOOP ──────────────────────────────────────── */
/* ══════════════════════════════════════════════════════════════════
   UNIFIED FOOTER  —  uf-* namespace  (v2 — matches screenshot design)
   Scoped completely; does not affect any other section.
   ══════════════════════════════════════════════════════════════════ */

/* ── Outer: full-width, very light blue-white bg ── */
.uf-outer {
  position: relative;
  background: #f0f5ff;
  overflow: hidden;
}
.uf-backdrop {
  position: absolute; inset: 0;
  background-size: cover;
  background-position: center right;
  opacity: 0.06;
  pointer-events: none;
}

/* ── Canvas: max-width 1480px, small vertical padding ── */
.uf-canvas {
  position: relative;
  z-index: 1;
  max-width: 1480px;
  margin: 0 auto;
  padding: 0.875rem clamp(0.75rem, 2vw, 1.5rem) 0.875rem;
}

/* ── Card: single rounded container ── */
.uf-card {
  border-radius: 22px;
  border: 1px solid #d0e0ff;
  box-shadow: 0 4px 20px rgba(54,82,136,0.08);
  overflow: hidden;
  background: #fff;
}

/* ── Shared pill ── */
.uf-pill {
  display: inline-flex;
  align-items: center;
  border-radius: 999px;
  border: 1px solid #c8d9ff;
  background: #fff;
  padding: 3px 12px;
  font-size: 0.625rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--blue, #0037a7);
  font-family: 'Plus Jakarta Sans', system-ui, sans-serif;
  margin-bottom: 0.5rem;
}
.uf-pill--sm {
  font-size: 0.5625rem;
  padding: 2px 10px;
  letter-spacing: 0.14em;
  color: #4169b2;
  border-color: #d7e4ff;
  background: #f5f8ff;
  margin-bottom: 0.375rem;
}

/* ══ TOP RIBBON: Newsletter ══ */
.uf-nl {
  position: relative;
  background: linear-gradient(135deg, #eaf1ff 0%, #f7f9ff 55%, #edf4ff 100%);
  padding: 1.25rem 1.5rem 1.125rem;
}
.uf-corner, .uf-accent-line {
  position: absolute; pointer-events: none;
}
.uf-corner {
  width: 48px; height: 48px;
}
.uf-corner--tl {
  top: 14px; left: 14px;
  border-top: 1px solid rgba(255,255,255,0.8);
  border-left: 1px solid rgba(255,255,255,0.8);
  border-radius: 14px 0 0 0;
}
.uf-corner--tr {
  top: 14px; right: 14px;
  border-top: 1px solid #c7d9ff;
  border-right: 1px solid #c7d9ff;
  border-radius: 0 14px 0 0;
  opacity: 0.7;
}
.uf-accent-line {
  bottom: 0; left: 1.5rem; right: 1.5rem;
  height: 1px;
  background: linear-gradient(90deg, transparent, #cfe0ff, transparent);
}

.uf-nl-inner {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  align-items: flex-start;
}
@media (min-width: 860px) {
  .uf-nl-inner {
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
    gap: 1.5rem;
  }
}

.uf-nl-copy { flex: 1; min-width: 0; }
.uf-nl-h {
  font-family: 'Outfit', system-ui, sans-serif;
  font-size: clamp(0.9375rem, 1.4vw, 1.0625rem);
  font-weight: 600;
  line-height: 1.35;
  color: #183153;
  margin: 0 0 0.25rem;
}
.uf-nl-sub {
  font-family: 'Plus Jakarta Sans', system-ui, sans-serif;
  font-size: 0.8125rem;
  line-height: 1.6;
  color: #4f6487;
  margin: 0;
  max-width: 52ch;
}

/* Form card — wider, inline row */
.uf-nl-form-wrap {
  position: relative;
  flex-shrink: 0;
  width: 100%;
  max-width: 520px;
  border-radius: 16px;
  border: 1px solid #d3e2ff;
  background: rgba(255,255,255,0.92);
  padding: 0.625rem 0.75rem;
  box-shadow: 0 2px 10px rgba(0,55,167,0.07);
}
.uf-nl-form-accent {
  position: absolute;
  top: 0; left: 0; right: 0; height: 1px;
  background: linear-gradient(90deg, transparent, #a7c1ff, transparent);
  pointer-events: none;
}
/* Fallback plain form: pill with Subscribe button inside */
.uf-nl-form-row {
  position: relative;
  display: flex;
  align-items: center;
}
.uf-nl-input {
  width: 100%;
  border: 1px solid #d3e2ff;
  border-radius: 999px;
  background: #fff;
  padding: 0.5rem 6.5rem 0.5rem 1rem;
  font-size: 0.8125rem;
  font-family: 'Plus Jakarta Sans', system-ui, sans-serif;
  color: var(--text, #0e1525);
  outline: none;
  transition: border-color 0.2s;
  box-shadow: 0 1px 4px rgba(0,55,167,0.06) inset;
}
.uf-nl-input::placeholder { color: #9aacbf; }
.uf-nl-input:focus {
  border-color: var(--blue, #0037a7);
  box-shadow: 0 0 0 3px rgba(0,55,167,0.08);
}
.uf-nl-btn {
  position: absolute;
  right: 4px;
  top: 50%;
  transform: translateY(-50%);
  border-radius: 999px;
  background: var(--blue, #0037a7);
  color: #fff;
  border: none;
  padding: 0.3rem 0.875rem;
  font-size: 0.75rem;
  font-weight: 700;
  font-family: 'Plus Jakarta Sans', system-ui, sans-serif;
  cursor: pointer;
  white-space: nowrap;
  transition: background 0.15s;
  line-height: 1.4;
}
.uf-nl-btn:hover { background: var(--blue-dark, #002580); }

.uf-nl-tags {
  display: flex; flex-wrap: wrap; gap: 0.3rem; margin-top: 0.5rem;
}
.uf-nl-tags span {
  border-radius: 999px;
  border: 1px solid #dce8ff;
  background: #f5f8ff;
  padding: 0.1rem 0.5rem;
  font-size: 0.625rem;
  color: #6b7f9e;
  font-family: 'Plus Jakarta Sans', system-ui, sans-serif;
}

/* Gravity Forms: email pill with Subscribe inside it */
.uf-nl-form-wrap .gform_wrapper { max-width: none; }
.uf-nl-form-wrap .gform_wrapper .gform_fields { margin: 0 !important; }
.uf-nl-form-wrap .gform_wrapper .gfield { margin: 0 !important; padding: 0 !important; }
.uf-nl-form-wrap .gform_wrapper .gfield_label { display: none !important; }

/* The input + submit sit in a relative wrapper so submit overlays the input */
.uf-nl-form-wrap .gform_wrapper form,
.uf-nl-form-wrap .gform_wrapper .gform_body { position: relative; }
.uf-nl-form-wrap .gform_wrapper .gform_footer {
  position: absolute !important;
  top: 50% !important; right: 4px !important;
  transform: translateY(-50%) !important;
  margin: 0 !important; padding: 0 !important;
}
.uf-nl-form-wrap .gform_wrapper input[type="email"],
.uf-nl-form-wrap .gform_wrapper input[type="text"] {
  border-radius: 999px !important;
  border: 1px solid #d3e2ff !important;
  padding: 0.5rem 6.5rem 0.5rem 1rem !important;
  font-size: 0.8125rem !important;
  width: 100% !important;
  box-sizing: border-box !important;
  background: #fff !important;
  outline: none !important;
}
.uf-nl-form-wrap .gform_wrapper input[type="email"]:focus {
  border-color: var(--blue, #0037a7) !important;
  box-shadow: 0 0 0 3px rgba(0,55,167,0.08) !important;
}
.uf-nl-form-wrap .gform_wrapper .gform_footer input[type="submit"],
.uf-nl-form-wrap .gform_wrapper .gform_footer button {
  border-radius: 999px !important;
  background: var(--blue, #0037a7) !important;
  color: #fff !important; border: none !important;
  padding: 0.3rem 0.875rem !important;
  font-size: 0.75rem !important;
  font-weight: 700 !important;
  font-family: 'Plus Jakarta Sans', system-ui, sans-serif !important;
  cursor: pointer !important;
  white-space: nowrap !important;
  line-height: 1.4 !important;
}
.uf-nl-form-wrap .gform_wrapper .gform_footer input[type="submit"]:hover {
  background: var(--blue-dark, #002580) !important;
}

/* ── Divider ── */
.uf-divider {
  height: 1px;
  background: linear-gradient(90deg, transparent, #b8ceff 30%, #b8ceff 70%, transparent);
  opacity: 0.6;
}

/* ══ LOWER PANEL: Footer ══ */
.uf-ft {
  position: relative;
  background: #fff;
  padding: 1.125rem 1.5rem 0;
}
.uf-ft-accent { display: none; } /* clean look per screenshot */

/* 4-col grid — matches screenshot proportions */
.uf-ft-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1rem;
}
@media (min-width: 600px) {
  .uf-ft-grid { grid-template-columns: 1fr 1fr; }
}
@media (min-width: 1024px) {
  .uf-ft-grid {
    grid-template-columns: 1.4fr 0.65fr 0.65fr 1.5fr;
    gap: 1rem;
    align-items: start;
  }
}

/* Brand col */
.uf-ft-brand { display: flex; flex-direction: column; gap: 0.25rem; align-items: flex-start; }
.uf-ft-logo {
  display: block;
  width: auto;
  height: auto;
  max-width: 220px;
  object-fit: contain;
  flex-shrink: 0;
  margin-bottom: 0.25rem;
}
.uf-ft-sub {
  font-family: 'Outfit', system-ui, sans-serif;
  font-size: 0.875rem;
  font-weight: 600;
  color: #183153;
  margin: 0.125rem 0 0;
  line-height: 1.35;
  max-width: 32ch;
}
.uf-ft-date {
  font-family: 'Plus Jakarta Sans', system-ui, sans-serif;
  font-size: 0.8125rem;
  color: #4f6487;
  margin: 0.125rem 0 0.375rem;
}
.uf-ft-ctas {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem;
  margin-top: 0.25rem;
}
.uf-ft-cta {
  display: inline-flex;
  align-items: center;
  white-space: nowrap;
  border-radius: 999px;
  border: 1px solid #cfe0ff;
  background: #fff;
  padding: 0.3rem 0.625rem;
  font-size: 0.6875rem;
  font-weight: 600;
  color: #35506f;
  text-decoration: none;
  box-shadow: 0 1px 4px rgba(0,55,167,0.07);
  transition: border-color 0.15s, color 0.15s;
  font-family: 'Plus Jakarta Sans', system-ui, sans-serif;
}
.uf-ft-cta:hover { border-color: #b7cdfd; color: var(--blue, #0037a7); text-decoration: none; }

/* Menu cols */
.uf-ft-col { display: flex; flex-direction: column; }
.uf-ft-col-h {
  font-family: 'Plus Jakarta Sans', system-ui, sans-serif;
  font-size: 0.625rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.16em;
  color: #4169b2;
  margin-bottom: 0.5rem;
}
/* nav menu styling — covers wp_nav_menu output AND fallback <ul> */
.uf-ft-col ul,
.uf-ft-col .menu,
.uf-ft-col .uf-ft-menu {
  list-style: none; margin: 0; padding: 0;
  display: flex; flex-direction: column; gap: 0.25rem;
}
.uf-ft-col ul li a,
.uf-ft-col .menu li a,
.uf-ft-col .uf-ft-menu li a {
  font-family: 'Plus Jakarta Sans', system-ui, sans-serif;
  font-size: 0.8125rem;
  font-weight: 500;
  color: #35506f;
  text-decoration: none;
  transition: color 0.15s;
  display: inline-block;
}
.uf-ft-col ul li a:hover,
.uf-ft-col .menu li a:hover,
.uf-ft-col .uf-ft-menu li a:hover { color: var(--blue, #0037a7); }
/* Remove any bullets wp_nav_menu might add */
.uf-ft-col ul li, .uf-ft-col .menu li { list-style: none; margin: 0; padding: 0; }

/* Festival App card */
.uf-ft-app {
  position: relative;
  overflow: hidden;
  border-radius: 16px;
  border: 1px solid #cfe0ff;
  background: linear-gradient(135deg, #f2f7ff 0%, #fff 60%, #eef4ff 100%);
  padding: 0.875rem 1rem;
  box-shadow: 0 2px 10px rgba(0,55,167,0.07);
  display: flex;
  flex-direction: column;
  gap: 0.375rem;
}
.uf-ft-app-accent {
  position: absolute; top: 0; left: 0; right: 0; height: 1px;
  background: linear-gradient(90deg, transparent, #9fbaff, transparent);
  pointer-events: none;
}
.uf-ft-app-p {
  font-family: 'Plus Jakarta Sans', system-ui, sans-serif;
  font-size: 0.78rem;
  line-height: 1.55;
  color: #4f6487;
  margin: 0;
}
.uf-ft-app-btns {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-start;
  gap: 0.5rem;
  margin-top: 0.25rem;
}
.uf-ft-app-btn {
  display: inline-flex;
  align-items: center;
  white-space: nowrap;
  border-radius: 999px;
  border: 1px solid #cfe0ff;
  background: #fff;
  padding: 0.4rem 0.875rem;
  font-size: 0.78rem;
  font-weight: 600;
  color: #35506f;
  text-decoration: none;
  box-shadow: 0 1px 4px rgba(0,55,167,0.07);
  transition: border-color 0.15s, color 0.15s;
  font-family: 'Plus Jakarta Sans', system-ui, sans-serif;
}
.uf-ft-app-btn:hover { border-color: #b7cdfd; color: var(--blue, #0037a7); text-decoration: none; }

/* ── lbf-reg shimmer button — global subset ──────────────────
   Base + shimmer + card-primary variant used in the footer
   Contact Us button. Full register-page variants live in
   assets/css/register-page.css (register page only).
   These rules are intentionally duplicated there so the register
   page still works if this global block ever moves.
──────────────────────────────────────────────────────────── */
.lbf-reg-btn {
  position: relative; display: inline-flex; align-items: center; justify-content: center;
  overflow: hidden; border-radius: 999px; border: none;
  font-family: 'Plus Jakarta Sans', system-ui, sans-serif;
  font-weight: 700; text-decoration: none; cursor: pointer;
  transition: transform .3s, box-shadow .3s, filter .3s;
}
.lbf-reg-btn:hover { transform: translateY(-2px); }
.lbf-reg-btn:active { transform: scale(.98); }
.lbf-reg-btn-label { position: relative; z-index: 1; }
.lbf-reg-shimmer {
  position: absolute; inset: 0; z-index: 0;
  background: linear-gradient(120deg, transparent, rgba(255,255,255,.30), transparent);
  transform: translateX(-100%);
  transition: transform .7s ease;
  pointer-events: none;
}
.lbf-reg-btn:hover .lbf-reg-shimmer { transform: translateX(100%); }
.lbf-reg-btn--card-primary {
  flex: 1; background: linear-gradient(to right, #2452df, #5e63e8);
  color: #fff; padding: .625rem 1rem; font-size: .875rem;
  box-shadow: 0 12px 22px rgba(36,82,223,.22);
}
.lbf-reg-btn--card-primary:hover { box-shadow: 0 18px 30px rgba(36,82,223,.28); }

/* Legal row */
.uf-ft-legal {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  margin-top: 0.875rem;
  border-top: 1px solid #dbe7ff;
  padding: 0.625rem 0;
  margin-left: 0; margin-right: 0;
}
@media (min-width: 640px) {
  .uf-ft-legal {
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
  }
}
.uf-ft-legal-accent {
  position: absolute; top: -1px; left: 0;
  width: 6rem; height: 1px;
  background: linear-gradient(90deg, #7fa7ff, transparent);
  pointer-events: none;
}
.uf-ft-legal-accent--r {
  left: auto; right: 0;
  background: linear-gradient(270deg, #c1d5ff, transparent);
}
.uf-ft-copy {
  font-family: 'Plus Jakarta Sans', system-ui, sans-serif;
  font-size: 0.72rem;
  color: #6b7f9e;
  margin: 0;
}
.uf-ft-legal-links {
  display: flex; flex-wrap: wrap; align-items: center; gap: 0.375rem;
}
.uf-ft-legal-links span,
.uf-ft-legal-links a {
  font-family: 'Plus Jakarta Sans', system-ui, sans-serif;
  font-size: 0.72rem;
  color: #6b7f9e;
  text-decoration: none;
  transition: color 0.15s;
}
.uf-ft-legal-links a:hover { color: var(--blue, #0037a7); }
.uf-legal-sep { color: #b0bdd0; font-size: 0.65rem; user-select: none; }

/* Responsive */
@media (max-width: 859px) {
  .uf-nl-inner { flex-direction: column; }
  .uf-nl-form-wrap { max-width: none; width: 100%; }
}
@media (max-width: 767px) {
  .uf-nl-form-row { flex-direction: column; }
  .uf-ft-ctas { flex-wrap: wrap; }
  .uf-ft-legal { flex-direction: column; gap: 0.375rem; }
}
@media (max-width: 599px) {
  .uf-ft-grid { grid-template-columns: 1fr; }
}



/* ---- PAGE HERO ---- */
.page-hero {
  background: linear-gradient(135deg, #001a6e 0%, var(--blue) 100%);
  padding: 7rem 1.5rem 3rem; text-align: center;
}
.page-hero h1 {
  font-family: 'Barlow Condensed', sans-serif;
  font-size: clamp(2rem, 5vw, 3.5rem);
  font-weight: 900; text-transform: uppercase;
  color: #fff;
}
.breadcrumb { font-size: .85rem; color: rgba(255,255,255,.6); margin-top: .75rem; }
.breadcrumb a { color: rgba(255,255,255,.6); }

/* ---- RESPONSIVE ---- */
@media (max-width: 1023px) {
  .hero-inner { grid-template-columns: 1fr; }
  .hero-left  { order: 1; }   /* text + countdown first */
  .hero-right { order: 2; }   /* image below on mobile */
  .hero-right-img-wrap { max-width: 100% !important; margin-top: 0 !important; }
  .hero-right-placeholder { max-width: 100% !important; aspect-ratio: 16/9; margin-top: 0 !important; }
  .footer-top { grid-template-columns: 1fr; gap: 2rem; }
  .ft-cols { grid-template-columns: 1fr 1fr; }
  .donate-grid { grid-template-columns: 1fr; }
  .contact-grid { grid-template-columns: 1fr; }
}

@media (max-width: 767px) {
  .menu-toggle { display: flex; }

  /* Old mobile #primary-navigation dropdown — disabled, replaced by #mobile-nav-panel in lbf-nav-v2.css */
  #primary-navigation {
    display: none !important; /* always hidden on mobile — lbf-nav-v2.css handles mobile-nav-panel */
  }
  #primary-navigation.open {
    display: none !important; /* prevent old .open class from showing it */
  }

  /* Hamburger → X animation */
  .menu-toggle .bar { transition: transform .25s ease, opacity .2s ease; }
  .menu-toggle[aria-expanded="true"] .bar:nth-child(1) { transform: translateY(7px) rotate(45deg); }
  .menu-toggle[aria-expanded="true"] .bar:nth-child(2) { opacity: 0; transform: scaleX(0); }
  .menu-toggle[aria-expanded="true"] .bar:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

  /* Old nav-open backdrop — disabled, lbf-nav-v2.css has #nav-backdrop instead */
  body.nav-open::after-DISABLED {
    content: '';
    position: fixed; inset: 0;
    z-index: 998;
  }
  .stats-inner { grid-template-columns: 1fr 1fr; }
  .footer-top { grid-template-columns: 1fr; }
  .sched-row { grid-template-columns: 90px 1fr; }
  .sched-cat { display: none; }
  .info-cards { grid-template-columns: 1fr; }
  .hero-btns { flex-direction: column; }
  .hero-cd-inline { align-items: center; }
}

/* ---- HERO RIGHT COLUMN (slideshow + card stacked) ---- */
.hero-right-col {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  min-width: 0;
}

/* ---- HERO SLIDESHOW ---- */
.hero-slideshow {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  border-radius: 16px;
  overflow: hidden;
  background: rgba(0,0,0,.3);
  box-shadow: 0 8px 40px rgba(0,0,0,.4);
  flex-shrink: 0;
}

.hs-slide {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity .8s cubic-bezier(.4,0,.2,1), transform 1.2s cubic-bezier(.4,0,.2,1);
  transform: scale(1.04);
}
.hs-slide.active {
  opacity: 1;
  transform: scale(1);
  z-index: 2;
}
.hs-slide.leaving {
  opacity: 0;
  transform: scale(.97);
  z-index: 1;
}

.hs-slide img {
  width: 100%; height: 100%;
  object-fit: cover;
  display: block;
}

.hs-placeholder {
  width: 100%; height: 100%;
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  background: linear-gradient(135deg, rgba(0,20,80,.6), rgba(0,55,167,.4));
  border: 2px dashed rgba(255,255,255,.2);
  border-radius: 14px;
  gap: .6rem;
}
.hs-ph-icon { font-size: 2.5rem; opacity: .5; }
.hs-ph-txt { font-size: .8rem; color: rgba(255,255,255,.45); text-align: center; line-height: 1.5; }

.hs-overlay {
  position: absolute; inset: 0;
  background: linear-gradient(
    to top,
    rgba(0,0,0,.75) 0%,
    rgba(0,0,0,.2)  50%,
    rgba(0,0,0,.05) 100%
  );
  z-index: 3;
}

.hs-caption {
  position: absolute; bottom: 0; left: 0; right: 0;
  padding: 1rem 1.25rem 1.1rem;
  z-index: 4;
  transform: translateY(6px);
  transition: transform .5s .3s ease, opacity .5s .3s ease;
  opacity: 0;
}
.hs-slide.active .hs-caption {
  transform: translateY(0);
  opacity: 1;
}
.hs-cap-main {
  font-family: 'Barlow Condensed', sans-serif;
  font-size: 1.15rem; font-weight: 800;
  text-transform: uppercase; letter-spacing: .04em;
  color: #fff; line-height: 1.2;
  text-shadow: 0 1px 4px rgba(0,0,0,.6);
}
.hs-cap-sub {
  font-size: .8rem; color: rgba(255,255,255,.75);
  margin-top: .2rem;
  text-shadow: 0 1px 3px rgba(0,0,0,.5);
}

/* Arrows */
.hs-arrow {
  position: absolute; top: 50%; z-index: 5;
  transform: translateY(-50%);
  width: 34px; height: 34px;
  background: rgba(0,0,0,.45);
  border: 1px solid rgba(255,255,255,.2);
  border-radius: 50%;
  color: #fff; font-size: 1.3rem; line-height: 1;
  cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  transition: all .2s;
  padding: 0;
}
.hs-arrow:hover { background: rgba(0,55,167,.8); border-color: rgba(255,255,255,.5); }
.hs-prev { left: .75rem; }
.hs-next { right: .75rem; }

/* Dots */
.hs-dots {
  position: absolute; bottom: 2.8rem; left: 50%;
  transform: translateX(-50%);
  display: flex; gap: 6px; z-index: 5;
}
.hs-dot {
  width: 8px; height: 8px;
  border-radius: 50%;
  background: rgba(255,255,255,.4);
  border: none; cursor: pointer; padding: 0;
  transition: all .3s;
}
.hs-dot.active {
  background: var(--gold);
  width: 22px;
  border-radius: 4px;
}

/* Progress bar */
.hs-progress {
  position: absolute; bottom: 0; left: 0; right: 0;
  height: 3px; background: rgba(255,255,255,.12); z-index: 5;
}
.hs-progress-bar {
  height: 100%;
  background: linear-gradient(90deg, var(--gold), #fff);
  width: 0%;
  transition: width linear;
}

/* ---- HERO IMAGE GRID (up to 4 images in 2x2 grid) ---- */
.hero-img-grid {
  display: grid;
  gap: .5rem;
  border-radius: 14px;
  overflow: hidden;
  margin-bottom: 1.5rem;
  grid-template-columns: 1fr 1fr;
  grid-template-rows: auto;
}
/* 1 image: full width */
.hero-img-grid.hero-img-count-1 {
  grid-template-columns: 1fr;
}
/* 2 images: side by side */
.hero-img-grid.hero-img-count-2 {
  grid-template-columns: 1fr 1fr;
}
/* 3 images: first spans full top, two below */
.hero-img-grid.hero-img-count-3 {
  grid-template-columns: 1fr 1fr;
}
.hero-img-grid.hero-img-count-3 .hero-img-cell:first-child {
  grid-column: 1 / -1;
}
/* 4 images: standard 2x2 */
.hero-img-grid.hero-img-count-4 {
  grid-template-columns: 1fr 1fr;
}
.hero-img-cell {
  overflow: hidden;
  aspect-ratio: 4/3;
}
.hero-img-cell img {
  width: 100%; height: 100%;
  object-fit: cover;
  display: block;
  transition: transform .4s ease;
}
.hero-img-cell img:hover { transform: scale(1.04); }
@media (max-width: 767px) {
  .hero-img-grid { grid-template-columns: 1fr 1fr; }
  .hero-img-cell { aspect-ratio: 1/1; }
}

/* ---- HERO LOGO IMAGE (replaces title text when set) ---- */
.hero-logo-wrap {
  margin-bottom: 1.5rem;
}
.hero-logo-img {
  max-width: 340px;
  width: 100%;
  height: auto;
  display: block;
  filter: drop-shadow(0 4px 24px rgba(0,0,0,.35));
}
@media (max-width: 767px) {
  .hero-logo-img { max-width: 260px; }
}

/* ---- COUNTDOWN MEDIA BLOCK ---- */
.cd-media { margin-top:.75rem; }
.cd-photo-group,.cd-gallery { display:grid;gap:.35rem;border-radius:10px;overflow:hidden;grid-template-columns:1fr 1fr; }
.cd-photo-group.cd-photos-1,.cd-gallery.cd-photos-1 { grid-template-columns:1fr; }
.cd-photo-group img { width:100%;height:90px;object-fit:cover;display:block; }
.cd-photo-group.cd-photos-1 img { height:140px; }
.cd-gallery-thumb { position:relative;padding:0;border:none;cursor:pointer;background:none;overflow:hidden;display:block; }
.cd-gallery-thumb img { width:100%;height:90px;object-fit:cover;display:block;transition:transform .25s; }
.cd-gallery-thumb:hover img { transform:scale(1.05); }
.cd-gallery-more { position:absolute;inset:0;background:rgba(0,0,0,.55);display:flex;align-items:center;justify-content:center;color:#fff;font-family:"Barlow Condensed",sans-serif;font-size:1.5rem;font-weight:900; }

/* lightbox */
.cd-lightbox { position:fixed;inset:0;z-index:9999;background:rgba(0,0,0,.92);display:flex;align-items:center;justify-content:center; }
.cd-lb-img { max-width:90vw;max-height:85vh;object-fit:contain;border-radius:8px; }
.cd-lb-close,.cd-lb-prev,.cd-lb-next { position:absolute;background:rgba(255,255,255,.12);border:1px solid rgba(255,255,255,.2);border-radius:50%;color:#fff;cursor:pointer;transition:background .2s;display:flex;align-items:center;justify-content:center;padding:0;line-height:1;width:44px;height:44px;font-size:1.4rem; }
.cd-lb-close:hover,.cd-lb-prev:hover,.cd-lb-next:hover { background:rgba(255,255,255,.3); }
.cd-lb-close { top:1rem;right:1rem;font-size:1.5rem; }
.cd-lb-prev  { left:1rem;top:50%;transform:translateY(-50%); }
.cd-lb-next  { right:1rem;top:50%;transform:translateY(-50%); }
.cd-lb-counter { position:absolute;bottom:1.25rem;left:50%;transform:translateX(-50%);color:rgba(255,255,255,.6);font-size:.85rem; }
/* instagram */
.cd-insta { margin-top:.5rem; }
.cd-insta-head { display:flex;align-items:center;gap:.4rem;margin-bottom:.5rem; }
.cd-insta-handle { color:rgba(255,255,255,.85);font-size:.85rem;font-weight:600;text-decoration:none; }
.cd-insta-handle:hover { color:#fff;text-decoration:none; }
.cd-insta-note { font-size:.78rem;color:rgba(255,255,255,.45);line-height:1.5; }
.cd-insta-note a { color:rgba(255,255,255,.6); }
.cd-insta-link { display:block;text-align:center;padding:.75rem;background:rgba(255,255,255,.07);border:1px solid rgba(255,255,255,.15);border-radius:8px;color:rgba(255,255,255,.8);font-size:.9rem;font-weight:600;text-decoration:none;transition:background .2s; }
.cd-insta-link:hover { background:rgba(255,255,255,.13);text-decoration:none; }
/* video */
.cd-vid-wrap { border-radius:10px;overflow:hidden;margin-top:.35rem; }
.cd-video { width:100%;display:block;border-radius:10px; }
.cd-yt-ratio { position:relative;padding-bottom:56.25%; }
.cd-yt-ratio iframe { position:absolute;inset:0;width:100%;height:100%;border:none; }
/* captions */
.cd-captions { padding:.5rem .25rem; }
.cd-caption-line { font-size:.82rem; color:rgba(255,255,255,.8); line-height:1.5; text-align:center; margin:.15rem 0; }
.cd-single-img-wrap {
  width: 100%;
  border-radius: 10px;
  overflow: hidden;
  margin: .5rem 0;
}
.cd-single-img {
  width: 100%; height: auto;
  display: block;
  object-fit: cover;
  max-height: 220px;
  border-radius: 10px;
}

/* ================================================================
   FESTIVAL MEMORIES PAGE
   ================================================================ */

/* Hero banner */
.mem-hero {
  background: linear-gradient(135deg, #001a6e 0%, #0037a7 50%, #002d8a 100%);
  padding: 5rem 1.5rem 4rem;
  position: relative;
  overflow: hidden;
}
.mem-hero::before {
  content: '';
  position: absolute; inset: 0;
  background: radial-gradient(ellipse at 70% 50%, rgba(243,195,3,.08) 0%, transparent 60%);
  pointer-events: none;
}
.mem-hero-inner {
  max-width: 1100px; margin: 0 auto;
  position: relative; z-index: 1;
}
.mem-hero-h {
  font-family: 'Barlow Condensed', sans-serif;
  font-size: clamp(2.8rem, 7vw, 5rem);
  font-weight: 900; text-transform: uppercase;
  color: #fff; line-height: .95;
  margin: .5rem 0 1rem;
}
.mem-hero-h span { color: var(--gold); }
.mem-hero-p { color: rgba(255,255,255,.8); font-size: 1.1rem; max-width: 640px; margin-bottom: 2rem; }

.mem-stats-row {
  display: flex; gap: 2.5rem; flex-wrap: wrap;
  padding-top: 1.5rem;
  border-top: 1px solid rgba(255,255,255,.15);
}
.mem-stat-n {
  font-family: 'Barlow Condensed', sans-serif;
  font-size: 2.2rem; font-weight: 900; color: var(--gold); line-height: 1;
}
.mem-stat-l { font-size: .8rem; color: rgba(255,255,255,.6); text-transform: uppercase; letter-spacing: .06em; margin-top: .2rem; }

/* Sections */
.mem-section { padding: 4.5rem 0; }
.mem-section--alt { background: var(--bg2); }

/* Featured video */
.mem-featured-vid {
  max-width: 860px; margin: 0 auto;
  border-radius: 14px; overflow: hidden;
  box-shadow: 0 20px 60px rgba(0,0,0,.15);
}
.mem-vid-ratio {
  position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;
}
.mem-vid-ratio iframe {
  position: absolute; top: 0; left: 0;
  width: 100%; height: 100%; border: none;
}
.mem-vid-local { width: 100%; border-radius: 14px; display: block; }

/* Year gallery blocks */
.mem-year-block { margin-bottom: 3.5rem; }
.mem-year-head {
  display: flex; align-items: center; gap: 1rem;
  margin-bottom: 1.25rem;
}
.mem-year-badge {
  font-family: 'Barlow Condensed', sans-serif;
  font-size: 1.5rem; font-weight: 900; color: var(--blue);
  background: var(--bg2);
  border: 2px solid var(--blue);
  border-radius: 8px;
  padding: .2rem .9rem;
  white-space: nowrap;
  flex-shrink: 0;
}
.mem-section--alt .mem-year-badge { background: #fff; }
.mem-year-desc { color: var(--text-2); font-size: .95rem; flex: 1; }
.mem-year-div { flex: 1; height: 1px; background: var(--border); }

/* Photo grid */
.mem-photo-grid {
  display: grid;
  gap: .5rem;
  grid-template-columns: repeat(3, 1fr);
}
@media (min-width: 640px) {
  .mem-photo-grid { grid-template-columns: repeat(4, 1fr); }
}
@media (min-width: 900px) {
  .mem-grid-1 { grid-template-columns: 1fr; max-width: 600px; }
  .mem-grid-2 { grid-template-columns: repeat(2, 1fr); max-width: 700px; }
  .mem-photo-grid { grid-template-columns: repeat(5, 1fr); }
}
.mem-photo-thumb {
  position: relative;
  cursor: pointer; border: none; padding: 0; background: none;
  border-radius: 8px; overflow: hidden;
  aspect-ratio: 1;
  transition: transform .2s, box-shadow .2s;
}
.mem-photo-thumb:hover { transform: scale(1.03); box-shadow: 0 6px 20px rgba(0,0,0,.2); }
.mem-photo-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.mem-photo-hidden { display: none !important; }
.mem-photo-more {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  background: rgba(0,30,100,.65);
  color: #fff; font-size: 1.4rem; font-weight: 800;
  font-family: 'Barlow Condensed', sans-serif;
  border-radius: 8px;
}
.mem-show-all {
  margin-top: .75rem;
  background: none;
  border: 1px solid var(--blue);
  color: var(--blue);
  border-radius: 8px;
  padding: .45rem 1.1rem;
  font-size: .85rem; font-weight: 700; cursor: pointer;
  transition: all .2s;
}
.mem-show-all:hover { background: var(--blue); color: #fff; }

/* Extra video grid */
.mem-video-grid {
  display: grid; gap: 1.5rem;
  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
}
.mem-vid-card {
  border-radius: 12px; overflow: hidden;
  background: var(--bg2);
  border: 1px solid var(--border);
  box-shadow: 0 4px 16px rgba(0,0,0,.07);
}
.mem-vid-caption {
  padding: .75rem 1rem;
  display: flex; gap: .75rem; align-items: baseline;
}
.mem-vid-year {
  font-family: 'Barlow Condensed', sans-serif;
  font-size: .85rem; font-weight: 800;
  color: var(--blue); text-transform: uppercase; letter-spacing: .05em;
  flex-shrink: 0;
}
.mem-vid-title { font-size: .9rem; color: var(--text-2); }

/* Empty state */
.mem-empty {
  text-align: center; padding: 5rem 1rem;
  max-width: 480px; margin: 0 auto;
}
.mem-empty-icon { font-size: 4rem; margin-bottom: 1rem; }
.mem-empty h2 { font-family: 'Barlow Condensed', sans-serif; font-size: 2rem; font-weight: 900; color: var(--blue); margin-bottom: .75rem; }
.mem-empty p { color: var(--text-2); font-size: 1rem; }

/* CTA strip */
.mem-cta-strip {
  background: var(--blue);
  padding: 2.5rem 1.5rem;
}
.mem-cta-inner {
  max-width: 1100px; margin: 0 auto;
  display: flex; align-items: center; justify-content: space-between;
  gap: 1.5rem; flex-wrap: wrap;
}
.mem-cta-strip h3 {
  font-family: 'Barlow Condensed', sans-serif;
  font-size: 1.4rem; font-weight: 800; color: #fff;
  text-transform: uppercase; margin-bottom: .25rem;
}
.mem-cta-strip p { color: rgba(255,255,255,.75); font-size: .95rem; }
.mem-cta-btns { display: flex; gap: .75rem; flex-wrap: wrap; }

/* Responsive */
@media (max-width: 600px) {
  .mem-stats-row { gap: 1.5rem; }
  .mem-photo-grid { grid-template-columns: repeat(3, 1fr); }
  .mem-hero { padding: 3.5rem 1rem 3rem; }
  .mem-cta-inner { flex-direction: column; align-items: flex-start; }
}

/* ═══════════════════════════════════════════════════════════════
   MOBILE SECTION COLLAPSE  (front-page only)
   Desktop: toggles hidden, everything always open
   Mobile ≤767px: toggle bars visible, sections collapse/expand
   ═══════════════════════════════════════════════════════════════ */

/* Collapse wrapper — desktop: transparent passthrough */
.lbf-col-wrap { position: relative; }

/* Toggle button — hidden on desktop */
.lbf-col-toggle {
  display: none;
}

/* Body — always visible on desktop */
.lbf-col-body { display: block; }

/* Expand/Collapse All bar — hidden on desktop */
.lbf-col-controls { display: none; }

/* ── Mobile ──────────────────────────────────────────────── */
@media (max-width: 767px) {

  /* Controls bar */
  .lbf-col-controls {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: .5rem;
    padding: .6rem 1rem;
    background: var(--blue, #0037a7);
    position: sticky;
    top: var(--header-h);
    z-index: 90;
    box-shadow: 0 2px 8px rgba(0,0,0,.18);
  }
  .lbf-col-all-btn {
    background: none;
    border: none;
    color: rgba(255,255,255,.9);
    font-size: .78rem;
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
    cursor: pointer;
    padding: .25rem .5rem;
    border-radius: 4px;
    transition: color .15s, background .15s;
  }
  .lbf-col-all-btn:hover { color: #fff; background: rgba(255,255,255,.15); }
  .lbf-col-divider { color: rgba(255,255,255,.35); font-size: .8rem; user-select: none; }

  /* The section wrapper */
  .lbf-col-wrap {
    border-bottom: 1px solid var(--border, #e5e7eb);
  }
  .lbf-col-wrap:last-of-type { border-bottom: none; }

  /* Toggle button */
  .lbf-col-toggle {
    display: flex;
    width: 100%;
    align-items: center;
    gap: .65rem;
    padding: .9rem 1.1rem;
    background: #fff;
    border: none;
    border-bottom: 1px solid transparent;
    cursor: pointer;
    text-align: left;
    -webkit-tap-highlight-color: transparent;
    transition: background .15s;
  }
  .lbf-col-toggle:hover,
  .lbf-col-toggle:focus-visible { background: #f4f7ff; outline: none; }

  /* When the section is open the button gets a bottom border */
  .lbf-col-wrap.open .lbf-col-toggle {
    border-bottom-color: var(--border, #e5e7eb);
    background: #f4f7ff;
  }

  .lbf-col-icon {
    font-size: 1.25rem;
    line-height: 1;
    flex-shrink: 0;
  }
  .lbf-col-label {
    flex: 1;
    font-family: 'Barlow Condensed', sans-serif;
    font-size: 1.05rem;
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: .05em;
    color: var(--text-1, #111);
  }
  .lbf-col-chevron {
    font-size: .7rem;
    color: var(--text-2, #666);
    transition: transform .28s ease;
    flex-shrink: 0;
  }
  .lbf-col-wrap.open .lbf-col-chevron {
    transform: rotate(180deg);
  }

  /* Body — hidden by default on mobile, shown when .open */
  .lbf-col-body {
    display: none;
    overflow: hidden;
  }
  .lbf-col-wrap.open .lbf-col-body {
    display: block;
    animation: lbfColSlide .25s ease-out;
  }

  @keyframes lbfColSlide {
    from { opacity: 0; transform: translateY(-6px); }
    to   { opacity: 1; transform: translateY(0); }
  }


}

/* ══════════════════════════════════════════════════════
   BLUEPRINT — ADDED DESIGN SYSTEM STYLES
   ══════════════════════════════════════════════════════ */

/* ── §7 Stats Row pattern ── */
.stats-row {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1rem;
}
.stats-row--dark .stats-row__number,
.stats-row--dark .stats-row__label { color: #fff; }
.stats-row__item {
  display: flex; flex-direction: column; align-items: center;
  gap: .25rem; padding: 1.25rem 1rem; text-align: center;
}
.stats-row__icon { font-size: 1.5rem; line-height: 1; }
.stats-row__number {
  font-family: 'Barlow Condensed', sans-serif;
  font-size: clamp(1.8rem, 3vw, 2.4rem);
  font-weight: 900; color: var(--blue); line-height: 1;
}
.stats-row--dark .stats-row__number { color: var(--gold); }
.stats-row__label { font-size: .82rem; color: var(--text-3); text-transform: uppercase; letter-spacing: .05em; }
@media (max-width: 767px) {
  .stats-row { grid-template-columns: repeat(2, 1fr); }
}

/* ── §9.1 Card system  ── */
.card-grid-3 {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1.5rem;
}
.card-grid-4 {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1.5rem;
}
@media (max-width: 900px) {
  .card-grid-3 { grid-template-columns: repeat(2, 1fr); }
  .card-grid-4 { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 540px) {
  .card-grid-3, .card-grid-4 { grid-template-columns: 1fr; }
}

/* ── §7 Editorial Split layout ── */
.editorial-split {
  display: grid;
  grid-template-columns: 55% 1fr;
  gap: 3rem;
  align-items: flex-start;
}
.editorial-split--reverse { grid-template-columns: 1fr 55%; }
.editorial-split--reverse .editorial-split__media { order: 2; }
.editorial-split--reverse .editorial-split__text  { order: 1; }
.editorial-split__media img {
  width: 100%; border-radius: var(--radius);
  object-fit: cover;
}
@media (max-width: 900px) {
  .editorial-split,
  .editorial-split--reverse { grid-template-columns: 1fr; }
  .editorial-split--reverse .editorial-split__media { order: 1; }
  .editorial-split--reverse .editorial-split__text  { order: 2; }
}

/* ── §4.1 Section header left-align variant ── */
.sec-hd--left { text-align: left; }
.sec-hd--left .sec-p { margin-left: 0; }

/* ── §9.3 Forms: narrow, labels above, gold submit ── */
.form-page-wrap { max-width: 720px; margin: 0 auto; }
.form-card-wrap {
  background: #fff;
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 2rem 2.5rem;
}
.form-field-group { margin-bottom: 1.5rem; }
.form-field-group label {
  display: block;
  font-size: .9rem; font-weight: 600;
  color: var(--text-2); margin-bottom: .4rem;
}
.form-field-group input,
.form-field-group select,
.form-field-group textarea {
  width: 100%;
  padding: .65rem .9rem;
  border: 1px solid var(--border);
  border-radius: 8px;
  font-size: 1rem;
  color: var(--text);
  background: #fff;
  transition: border-color .2s;
}
.form-field-group input:focus,
.form-field-group select:focus,
.form-field-group textarea:focus {
  outline: none;
  border-color: var(--blue);
  box-shadow: 0 0 0 3px rgba(0,55,167,.08);
}
/* Blueprint §9.3: error state — left border + helper text */
.form-field-group.has-error input,
.form-field-group.has-error select,
.form-field-group.has-error textarea {
  border-left: 3px solid #dc2626;
}
.form-field-group .field-error {
  display: block; font-size: .8rem;
  color: #dc2626; margin-top: .3rem;
}
.form-privacy-note {
  font-size: .82rem; color: var(--text-3);
  text-align: center; margin-bottom: 1rem;
}

/* ── §9.3 Schedule row enhancements ── */
/* Alternating rows already handled by :nth-child selector above */
/* Category color dot */
.sched-row { position: relative; }
.sched-cat-dot {
  display: inline-block;
  width: 6px; height: 6px;
  border-radius: 50%;
  margin-right: .4rem;
  vertical-align: middle;
  flex-shrink: 0;
}

/* ── §G Sponsor tier grid ── */
.sponsor-tier { margin-bottom: 2.5rem; }
.sponsor-tier__grid {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
  margin-top: 1rem;
}
.sponsor-logo-wrap__name {
  font-size: .8rem; font-weight: 700;
  color: var(--text-2); text-align: center;
}
/* Tier-size variants for .sp classes */
.sp-xl .sponsor-logo-wrap { width: 240px; height: 135px; }
.sp-lg .sponsor-logo-wrap { width: 200px; height: 112px; }
.sp-md .sponsor-logo-wrap { width: 160px; height: 90px; }
.sp-sm .sponsor-logo-wrap { width: 120px; height: 68px; }
.sp-xs .sponsor-logo-wrap { width: 90px;  height: 50px; padding: .5rem; }

/* ── §C Entertainment — night hero override ── */
.sp-pg-hero--night {
  background: var(--grad-night) !important;
}

/* ── §E Pageant hero override already defined; ensure purple CTA band ── */
.sp-cta-band--pageant {
  background: var(--grad-pageant);
}

/* ── §5.1 Section connector divider ── */
.sec-connector { border-top: 1px solid var(--border); }

/* ── §3 Background level helpers ── */
.bg-level-0 { background: #fff; }
.bg-level-1 { background: var(--bg); }
.bg-level-2 { background: var(--bg2); }



/* ── §6.1 / §11.7 Slim hero base colours ── */
.sp-pg-hero--slim {
  background: var(--grad-blue);
}

/* ---- GRAVITY FORMS INSIDE DARK DONATION SECTION ---- */
.donate-card--gf { padding: .9rem; max-width:60%;margin:0 auto; }
.donate-card--gf .gform_wrapper,
.donate-card--gf .gform_wrapper * { box-sizing: border-box; }

/* Labels */
.donate-card--gf .gfield_label,
.donate-card--gf .gform_wrapper label { color: rgba(255,255,255,.9) !important; font-size: .9rem !important; }

/* Inputs, selects, textareas */
.donate-card--gf input[type="text"],
.donate-card--gf input[type="email"],
.donate-card--gf input[type="number"],
.donate-card--gf input[type="tel"],
.donate-card--gf select,
.donate-card--gf textarea {
  background: rgba(255,255,255,.1) !important;
  border: 1px solid rgba(255,255,255,.25) !important;
  border-radius: 8px !important;
  color: #fff !important;
  padding: .6rem .85rem !important;
  width: 100% !important;
}
.donate-card--gf input::placeholder,
.donate-card--gf textarea::placeholder { color: rgba(255,255,255,.4) !important; }

/* Radio and checkbox labels */
.donate-card--gf .gfield_radio label,
.donate-card--gf .gfield_checkbox label { color: rgba(255,255,255,.85) !important; }

/* Submit button */
.donate-card--gf .gform_footer input[type="submit"],
.donate-card--gf input[type="submit"] {
  background: var(--gold) !important;
  color: var(--text) !important;
  border: none !important;
  border-radius: 8px !important;
  padding: .75rem 2rem !important;
  font-family: 'Barlow Condensed', sans-serif !important;
  font-size: 1.05rem !important;
  font-weight: 800 !important;
  text-transform: uppercase !important;
  cursor: pointer !important;
  width: 100% !important;
  letter-spacing: .04em !important;
  transition: opacity .2s !important;
}
.donate-card--gf input[type="submit"]:hover { opacity: .88 !important; }

/* Validation messages */
.donate-card--gf .gfield_description,
.donate-card--gf .gform_description { color: rgba(255,255,255,.65) !important; font-size: .82rem !important; }
.donate-card--gf .validation_message { color: #fca5a5 !important; font-size: .8rem !important; }

/* Price / total fields */
.donate-card--gf .ginput_product_price,
.donate-card--gf .gfield_price { color: var(--gold) !important; font-weight: 700 !important; }

/* Select arrow visibility */
.donate-card--gf select option { background: #0037a7; color: #fff; }

.fp-attr-cat-title {
  font-family: 'Barlow Condensed', sans-serif;
  font-size: 1.5rem; font-weight: 800; text-transform: uppercase;
  color: var(--blue); margin: 2rem 0 1rem;
  padding-bottom: .5rem; border-bottom: 2px solid var(--blue-tint, #e8eeff);
}
.fp-attr-cat-title:first-child { margin-top: 0; }

/* ============================================================
   MERCHANDISE SECTION — Front Page
   ============================================================ */

.lbf-merch-section {
  background: linear-gradient(180deg, #f4f6fb 0%, #fff 100%);
  padding: 4.5rem 0;
}

.lbf-merch-hd {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 2.5rem;
  flex-wrap: wrap;
}

.lbf-merch-sub {
  color: var(--text-2, #555);
  font-size: 1rem;
  margin: 0;
}

.lbf-merch-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1.25rem;
  margin-bottom: 2.5rem;
}

.lbf-merch-card {
  background: #fff;
  border-radius: 14px;
  overflow: hidden;
  box-shadow: 0 2px 12px rgba(0,0,0,.07);
  text-decoration: none;
  color: inherit;
  display: flex;
  flex-direction: column;
  transition: transform .18s, box-shadow .18s;
  border: 1.5px solid #f3f4f6;
}
.lbf-merch-card:hover {
  transform: translateY(-4px);
  box-shadow: 0 8px 28px rgba(0,55,167,.13);
  text-decoration: none;
  color: inherit;
}

.lbf-merch-card__img {
  aspect-ratio: 1;
  overflow: hidden;
  background: linear-gradient(135deg, #eef2ff, #dbeafe);
  display: flex;
  align-items: center;
  justify-content: center;
}
.lbf-merch-card__img img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform .3s;
}
.lbf-merch-card:hover .lbf-merch-card__img img { transform: scale(1.04); }

.lbf-merch-card__placeholder {
  font-size: 3.5rem;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  aspect-ratio: 1;
}

.lbf-merch-card__body {
  padding: .9rem 1rem .5rem;
  flex: 1;
}

.lbf-merch-card__cat {
  display: inline-block;
  font-size: .7rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--blue, #0037a7);
  margin-bottom: .35rem;
}

.lbf-merch-card__name {
  font-size: .95rem;
  font-weight: 700;
  color: var(--text-1, #111);
  margin: 0 0 .4rem;
  line-height: 1.3;
}

.lbf-merch-card__price {
  font-size: .9rem;
  font-weight: 700;
  color: var(--blue, #0037a7);
}
.lbf-merch-card__price .woocommerce-Price-amount { font-weight: 700; }

.lbf-merch-card__cta {
  padding: .65rem 1rem;
  background: var(--blue, #0037a7);
  color: #fff;
  font-size: .78rem;
  font-weight: 700;
  text-align: center;
  letter-spacing: .03em;
  transition: background .15s;
}
.lbf-merch-card:hover .lbf-merch-card__cta { background: var(--gold, #f3c303); color: #1a0f00; }

.lbf-merch-footer {
  text-align: center;
  padding-top: .5rem;
}

@media (max-width: 900px) {
  .lbf-merch-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 540px) {
  .lbf-merch-grid { grid-template-columns: repeat(2, 1fr); gap: .75rem; }
  .lbf-merch-hd { flex-direction: column; align-items: flex-start; }
}


/* ─── Version 13 Hero + Stats ─────────────────────────────────── */

/* ═══ V13: TYPOGRAPHIC ═══════════════════════════════════════════════ */
.hero-v13 {
  min-height:100vh; background:linear-gradient(135deg,#001240 0%,#001f6e 50%,#0030a0 100%);
  position:relative; overflow:hidden; display:flex; align-items:flex-start;
  padding:0 0 4rem;
  margin:0; width:100%;
}
.v13-overlay { position:absolute;inset:0;background:linear-gradient(to right,rgba(0,0,0,.3) 0%,transparent 60%);z-index:1;pointer-events:none; }
.v13-side-accent { display:none; }
.v13-inner { max-width:1200px;margin:0 auto;width:100%;display:grid;grid-template-columns:1fr auto;gap:4rem;align-items:flex-start;position:relative;z-index:2;padding:0 2.5rem; }
.v13-left { display:flex;flex-direction:column;gap:.4rem;padding-left:0; }
.v13-label { display:inline-block;padding:.28rem .8rem;font-size:.72rem;font-weight:800;letter-spacing:.12em;text-transform:uppercase;border:1px solid transparent;border-radius:20px !important;overflow:hidden;margin-top:0;margin-bottom:.8rem;align-self:flex-start; }
.v13-title { font-family:'Barlow Condensed',sans-serif;font-size:clamp(3.5rem,9vw,7rem);font-weight:900;text-transform:uppercase;line-height:.88;letter-spacing:-.025em;color:#fff;margin:0 0 .8rem;display:flex;flex-direction:column; }
.v13-title span { display:block; }
.v13-rule { width:100px;height:3px;background:var(--gold);margin-bottom:1.2rem; }
.v13-sub { color:rgba(255,255,255,.72);font-size:1rem;line-height:1.6;max-width:460px;margin-bottom:1.2rem; }
.v13-meta { display:flex;flex-direction:column;gap:.4rem;margin-bottom:1.5rem; }
.v13-meta-item { display:inline-flex;align-items:center;gap:.5rem;color:rgba(255,255,255,.75);font-size:.88rem;font-weight:600; }
.v13-meta-icon { font-size:.9rem; }
.v13-cd { display:inline-flex;flex-direction:column;gap:.5rem;padding:1rem 1.3rem;border:1px solid transparent;border-radius:8px;margin-bottom:1.6rem;align-self:flex-start; }
.v13-cd-lbl { font-size:.72rem;font-weight:800;letter-spacing:.12em;text-transform:uppercase; }
.v13-cd-boxes { display:flex;align-items:center;gap:.35rem; }
.v13-cd-box { display:flex;flex-direction:column;align-items:center;padding:.5rem .65rem;min-width:52px;border-radius:4px; }
.v13-cd-n { font-family:'Barlow Condensed',sans-serif;font-size:1.6rem;font-weight:900;line-height:1; }
.v13-cd-u { font-size:.56rem;text-transform:uppercase;letter-spacing:.08em;margin-top:.15rem; }
.v13-cd-sep { font-size:1.3rem;font-weight:900;padding-bottom:.7rem; }
.v13-btns { display:flex;gap:.75rem;flex-wrap:wrap; }
.v13-right { display:flex;align-items:flex-start;padding-top:160px; }
.v13-stats-side { display:flex;flex-direction:column;gap:0;background:rgba(255,255,255,.05);border:1px solid rgba(255,255,255,.1);border-radius:16px;overflow:hidden;min-width:200px; }
.v13-side-stat { padding:1.5rem 1.8rem;text-align:center; }
.v13-ss-n { font-family:'Barlow Condensed',sans-serif;font-size:2.4rem;font-weight:900;color:var(--gold);line-height:1; }
.v13-ss-l { font-size:.75rem;color:rgba(255,255,255,.55);text-transform:uppercase;letter-spacing:.08em;margin-top:.25rem; }
.v13-ss-rule { height:1px;background:rgba(255,255,255,.08); }
@media(max-width:1000px){.v13-inner{grid-template-columns:1fr;}.v13-right{display:none;}}

/* ── Donate GF section title "Your Information" → white ─────────── */
.donate-card--gf .gsection_title,
.donate-card--gf .gfield--type-section .gfield_label,
.donate-card--gf .gsection .gsection_title,
.donate-card--gf h2.gsection_title,
.donate-card--gf h3.gsection_title { color: #fff !important; }

/* ── Donate GF — extra spacing reduction between field groups ──── */
.donate-card--gf .gform_body .gsection { margin-top: .25rem !important; margin-bottom: .25rem !important; padding-bottom: .15rem !important; }
.donate-card--gf .gform_fields { row-gap: 0 !important; }
.donate-card--gf li.gfield { margin-top: 0 !important; padding-top: 0 !important; }

/* ══════════════════════════════════════════════════════════
   WP BLOCK EDITOR LAYOUT OVERRIDE
   WP 6.x injects .is-layout-constrained CSS that constrains
   all content to ~650px. Reset it for our full-width templates.
═══════════════════════════════════════════════════════════ */
.is-layout-constrained > * {
  max-width: none !important;
  margin-left: unset !important;
  margin-right: unset !important;
}
.wp-site-blocks {
  padding-top: 0 !important;
  padding-bottom: 0 !important;
}
body > .wp-site-blocks,
.wp-block-template-part {
  max-width: none !important;
  padding: 0 !important;
}
.wp-block-group.is-layout-constrained,
.wp-block-group.is-layout-flow {
  max-width: none !important;
  padding-left: 0 !important;
  padding-right: 0 !important;
}

/* ── Force full width — override WP default content constraints ── */
body,
.wp-site-blocks,
.wp-block-group,
.entry-content,
.post-content,
.page-content,
.site-content,
#content,
#page,
#primary,
#main,
.site-main {
  max-width: none !important;
  width: 100% !important;
  margin-left: 0 !important;
  margin-right: 0 !important;
  padding-left: 0 !important;
  padding-right: 0 !important;
  box-sizing: border-box !important;
}

/* ── Blueprint §9.3 — All form pages: Gravity Forms submit = gold full-width ── */
.form-page-content .gform_wrapper .gform_footer input[type="submit"],
.form-page-content .gform_wrapper .gform_footer button[type="submit"],
.container-narrow .gform_wrapper .gform_footer input[type="submit"],
.container-narrow .gform_wrapper .gform_footer button[type="submit"] {
  background: var(--gold) !important;
  color: var(--text) !important;
  border: none !important;
  border-radius: 8px !important;
  padding: .85rem 2rem !important;
  font-family: 'Barlow Condensed', sans-serif !important;
  font-size: 1.05rem !important;
  font-weight: 800 !important;
  text-transform: uppercase !important;
  cursor: pointer !important;
  width: 100% !important;
  letter-spacing: .04em !important;
  transition: opacity .2s !important;
}
.container-narrow .gform_wrapper .gform_footer input[type="submit"]:hover,
.container-narrow .gform_wrapper .gform_footer button[type="submit"]:hover { opacity: .88 !important; }

/* Blueprint §9.3 — Form label above input (Gravity Forms) */
.container-narrow .gform_wrapper .gfield_label { display: block; margin-bottom: .3rem; font-weight: 600; }
.container-narrow .gform_wrapper .ginput_container { margin-top: 0 !important; }
.container-narrow .gform_wrapper li.gfield { margin-bottom: 1.5rem !important; }

/* Blueprint §9.3 — Privacy note above submit */
.container-narrow .gform_wrapper .gform_footer::before {
  content: 'Your information is never sold or shared.';
  display: block;
  font-size: .8rem;
  color: var(--text-3);
  text-align: center;
  margin-bottom: .75rem;
}


/* ═══════════════════════════════════════════════════════════════════════
   LBF v18.1 — Blueberry Hero Particle System
   Canvas sits at z-index:0, behind v13-overlay (z:1) and v13-inner (z:2).
   pointer-events:none ensures all hero clicks / taps pass through cleanly.
═══════════════════════════════════════════════════════════════════════ */

/* Canvas element — fills the hero section absolutely */
#lbf-hero-canvas {
  position:       absolute;
  inset:          0;
  width:          100%;
  height:         100%;
  z-index:        0;
  pointer-events: none;
  display:        block;

  /* Subtle blending so canvas tones merge with the gradient underneath */
  mix-blend-mode: screen;
  opacity:        0.9;
}

/* Respect prefers-reduced-motion — hide entirely, gradient remains */
@media (prefers-reduced-motion: reduce) {
  #lbf-hero-canvas {
    display: none;
  }
}

/* Ensure existing hero overlay and inner content sit above the canvas */
.hero-v13 .v13-overlay    { z-index: 1; }
.hero-v13 .v13-inner      { z-index: 2; }
/* hero-bg-media removed v19.4 */


/* ═══════════════════════════════════════════════════════════════════════
   LBF v18.2 — Homepage Scroll Reveal System
   ─────────────────────────────────────────────────────────────────────
   Elements with [data-lbf-reveal] start hidden.
   JS adds .lbf-rv-ready on init (triggers initial state below).
   JS adds .lbf-rv-visible when element enters the viewport.

   Direction variants via data-lbf-from:
     "up"    — default, rises from below
     "left"  — slides in from left
     "right" — slides in from right
     "fade"  — pure opacity, no translate

   Stagger is handled by JS using data-lbf-delay="N" (ms).
   prefers-reduced-motion: no transform, instant opacity.
═══════════════════════════════════════════════════════════════════════ */

/* ── Base hidden state (only applied after JS inits) ── */
.lbf-rv-ready                            { opacity: 0; }
.lbf-rv-ready[data-lbf-from="up"]        { transform: translateY(28px); }
.lbf-rv-ready[data-lbf-from="left"]      { transform: translateX(-24px); }
.lbf-rv-ready[data-lbf-from="right"]     { transform: translateX(24px); }
.lbf-rv-ready[data-lbf-from="fade"]      { transform: none; }

/* ── Transition timing — premium cubic-bezier easing ── */
.lbf-rv-ready {
  transition: opacity 0.68s cubic-bezier(0.22, 0.61, 0.36, 1),
              transform 0.68s cubic-bezier(0.22, 0.61, 0.36, 1);
  will-change: opacity, transform;
}

/* Cards get a subtle scale-up micro-effect on reveal */
.attr-card.lbf-rv-ready,
.form-card.lbf-rv-ready,
.sp.lbf-rv-ready {
  transform: translateY(22px) scale(0.97);
}
.attr-card.lbf-rv-ready.lbf-rv-visible,
.form-card.lbf-rv-ready.lbf-rv-visible,
.sp.lbf-rv-ready.lbf-rv-visible {
  transform: translateY(0) scale(1);
}

/* ── Visible state ── */
.lbf-rv-ready.lbf-rv-visible {
  opacity:   1;
  transform: none;
}

/* ── Reduced motion: skip animation entirely, show everything ── */
@media (prefers-reduced-motion: reduce) {
  .lbf-rv-ready,
  .lbf-rv-ready[data-lbf-from="up"],
  .lbf-rv-ready[data-lbf-from="left"],
  .lbf-rv-ready[data-lbf-from="right"],
  .lbf-rv-ready[data-lbf-from="fade"] {
    opacity:    1 !important;
    transform:  none !important;
    transition: none !important;
  }
}

/* ── Section heading group ── */
.sec-hd[data-lbf-reveal] { /* handled by the main rule */ }

/* ─────────────────────────────────────────────────────────────────────
   Section-level entrance: the whole section block gets a subtle
   baseline fade, independent of per-card staggering inside it.
   Applied to .lbf-col-body when it opens (after accordion expand).
   Not applied to the hero — it has its own entrance.
───────────────────────────────────────────────────────────────────── */


/* ═══════════════════════════════════════════════════════════════════════
   LBF v18.3 — Inline Editor Enhancements
   Pageant cat-card empty-state editing hints + chip emoji isolation
═══════════════════════════════════════════════════════════════════════ */

/* Emoji span is purely decorative — never editable */
.v13-label-emoji {
  user-select:     none;
  pointer-events:  none;
  margin-right:    0.3em;
}

/* Empty cat-card slot visible only in edit mode */
.lbf-cat-card--empty {
  opacity:     0.45;
  border:      2px dashed rgba(243,195,3,0.4) !important;
}
.lbf-cat-card--empty .cat-name,
.lbf-cat-card--empty .cat-age {
  color: rgba(255,255,255,0.4);
  font-style: italic;
}

/* Pageant inline edit hint — shown only to editors */
.lbf-pag-edit-hint {
  font-size:   0.78rem;
  color:       rgba(255,255,255,0.45);
  margin-top:  1rem;
  font-style:  italic;
  text-align:  center;
}
.lbf-pag-edit-hint a {
  color: var(--gold);
  text-decoration: underline;
  text-underline-offset: 2px;
}

/* Cat-card fields get the standard editable outline from inline-editor.php
   but we tighten the border-radius to match the card design */
.cat-card [data-lbf-field]:hover,
.cat-card [data-lbf-field]:focus {
  border-radius: 4px;
}


/* ═══════════════════════════════════════════════════════════════════════
   LBF v18.3 patch — Fix edit-mode tooltip overflow on pageant cat-cards
   ─────────────────────────────────────────────────────────────────────
   The inline editor's [data-lbf-field]::before / ::after tooltip bubbles
   are position:absolute and were escaping the cat-card bounds, causing
   a yellow box to cover the pageant section during hover/edit.
   Fix: suppress those pseudo-elements inside .cat-card and replace with
   a clean contained indicator. Also add overflow:hidden + isolation to
   the card to guarantee no future pseudo-element bleed.
═══════════════════════════════════════════════════════════════════════ */

/* Contain all absolutely-positioned children inside cat-cards */
.cat-card {
  overflow:  visible;   /* keep glow outline visible outside the card */
  isolation: isolate;   /* new stacking context stops z-index bleed */
  position:  relative;  /* ensure any internal absolute children anchor here */
}

/* ── Suppress the flying tooltip bubbles inside cat-cards entirely ── */
.cat-card [data-lbf-field]::before,
.cat-card [data-lbf-field]::after {
  display: none !important;
}

/* ── Replace with a subtle contained inline hint ── */
/* Show a tiny pencil badge on the card itself (not the field) on hover */
.cat-card:has([data-lbf-field]):hover::after {
  content:          '✏️';
  position:         absolute;
  top:              6px;
  right:            6px;
  font-size:        11px;
  line-height:      1;
  background:       rgba(243,195,3,0.18);
  border:           1px solid rgba(243,195,3,0.4);
  border-radius:    6px;
  padding:          2px 5px;
  pointer-events:   none;
  z-index:          2;
}

/* ── Keep the outline/glow feedback but contain it visually ── */
.cat-card [data-lbf-field] {
  border-radius: 4px;
}
.cat-card [data-lbf-field]:hover {
  outline:        2px solid rgba(243,195,3,0.7);
  outline-offset: 2px;   /* tighter — stays within card */
  background:     rgba(243,195,3,0.1);
  box-shadow:     none;  /* remove the 4px spread that was escaping */
}
.cat-card [data-lbf-field]:focus {
  outline:        2px solid #f3c303;
  outline-offset: 2px;
  background:     rgba(243,195,3,0.12);
  box-shadow:     none;
}

/* Fallback for browsers without :has() support — hide ::after on card too */
@supports not (selector(:has(a))) {
  .cat-card::after { display: none !important; }
}

/* v18.3.3 — Improved background-edit hover indicator for all sections */
[data-lbf-bg]:hover::before {
  content: '🎨 Right-click to change background' !important;
  display: block !important;
  position: absolute !important;
  top: 8px !important;
  right: 12px !important;
  left: auto !important;
  transform: none !important;
  background: rgba(22,0,64,0.9) !important;
  color: #f3c303 !important;
  font-size: 11px !important;
  font-weight: 700 !important;
  padding: 4px 12px !important;
  border-radius: 20px !important;
  border: 1px solid rgba(243,195,3,0.4) !important;
  white-space: nowrap !important;
  z-index: 999 !important;
  pointer-events: none !important;
  font-family: -apple-system, sans-serif !important;
}
/* cat-card and section children — suppress the above tooltip */
.cat-card [data-lbf-bg]::before {
  display: none !important;
}


/* Sponsor logo fit fix — keep logos inside existing card shapes without changing card size */
.sponsor-logo-wrap,
.sp {
  overflow: hidden;
  box-sizing: border-box;
}

.sponsor-logo-wrap a,
.sp > a {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  box-sizing: border-box;
}

.sponsor-logo-wrap img,
.sp img {
  display: block;
  width: auto !important;
  height: auto !important;
  max-width: 100% !important;
  max-height: 100% !important;
  object-fit: contain;
  object-position: center center;
}

.page-template-page-sponsors-php .sp a,
.page-template-page-sponsors-php .sponsor-logo-wrap a {
  padding: .7rem;
}

body.lbf-home-v2 .sp > a,
body.lbf-home-v3 .sp > a {
  padding: .45rem;
}

body.lbf-home-v3 .lbf-spd25 .sp > a {
  padding: .3rem;
}

/* ═════════════════════════════════════════════════════════════════
   v30.0.3: Footer social icons (Facebook + Instagram, brand colors).
   Placed inside .uf-ft-legal-links, immediately before Privacy Policy.
   ───────────────────────────────────────────────────────────────── */
.uf-ft-legal-links .uf-ft-social {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border-radius: 8px;
  margin: 0 2px;
  vertical-align: middle;
  transition: transform 0.15s ease, box-shadow 0.15s ease;
  text-decoration: none;
}
.uf-ft-legal-links .uf-ft-social svg {
  width: 16px;
  height: 16px;
  fill: #fff;
  display: block;
}
.uf-ft-legal-links .uf-ft-social--fb {
  background: #1877F2;
}
.uf-ft-legal-links .uf-ft-social--ig {
  background: linear-gradient(135deg, #F58529 0%, #DD2A7B 50%, #8134AF 100%);
}
.uf-ft-legal-links .uf-ft-social:hover,
.uf-ft-legal-links .uf-ft-social:focus {
  transform: translateY(-1px);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.18);
}
.uf-ft-legal-links .uf-ft-social:focus-visible {
  outline: 2px solid #f3c303;
  outline-offset: 2px;
}
