/*
Theme Name: Polara AI
Theme URI: https://polara.ai
Author: Polara AI
Author URI: https://polara.ai
Description: Custom theme for Polara AI. Italian AI agency landing page. Light/dark toggle, light default.
Version: 5.11.41
License: Proprietary
Text Domain: polara
Requires at least: 5.0
Tested up to: 6.6
Requires PHP: 7.4
*/

/* CHANGELOG
   Kept OUT of the Description: header on purpose. WordPress get_file_data()
   only parses the FIRST 8192 BYTES of style.css, so a changelog inlined into
   Description: eventually pushes Version: past the cutoff and the theme reads
   back with an EMPTY version (hit on v5.11.25: Version: had reached byte 9319).
   Add new entries HERE, newest first. Keep the header block above short.

   v5.11.39 (2026-07-31): Pulled the homepage whack-a-mole banner right back
   out ($polara_show_wm = false again) per Luca ("remove the popup it doesn't
   work"), same day it was re-launched in v5.11.38. Left the is_front_page()
   gate + 20%-scroll trigger code in place (just flag-gated off) rather than
   ripping it out, in case the fix is small once the actual complaint is
   known. The Railway-primary email-delivery fix from v5.11.38 (game leads
   now send via the same reliable path as the contact form instead of
   wp_mail) is UNRELATED to the banner and was left in place.

   v5.11.38 (2026-07-31): Re-launched the homepage whack-a-mole promo banner
   (footer.php) — it already existed fully built (IT/EN copy, dismiss +
   localStorage, links to /agente-ai-builder/) but had been gated off since
   before launch with `$polara_show_wm = false`. Re-enabled with
   `is_front_page()` (covers both /  and /en/ — the old comment's suggested
   `is_page('home-en')` was stale, that slug now just 301s to /en/, see
   functions.php's $always_redirects map). Changed the reveal trigger from a
   fixed "60% of one viewport height" to a real "20% of the page's total
   scrollable height" (document.documentElement.scrollHeight - innerHeight),
   per request — the old trigger fired at wildly different actual scroll
   depths depending on how tall the homepage is.

   Also fixed a real lead-delivery gap raised alongside this: the game's
   admin-ajax handler (polara_handle_contact in functions.php) always sent
   its OWN notification email via wp_mail() — which on this IONOS Managed WP
   install falls back to raw PHP mail() whenever no SMTP plugin is active, a
   known unreliable/spam-prone path — and only ADDITIONALLY, fire-and-forget,
   forwarded to the Railway API. The homepage contact form/chatbot/audit
   modal all send their notification through Railway's real authenticated
   SMTP (app/services/email.py) directly from the browser. Restructured so
   the Railway forward is now the PRIMARY path (blocking, response checked)
   and wp_mail is only a fallback when Railway is unreachable — so a game
   lead's email now goes out through the exact same reliable code as a
   contact-form lead, instead of a separately unreliable one, with no
   duplicate emails on the normal path.

   v5.11.37 (2026-07-31): Whack-a-mole round 6 - the extended live regression
   suite (verify_whack_a_mole_live.py, now 44 checks incl. 1366x768/1280x720
   for the reveal panel + 1280x700 for the start screen + hud/brand overlap)
   caught a real 3px regression the start-screen "fill a tall box instead of
   floating in empty space" enhancement introduced at 1280x700: the vh
   contribution added to title/coin/hint/tap font-size also grows on a SHORT
   box, and the existing max-height:820px compaction pass only touched
   padding/gap, not those font sizes - so a short box got slightly bigger
   text with the same reduced spacing, and clipped by a few px. Added
   explicit font-size caps for the four text elements inside that same
   media query. Full suite 44/44 after this fix (was 43/44).

   v5.11.36 (2026-07-31): Whack-a-mole round 5 - live-verified v5.11.35 got
   1366x768 (the single most common laptop resolution) to EXACT zero scroll
   (484/484) and 1280x800/1536x864/1280x860/1920x1080/768x1024 all clean.
   Only 1280x720 (a rare window height) had ~20px left. Added one more
   max-height:760px step (form-bridge/head margins, form gap, hours, card-
   body padding) placed AFTER the 820px block so it wins the cascade on the
   overlapping properties at same specificity (a narrower block placed
   BEFORE a wider one with equal specificity silently loses on source
   order - verified this ordering matters by getting it backwards first).

   v5.11.35 (2026-07-31): Whack-a-mole round 4 - v5.11.34's extra card-column
   trims produced ZERO further live improvement (still 505/484 at 1366x768,
   identical to v5.11.33). Root cause found by measuring the two columns
   separately: after v5.11.33's trims the CARD column (345px) had already
   shrunk below the FORM column (434px, dominated by bridge/head copy +
   email input + real Turnstile 72px + submit + trust + restart + brand) -
   so form-wrap was the actual binding constraint and every further card
   trim was invisible. Trimmed form-wrap instead: bridge/head copy margins,
   the #wm-form>*+* inter-field gap 11->8px, input/submit padding. Lesson
   for next time this needs revisiting: ALWAYS measure both columns
   separately before trimming either one - shrinking the column that isn't
   the tallest is wasted work that looks like a fix but changes nothing.

   v5.11.34 (2026-07-31): Whack-a-mole round 3 - live re-measure after v5.11.33
   (WITH the real Turnstile widget, absent from any local test) still showed a
   21px gap at 1366x768 and 64px at 1280x720. Tightened the max-height:820px
   pass further: mole avatar scale .72->.66 (margin -9px->-11px), powers-list
   font 12.5->12px/line-height 1.28->1.22/gap 5->4px, card-badge/card-body/
   hours-box/reveal padding all trimmed a further 2-6px. Verified LOCALLY
   needsScroll=false at 1366x768, 1280x720, 1280x800, 1536x864, 1280x860 (no
   Turnstile present locally, so this is the floor - live re-check is what
   actually confirms it, per the file's own repeated lesson: never trust a
   local/no-network measurement as proof against something that only renders
   over the network).

   v5.11.33 (2026-07-31): Whack-a-mole (agente-ai-builder) round 2 - v5.11.32
   only eliminated the reveal-panel scroll at the exact heights it was
   measured against (860/900/1024). Real Playwright measurement at 1366x768
   (the single most common laptop resolution) and 1280x720/800 showed it was
   NOT actually fixed there (80-130px still needed). Root cause: the round-1
   trim used fixed px paddings/margins tuned to one height, so it hit zero
   slack at 860 and simply overflowed again below it. Fix: converted the
   reveal panel's vertical rhythm (padding, gaps, card-body/mole-band
   padding, powers-list gap, hours-box margin, restart/brand margins) to
   clamp(MIN,Xvh,MAX) so it keeps shrinking proportionally on any real
   height instead of only the ones tested; added a max-height:820px pass
   (two-column only) that shrinks the mole avatar (transform:scale(.72) +
   compensating negative margin so it actually gives back layout space, not
   just visual space) and hides the secondary #wm-proof trust line
   (!important - resetForm()/Rigioca sets its inline style.display='' on
   replay, which would otherwise win back over a plain media-query rule).
   Verified needsScroll=false at 1366x768/1280x800/1536x864/1280x860/1920x1080
   locally; live re-verify pending (Turnstile's real ~72px isn't present in
   a local/no-network test). Also: (1) fixed #wm-hud/.wm-brand still
   colliding on some real widths - margin-top:26px on .wm-brand, confirmed
   clear at all tested widths; (2) start screen no longer reads as a small
   text huddle floating in a mostly-empty box on wide/tall desktops - title/
   coin-label/hint/tap font-size and .wm-start-inner gap now use
   clamp(MIN, Xvw + Yvh, MAX) so they grow on tall boxes instead of capping
   out on the vw-only clamp's low max the moment the 860px-wide cabinet cap
   is hit.

   v5.11.32 (2026-07-31): Whack-a-mole (agente-ai-builder) layout fixes, ported
   from funnel-build/whack-a-mole/index.html via port_wm_to_wp.py. Confirmed via
   live Playwright screenshots+measurements (not CSS reading alone) at 360/680/
   768/860/900/1024 widths and short-height variants (375h landscape, 700h
   desktop): (1) the star-count badge (#wm-hud, absolute top-left) had no
   clearance from the centered .wm-brand line right after it, so on any cabinet
   narrower than ~860px the two visually collided/overlapped - added
   margin-top:26px to .wm-brand and removed the narrower-still override that
   used to reset it back to 10px; (2) the coin/start screen's content could be
   clipped top+bottom by #wm-game's overflow:hidden on short viewports (proven
   at 375px landscape and 700px desktop height) - compacted .wm-start's padding
   and .wm-start-inner's gap under max-height:820px, plus overflow-y:auto safety
   net on .wm-start itself for the remaining extreme landscape-phone case (same
   pattern as #wm-reveal.active's existing scroll fallback); (3) the two-column
   desktop results panel needed to scroll despite the "no scroll" comment
   already on this code, because #wm-restart/.wm-reveal-brand were forced onto
   their own full-width flex row below both columns - moved them to be DOM
   children of #wm-form-wrap instead of siblings, so they add height to the
   shorter column instead of a new row; combined with trimming card-body/
   card-mole/powers-list/hours-box spacing, the two-column view (>=760px width,
   realistic laptop heights) now needs zero scroll (verified 768-1024px
   height); mobile single-column scrolling is unchanged and by design (existing
   comment: "the reveal panel scrolls instead"). No JS/logic/copy change.

   v5.11.31 (2026-07-30): Whack-a-mole (agente-ai-builder) aesthetic consistency
   pass. CSS-only, ported from funnel-build/whack-a-mole/index.html via
   port_wm_to_wp.py. Introduced a scoped #wm-wrap --wm-* design-token layer and
   applied 6 confirmed fixes from a multi-agent visual audit: (1) reveal/success
   panel navy #1a1a2e/#16213e/#0f3460 -> cabinet green-black #0f2019/#06422f/#080c0b
   (the payoff screen no longer reads as a foreign navy product); (2) coin-screen
   title #14c197 -> brand #3ECFAA; (3) #wm-book CTA #0d9b78->#0a7a5e (was 3.51:1 on
   white, fails AA at 16px bold - same fix already on the submit button); (4) book
   hover #0fb389->#0d9b78; (5) submit focus ring #fff->#3ECFAA; (6) stray sky-blue
   backdrop glow -> green. Deliberately UNCHANGED (adversarially verified as arcade
   character, not drift): the 9 agent branch accents (seen one-per-playthrough), the
   sky/grass/mole CRT world, deck R/Y/G hardware lights, the two-role gold system,
   in-game gold focus rings, the white-field input focus ring (#0d9b78 for 3:1). No
   JS/logic/copy/pipeline change. Verified: playthrough IT+EN @360/768/1200, 0 JS
   errors, no h-overflow, reveal full at 360, all prior-review fixes intact.

   v5.11.30 (2026-07-30): Blog tables, mobile fix. .prose is a grid item, so its
   default min-width:auto stopped it shrinking below the table min-width: at 375px
   the column ran to 512px and body{overflow-x:hidden} CLIPPED the last table
   column with no way to scroll to it. Added .post-grid > .prose { min-width: 0 }
   plus max-width:100% on the wrapper. Caught in a real browser, not by markup checks.

   v5.11.29 (2026-07-30): Blog tables. single.php gains .prose-table-wrap, a
   scroll container so a wide post table scrolls inside its own box instead of
   making the page body scroll horizontally on mobile. Paired with the SEO
   engine fix that finally converts GFM pipe tables to real <table> markup
   (they had been shipping as literal "| a | b |" text since the engine has no
   markdown library). Base .prose table/th/td rules unchanged.

   v5.11.28 (in-place update 2026-07-30): Legal entity update. Footer, terms,
   privacy (IT+EN), llms.txt and the Organization JSON-LD now identify the provider
   as Polara s.r.l.s. (P.IVA IT14832700968), legale rappresentante Luca Edward Villa,
   replacing the old ditta-individuale P.IVA IT12844070966. Footer gained a
   "Polara s.r.l.s." line. Shipped by overwriting the active polara-ai-v51128 folder
   in place (--no-activate) because IONOS Managed WP reverts theme SWITCHES back to
   the previously-active theme — a new-slug activate does not persist on this host.

   v5.11.28: SEO fixes from the 2026-07-16 audit. (1) Removed the
   scegliere-consulente-ai-2 -> /scegliere-consulente-ai/ entry from
   $always_redirects: the clean slug has no post, so WP guess-redirected it back
   to -2, producing an INFINITE 301 loop (10+ hops, live-confirmed). Removing the
   entry lets -2 (the real published post #298) serve 200; the bare slug makes at
   most one WP-canonical hop. (2) Added slugs 'privacy' and 'thank-you-en' to the
   noindex slug list (both were live index,follow: /privacy/ is a duplicate of the
   noindexed /privacy-policy/, /thank-you-en/ is a post-conversion page).

   v5.11.27: reveal panel clipped its own payoff on short desktop viewports (<=~900px tall).
   #wm-reveal.active is a wrapping flex container that ALSO scrolls; align-content:center
   pushed the first line above the scroll origin (scrollTop:0 could not reach it), so the
   "Il tuo Agente AI e pronto" headline was invisible and Rigioca was cut. Latent, but only
   triggered once v5.11.26 made Turnstile actually render (+72px). Fixed with align-content:
   safe center (plain center kept as fallback). Theme folder slug bumped to polara-ai-v51127.
   v5.11.26: complete the Google Ads CSP allowlist - gtag loads from googletagmanager but
   beacons conversions to pagead2.googlesyndication.com / googleads.g.doubleclick.net /
   google.com, so v5.11.25 un-blocked the script while every conversion ping stayed blocked
   (caught by a live browser check). Added those to connect-src + td.doubleclick.net to
   frame-src. Theme folder slug bumped to polara-ai-v51126.
   v5.11.25: whack-a-mole live-QA fixes. CSP: added worker-src 'self' blob: + blob: to script-src (Cloudflare Turnstile spins up a blob: Web Worker; without these the widget never renders and every captcha-gated submit 400s - same failure as Wayrent 2026-06-12), and allowed googletagmanager/google-analytics/googleadservices so the Google Ads conversion tag is no longer CSP-blocked site-wide. Game page: theme nav/grain/footer suppressed on lego-builder.php (the fixed nav overlaid the arcade cabinet's marquee/coin screen/back pill). Game: added a bilingual GDPR consent checkbox + language-correct privacy link (the form collected email+name+phone with no consent), focus now moves to the reveal heading for screen readers, Rigioca after a successful submit no longer leaves the submit button stuck disabled on "Invio in corso..." (a 2nd lead could never be sent), submit CTA darkened to #0a7a5e for WCAG AA (was 3.51:1), bonus stars are keyboard-hittable. Lead source (agente-ai-game) now carried into the notification email + the Railway forward. polara_whatsapp_url is now a registered setting with an admin field; success copy only promises WhatsApp when it is set. Theme folder slug bumped to polara-ai-v51125.
   v5.11.24: hide the whack-a-mole homepage sticky banner (footer.php $polara_show_wm=false) until the game is launch-ready; the banner markup, reveal JS and widgets.css styles are left intact so re-enabling is a one-line flip back to the is_front_page()||is_page('home-en') gate. Game page /agente-ai-builder left in place (unadvertised, direct-link only). Theme folder slug bumped to polara-ai-v51124.
   v5.11.23: phone is now genuinely required in the admin-ajax contact handler (polara_handle_contact rejects invalid_fields when empty) — the front-end already enforced it, and the FastAPI /api/contact ContactRequest now also requires phone (min 6). Closes the gap where the earlier v5.8.2 "backend requires it" note in practice only held for the Readiness Audit. Theme folder slug bumped to polara-ai-v51123.
   v5.11.22: mobile PageSpeed — dropped unused Geist weight 300 from the font request (weights 400-900 are the only ones used). Fonts stay async (preload+onload). Note: an async style_loader_tag defer of style.css/widgets.css was tested and REVERTED — it caused a large CLS regression (widgets.css styles the hero audit CTA), so the non-critical CSS stays render-blocking (it is small and CLS-safe). Desktop unchanged.
   v5.11.21: move ai-vendite-b2b-guida-v2 and add ai-vendite-b2b-guida-v2-2 to $always_redirects (published pages need hard redirects, not 404-only).
   v5.11.20: ROI calculator page (calcolatore-roi-agente-ai) — linkable asset for backlink strategy. Vanilla JS, real-time output, CCNL-derived hourly defaults per sector, payback vs Polara engagement cost range, priority badge. Registered in polara_create_lp_pages() + polara_page_meta_map().
   v5.11.19: backlink pre-work — fix noindex slugs (was 'privacy', now 'privacy-policy' to match actual page slug so Privacy Policy page is correctly noindexed); add 301 redirects for common legal page shorthand paths (/privacy → /privacy-policy/, /terms and /terms-of-service → /termini-di-servizio/, /cookie → /cookie-policy/). Theme folder slug bumped to polara-ai-v5119b.
   v5.11.18: page-blog-en.php template for /en/blog/ — queries polara_lang=en posts directly so the EN blog archive shows the 10 English posts.
   v5.11.17: save_post hook in i18n.php auto-sets polara_lang=en for slugs ending in -en, polara_lang=it otherwise (skips if already set) — enables EN blog posts to be published via bridge without plugin update.
   v5.11.16: fix nav.toggle_aria EN string (was Italian "Passa all'italiano").
   v5.11.15: fix meta desc &#039; double-encoding: html_entity_decode() in save_post hook + wpseo_metadesc filter at priority 99.
   v5.11.14: remove temp /schema-purge endpoint (backfill done: 18 posts cleaned to FAQPage-only).
   v5.11.12: SEO batch — defer widgets.js; remove WP emoji+block CSS; noindex /en/blog/; remove hreflang from blog posts (no EN counterparts); llms.txt served inline; 301 /home-en/→/en/ and /davvero/→/scegliere/; Gravatar alt text; trim agenti-ai-vs-zapier title to 65.
   v5.11.11: 301 /blog/page/3+ → /blog/page/2/ (post count dropped below pagination threshold after duplicate posts were privatized).
   v5.11.10: fixed `founders` → `founder` (valid Schema.org property) in ProfessionalService JSON-LD on homepage (both IT + EN variants).
   v5.11.9: save_post hook syncs post_excerpt → _yoast_wpseo_metadesc on every post save (blog posts only). Fixes missing <meta name="description"> on all Yoast-managed sites without touching the bridge plugin. Theme folder slug bumped to polara-ai-v5119.
   v5.11.8: (bridge-updater attempt, superseded by v5.11.9). Theme folder slug bumped to polara-ai-v5118.
   v5.11.7: on the 7 vertical funnels, replaced the hero "Guarda la demo" video pill (lightbox + empty <video>, no clip yet) with a "Prenota una demo" CTA scrolling to the booking form (#prenota); removed the lightbox markup + its JS. Cleaner conversion pages for paid traffic ahead of the vertical Google Ads launch. Theme folder slug bumped to polara-ai-v5117.
   v5.11.6: image-less blog listing — when a post has no featured image, home/archive/search drop the image column entirely (no "P##" placeholder tiles); list rows + the featured card collapse to full-width text. Fixes a CSS source-order bug that kept home rows pinned in the 14rem image column; featured card now hugs its content instead of a tall empty box. featured_images is disabled engine-wide. Theme folder slug bumped to polara-ai-v5116.
   v5.11.0: the 7 vertical product LPs (automazione-logistica, automazione-noleggio, ai-immobiliare, ai-system-integrator, ai-studi-dentistici, monitoraggio-prezzi-manifatturiero, reportistica-ai) rebuilt as self-contained high-conversion funnels — minimal chrome (logo + sticky "Prenota una demo" CTA), animated hero demo (chat / stepper / dual-agent KB+compilatore for noleggio), bespoke "Su di te" custom-build section, hero demo-video lightbox, inline #polara-contact-form. Each renders its own head (no get_header/get_footer) to avoid clashing with the theme's global inline CSS, but keeps the Google Ads gtag conversion (fires on /grazie), in-range title/meta + canonical/OG, and Service/FAQ/Breadcrumb JSON-LD. Shared styles in funnel.css; fully responsive (920/560 breakpoints, floating cards pulled in-viewport on mobile). Page->template assignments unchanged (same filenames). Theme folder slug bumped to polara-ai-v5110.
   v5.10.0: 7 vertical product LPs (automazione-logistica, automazione-noleggio, ai-immobiliare, ai-system-integrator, ai-studi-dentistici, monitoraggio-prezzi-manifatturiero, reportistica-ai) — industry-named, build-grounded, client-anonymized, with a before/after demo slot (video-ready) + Service/FAQ/Breadcrumb JSON-LD; registered in polara_create_lp_pages() + per-page meta in polara_page_meta_map(). Added a "Servizi correlati" cross-link block to siti-web/seo/google-ads and a "lo usiamo noi per primi" proof block to automazione-vendite-b2b (GTM). Theme folder slug bumped to polara-ai-v5100.
   v5.9.2: noindex now hard-emitted in wp_head for tag archives + legal pages (this Yoast build outputs no robots meta, so the wpseo_robots_array filter was a no-op). Theme folder slug bumped to polara-ai-v592.
   v5.9.1: on-page SEO fix (2026-06-01 audit, On-Page 56/100). Per-page title (30-65) + meta description (110-165) for every LP + the blog index via polara_page_meta_map() (was homepage-only); noindex tag archives + legal pages; 301 redirect map for stale/renamed slugs (consulenza-ai-cosa-aspettarsi*, ai-vendite-b2b-guida*, contatti); trimmed the over-length imprese-edili post title. Theme folder slug bumped to polara-ai-v591.
   v5.9.0: 3 service landing pages for the Tier-1 Google Ads strategy (siti-web, seo, google-ads), validated keyword clusters (Keyword Planner 2026-05-31). Each clones the LP pattern with service-specific HERO/PROBLEM/COS'È/SERVICES/PROCESS/FAQ + Service & FAQ JSON-LD; contact form + audit modal inherited, conversion fires on /grazie. Theme folder slug bumped to polara-ai-v590.
   v5.8.2: mandatory phone field added to all contact forms and the Readiness Audit (front-end + JS validation, full-width tel styling; backend now requires it and passes it to Attio; privacy policy IT/EN updated to list phone). Theme folder slug bumped to polara-ai-v582.
   v5.8.0: EN thank-you page (/en/thank-you-en/) now fires the Google Ads conversion (Polara Lead Form Submit), parity with /grazie.
   v5.7.9: 6 new vertical LPs for Google Ads campaign rebuild (ai-per-avvocati, ai-per-architetti, ai-per-medici, ai-per-professionisti, chatgpt-aziendale, ai-whatsapp). Each LP is a homepage clone with retargeted HERO/PROBLEM/COS'È/CTA per ad group, validated keyword set (335 KW tested across 6 rounds).
   v5.7.8: Google Ads conversion tracking (gtag.js AW-18165256941) with Consent Mode v2.
   v5.7.7: 4 IT Google Ads LPs.
   v5.7.6: H1 reflows. v5.7.5 cut "Come funziona". v5.7.4 removed redundant CTA. v5.7.3 dropped "no hiring" line.
*/
/* v5.11.1: Cloudflare Turnstile anti-spam on contact form, Readiness Audit, and chatbot (token verified server-side on the Railway API + the admin-ajax fallback). Site/secret keys in Polara Lead Capture settings. Theme folder slug bumped to polara-ai-v5111. */
