<?php
/**
 * Generates Shoptimizer dynamic css.
 *
 * @package Shoptimizer
 */

if ( ! defined( 'ABSPATH' ) ) {
	exit; // Exit if accessed directly.
}

/**
 * Transient key used to store the compiled typography CSS.
 * Including the theme version ensures the cache is automatically
 * invalidated whenever the theme is updated.
 */
function shoptimizer_css_transient_key() {
	return 'shoptimizer_typo2_css_' . md5( SHOPTIMIZER_VERSION );
}

if ( ! function_exists( 'shoptimizer_get_font_property' ) ) {
	/**
	 * Helper to access font properties.
	 *
	 * Uses a static memo table so that the same JSON string is decoded only
	 * once per request regardless of how many times the function is called
	 * with the same value (typically 2-3 calls per font slug).
	 *
	 * @since 0.1
	 *
	 * @param string $json     Raw JSON font object.
	 * @param string $property Property name to retrieve.
	 * @return string
	 */
	function shoptimizer_get_font_property( $json, $property ) {
		// Per-request decode cache: keyed by the raw JSON string.
		static $decoded_cache = array();

		$cache_key = $json; // JSON strings are suitable map keys.

		if ( ! isset( $decoded_cache[ $cache_key ] ) ) {
			$decoded_cache[ $cache_key ] = json_decode( (string) $json );
		}

		$shoptimizer_font_property = $decoded_cache[ $cache_key ];

		if ( ! is_object( $shoptimizer_font_property ) || ! isset( $shoptimizer_font_property->$property ) ) {
			return '';
		}

		if ( 'regularweight' === $property ) {
			// "regular" is Google Fonts shorthand for 400.
			if ( 'regular' === $shoptimizer_font_property->$property ) {
				$shoptimizer_font_property->$property = '400';
			}

			// Variant strings like "700italic" encode the style in the weight.
			// Strip the italic suffix so we get a clean numeric weight.
			$value = (string) $shoptimizer_font_property->$property;
			if ( false !== strpos( $value, 'italic' ) ) {
				$shoptimizer_font_property->$property = str_replace( 'italic', '', $value );
			}

			if ( '' === $shoptimizer_font_property->$property ) {
				$shoptimizer_font_property->$property = '400';
			}
		}

		return $shoptimizer_font_property->$property;
	}
}

if ( ! function_exists( 'shoptimizer_get_font_family_css' ) ) {
	/**
	 * Helper to access font properties.
	 *
	 * @since 0.1
	 */
	function shoptimizer_get_font_family_css( $font ) {
		$shoptimizer_font2_defaults = shoptimizer_typography2_defaults();
		$shoptimizer_options        = get_option( 'shoptimizer_settings', array() );
		$shoptimizer_font_settings  = wp_parse_args(
			$shoptimizer_options,
			$shoptimizer_font2_defaults
		);

		$typog2_shoptimizer_typography2_fontfamily   = shoptimizer_get_font_property( $shoptimizer_font_settings[ $font ], 'font' );
		$typog2_shoptimizer_typography2_fontcategory = shoptimizer_get_font_property( $shoptimizer_font_settings[ $font ], 'category' );

		$string_start = '"';
		$string_end   = '", ';

		$font_family_css = $string_start . $typog2_shoptimizer_typography2_fontfamily . $string_end . $typog2_shoptimizer_typography2_fontcategory;
		return $font_family_css;
	}
}

if ( ! function_exists( 'shoptimizer_maybe_font_italic_style' ) ) {
	/**
	 * Helper to check if we have italics.
	 *
	 * Uses the same static decode cache as shoptimizer_get_font_property() so
	 * no extra json_decode() calls are incurred when both helpers are called for
	 * the same font slug (the common case in shoptimizer_typography2_css()).
	 *
	 * @since 0.1
	 *
	 * @param string $json     Raw JSON font object.
	 * @param string $property Property name to inspect.
	 * @return bool
	 */
	function shoptimizer_maybe_font_italic_style( $json, $property ) {
		// Re-use the same static cache defined in shoptimizer_get_font_property().
		static $decoded_cache = array();

		$cache_key = $json;

		if ( ! isset( $decoded_cache[ $cache_key ] ) ) {
			$decoded_cache[ $cache_key ] = json_decode( (string) $json );
		}

		$shoptimizer_font_property = $decoded_cache[ $cache_key ];

		if ( ! is_object( $shoptimizer_font_property ) || ! isset( $shoptimizer_font_property->$property ) ) {
			return false;
		}

		if ( 'regularweight' === $property ) {
			$value = (string) $shoptimizer_font_property->$property;
			if ( false !== strpos( $value, 'italic' ) ) {
				return true;
			}
		}

		return false;
	}
}

if ( ! function_exists( 'shoptimizer_typography2_css' ) ) {
	/**
	 * Main function to generate typography css.
	 *
	 * This function is intentionally unaware of caching. Callers are responsible
	 * for wrapping it in shoptimizer_get_dynamic_css(), which handles transient
	 * reads and writes.
	 *
	 * @since 0.1
	 *
	 * @return string Raw CSS string.
	 */
	function shoptimizer_typography2_css() {

		$shoptimizer_font2_defaults = shoptimizer_typography2_defaults();
		$shoptimizer_options        = get_option( 'shoptimizer_settings', array() );

		$shoptimizer_font_settings = wp_parse_args(
			$shoptimizer_options,
			$shoptimizer_font2_defaults
		);

		$css = new CommerceGurus\Shoptimizer_CSS();

		// Main body.
		$css->set_selector( ':root :where(body), body, button, input, select, textarea' );
		$typog2_shoptimizer_typography2_main_body_font_family_css = shoptimizer_get_font_family_css( 'typog2_shoptimizer_typography2_main_body_fontfamily' );
		$css->add_property( 'font-family', $typog2_shoptimizer_typography2_main_body_font_family_css );
		$css->add_property( 'font-size', $shoptimizer_font_settings['shoptimizer_typography2_main_body_font_size'], '', 'px' );
		$css->add_property( 'font-weight', shoptimizer_get_font_property( $shoptimizer_font_settings['typog2_shoptimizer_typography2_main_body_fontfamily'], 'regularweight' ) );
		$css->add_property( 'color', $shoptimizer_font_settings['shoptimizer_typography2_main_body_font_color'], '' );
		if ( shoptimizer_maybe_font_italic_style( $shoptimizer_font_settings['typog2_shoptimizer_typography2_main_body_fontfamily'], 'regularweight' ) ) {
			$css->add_property( 'font-style', 'italic', '' );
		}
		$css->add_property( 'letter-spacing', $shoptimizer_font_settings['shoptimizer_typography2_main_body_font_letter_spacing'], '', 'px' );
		$css->set_selector( '.wp-block-button__link, figcaption, .wp-block-table, .wp-block-pullquote__citation' );
		$css->add_property( 'font-size', $shoptimizer_font_settings['shoptimizer_typography2_main_body_font_size'], '', 'px' );

		// Main Navigation Level 1 Menu Font.
		$css->set_selector( '.site .menu-primary-menu-container > ul > li > a, .site .site-header-cart .cart-contents' );
		$typog2_shoptimizer_typography2_mainmenu_level1_font_family_css = shoptimizer_get_font_family_css( 'typog2_shoptimizer_typography2_mainmenu_level1_fontfamily' );
		$css->add_property( 'font-family', $typog2_shoptimizer_typography2_mainmenu_level1_font_family_css );
		$css->add_property( 'font-size', $shoptimizer_font_settings['shoptimizer_typography2_mainmenu_level1_font_size'], '', 'px' );
		$css->add_property( 'font-weight', shoptimizer_get_font_property( $shoptimizer_font_settings['typog2_shoptimizer_typography2_mainmenu_level1_fontfamily'], 'regularweight' ) );
		if ( shoptimizer_maybe_font_italic_style( $shoptimizer_font_settings['typog2_shoptimizer_typography2_mainmenu_level1_fontfamily'], 'regularweight' ) ) {
			$css->add_property( 'font-style', 'italic', '' );
		}
		$css->add_property( 'letter-spacing', $shoptimizer_font_settings['shoptimizer_typography2_mainmenu_level1_font_letter_spacing'], '', 'px' );
		$css->add_property( 'text-transform', $shoptimizer_font_settings['shoptimizer_typography2_mainmenu_level1_text_transform'], '', '' );

		// Main Navigation Level 2 Menu Font.
		$css->set_selector( '.main-navigation ul.menu ul li > a, .main-navigation ul.nav-menu ul li > a' );
		$typog2_shoptimizer_typography2_mainmenu_level2_font_family_css = shoptimizer_get_font_family_css( 'typog2_shoptimizer_typography2_mainmenu_level2_fontfamily' );
		$css->add_property( 'font-family', $typog2_shoptimizer_typography2_mainmenu_level2_font_family_css );
		$css->add_property( 'font-size', $shoptimizer_font_settings['shoptimizer_typography2_mainmenu_level2_font_size'], '', 'px' );
		$css->add_property( 'font-weight', shoptimizer_get_font_property( $shoptimizer_font_settings['typog2_shoptimizer_typography2_mainmenu_level2_fontfamily'], 'regularweight' ) );
		if ( shoptimizer_maybe_font_italic_style( $shoptimizer_font_settings['typog2_shoptimizer_typography2_mainmenu_level2_fontfamily'], 'regularweight' ) ) {
			$css->add_property( 'font-style', 'italic', '' );
		}
		$css->add_property( 'text-transform', $shoptimizer_font_settings['shoptimizer_typography2_mainmenu_level2_text_transform'], '', '' );

		// Mega menu heading Font.
		$css->set_selector( '.main-navigation ul.menu li.menu-item-has-children.full-width > .sub-menu-wrapper li.menu-item-has-children > a, .main-navigation ul.menu li.menu-item-has-children.full-width > .sub-menu-wrapper li.heading > a' );
		$typog2_shoptimizer_typography2_mainmenu_heading_font_family_css = shoptimizer_get_font_family_css( 'typog2_shoptimizer_typography2_mainmenu_heading_fontfamily' );
		$css->add_property( 'font-family', $typog2_shoptimizer_typography2_mainmenu_heading_font_family_css );
		$css->add_property( 'font-size', $shoptimizer_font_settings['shoptimizer_typography2_mainmenu_heading_font_size'], '', 'px' );
		$css->add_property( 'letter-spacing', $shoptimizer_font_settings['shoptimizer_typography2_mainmenu_heading_font_letter_spacing'], '', 'px' );
		$css->add_property( 'font-weight', shoptimizer_get_font_property( $shoptimizer_font_settings['typog2_shoptimizer_typography2_mainmenu_heading_fontfamily'], 'regularweight' ) );
		if ( shoptimizer_maybe_font_italic_style( $shoptimizer_font_settings['typog2_shoptimizer_typography2_mainmenu_heading_fontfamily'], 'regularweight' ) ) {
			$css->add_property( 'font-style', 'italic', '' );
		}
		$css->add_property( 'text-transform', $shoptimizer_font_settings['shoptimizer_typography2_mainmenu_heading_font_text_transform'], '', '' );
		$css->add_property( 'color', $shoptimizer_font_settings['shoptimizer_typography2_mainmenu_heading_font_color'], '' );

		// Paragraph Font.
		$css->set_selector( '.entry-content' );
		$typog2_shoptimizer_typography2_p_font_family_css = shoptimizer_get_font_family_css( 'typog2_shoptimizer_typography2_p_fontfamily' );
		$css->add_property( 'font-family', $typog2_shoptimizer_typography2_p_font_family_css );
		$css->add_property( 'font-weight', shoptimizer_get_font_property( $shoptimizer_font_settings['typog2_shoptimizer_typography2_p_fontfamily'], 'regularweight' ) );
		if ( shoptimizer_maybe_font_italic_style( $shoptimizer_font_settings['typog2_shoptimizer_typography2_p_fontfamily'], 'regularweight' ) ) {
			$css->add_property( 'font-style', 'italic', '' );
		}
		$css->add_property( 'font-size', $shoptimizer_font_settings['shoptimizer_typography2_p_font_size'], '', 'px' );
		$css->add_property( 'letter-spacing', $shoptimizer_font_settings['shoptimizer_typography2_p_font_letter_spacing'], '', 'px' );
		$css->add_property( 'text-transform', $shoptimizer_font_settings['shoptimizer_typography2_p_font_text_transform'], '', '' );
		$css->add_property( 'color', $shoptimizer_font_settings['shoptimizer_typography2_p_font_color'], '' );

		// H1 Font.
		$css->set_selector( 'h1' );
		$typog2_shoptimizer_typography2_h1_font_family_css = shoptimizer_get_font_family_css( 'typog2_shoptimizer_typography2_h1_fontfamily' );
		$css->add_property( 'font-family', $typog2_shoptimizer_typography2_h1_font_family_css );
		$css->add_property( 'font-weight', shoptimizer_get_font_property( $shoptimizer_font_settings['typog2_shoptimizer_typography2_h1_fontfamily'], 'regularweight' ) );
		if ( shoptimizer_maybe_font_italic_style( $shoptimizer_font_settings['typog2_shoptimizer_typography2_h1_fontfamily'], 'regularweight' ) ) {
			$css->add_property( 'font-style', 'italic', '' );
		}
		$css->add_property( 'font-size', $shoptimizer_font_settings['shoptimizer_typography2_h1_font_size'], '', 'px' );
		$css->add_property( 'letter-spacing', $shoptimizer_font_settings['shoptimizer_typography2_h1_font_letter_spacing'], '', 'px' );
		$css->add_property( 'text-transform', $shoptimizer_font_settings['shoptimizer_typography2_h1_font_text_transform'], '', '' );
		$css->add_property( 'line-height', $shoptimizer_font_settings['shoptimizer_typography2_h1_font_line_height'], '', '' );
		$css->add_property( 'color', $shoptimizer_font_settings['shoptimizer_typography2_h1_font_color'], '' );

		// H2 Font.
		$css->set_selector( 'h2, .wp-block-heading h2' );
		$typog2_shoptimizer_typography2_h2_font_family_css = shoptimizer_get_font_family_css( 'typog2_shoptimizer_typography2_h2_fontfamily' );
		$css->add_property( 'font-family', $typog2_shoptimizer_typography2_h2_font_family_css );
		$css->add_property( 'font-weight', shoptimizer_get_font_property( $shoptimizer_font_settings['typog2_shoptimizer_typography2_h2_fontfamily'], 'regularweight' ) );
		if ( shoptimizer_maybe_font_italic_style( $shoptimizer_font_settings['typog2_shoptimizer_typography2_h2_fontfamily'], 'regularweight' ) ) {
			$css->add_property( 'font-style', 'italic', '' );
		}
		$css->add_property( 'font-size', $shoptimizer_font_settings['shoptimizer_typography2_h2_font_size'], '', 'px' );
		$css->add_property( 'letter-spacing', $shoptimizer_font_settings['shoptimizer_typography2_h2_font_letter_spacing'], '', 'px' );
		$css->add_property( 'text-transform', $shoptimizer_font_settings['shoptimizer_typography2_h2_font_text_transform'], '', '' );
		$css->add_property( 'line-height', $shoptimizer_font_settings['shoptimizer_typography2_h2_font_line_height'], '', '' );
		$css->add_property( 'color', $shoptimizer_font_settings['shoptimizer_typography2_h2_font_color'], '' );

		// H3 Font.
		$css->set_selector( 'h3, .wp-block-heading h3' );
		$typog2_shoptimizer_typography2_h3_font_family_css = shoptimizer_get_font_family_css( 'typog2_shoptimizer_typography2_h3_fontfamily' );
		$css->add_property( 'font-family', $typog2_shoptimizer_typography2_h3_font_family_css );
		$css->add_property( 'font-weight', shoptimizer_get_font_property( $shoptimizer_font_settings['typog2_shoptimizer_typography2_h3_fontfamily'], 'regularweight' ) );
		if ( shoptimizer_maybe_font_italic_style( $shoptimizer_font_settings['typog2_shoptimizer_typography2_h3_fontfamily'], 'regularweight' ) ) {
			$css->add_property( 'font-style', 'italic', '' );
		}
		$css->add_property( 'font-size', $shoptimizer_font_settings['shoptimizer_typography2_h3_font_size'], '', 'px' );
		$css->add_property( 'letter-spacing', $shoptimizer_font_settings['shoptimizer_typography2_h3_font_letter_spacing'], '', 'px' );
		$css->add_property( 'text-transform', $shoptimizer_font_settings['shoptimizer_typography2_h3_font_text_transform'], '', '' );
		$css->add_property( 'line-height', $shoptimizer_font_settings['shoptimizer_typography2_h3_font_line_height'], '', '' );
		$css->add_property( 'color', $shoptimizer_font_settings['shoptimizer_typography2_h3_font_color'], '' );

		// H4 Font.
		$css->set_selector( 'h4, .wp-block-heading h4' );
		$typog2_shoptimizer_typography2_h4_font_family_css = shoptimizer_get_font_family_css( 'typog2_shoptimizer_typography2_h4_fontfamily' );
		$css->add_property( 'font-family', $typog2_shoptimizer_typography2_h4_font_family_css );
		$css->add_property( 'font-weight', shoptimizer_get_font_property( $shoptimizer_font_settings['typog2_shoptimizer_typography2_h4_fontfamily'], 'regularweight' ) );
		if ( shoptimizer_maybe_font_italic_style( $shoptimizer_font_settings['typog2_shoptimizer_typography2_h4_fontfamily'], 'regularweight' ) ) {
			$css->add_property( 'font-style', 'italic', '' );
		}
		$css->add_property( 'font-size', $shoptimizer_font_settings['shoptimizer_typography2_h4_font_size'], '', 'px' );
		$css->add_property( 'letter-spacing', $shoptimizer_font_settings['shoptimizer_typography2_h4_font_letter_spacing'], '', 'px' );
		$css->add_property( 'text-transform', $shoptimizer_font_settings['shoptimizer_typography2_h4_font_text_transform'], '', '' );
		$css->add_property( 'line-height', $shoptimizer_font_settings['shoptimizer_typography2_h4_font_line_height'], '', '' );
		$css->add_property( 'color', $shoptimizer_font_settings['shoptimizer_typography2_h4_font_color'], '' );

		// H5 Font.
		$css->set_selector( 'h5, .wp-block-heading h5' );
		$typog2_shoptimizer_typography2_h5_font_family_css = shoptimizer_get_font_family_css( 'typog2_shoptimizer_typography2_h5_fontfamily' );
		$css->add_property( 'font-family', $typog2_shoptimizer_typography2_h5_font_family_css );
		$css->add_property( 'font-weight', shoptimizer_get_font_property( $shoptimizer_font_settings['typog2_shoptimizer_typography2_h5_fontfamily'], 'regularweight' ) );
		if ( shoptimizer_maybe_font_italic_style( $shoptimizer_font_settings['typog2_shoptimizer_typography2_h5_fontfamily'], 'regularweight' ) ) {
			$css->add_property( 'font-style', 'italic', '' );
		}
		$css->add_property( 'font-size', $shoptimizer_font_settings['shoptimizer_typography2_h5_font_size'], '', 'px' );
		$css->add_property( 'letter-spacing', $shoptimizer_font_settings['shoptimizer_typography2_h5_font_letter_spacing'], '', 'px' );
		$css->add_property( 'text-transform', $shoptimizer_font_settings['shoptimizer_typography2_h5_font_text_transform'], '', '' );
		$css->add_property( 'line-height', $shoptimizer_font_settings['shoptimizer_typography2_h5_font_line_height'], '', '' );
		$css->add_property( 'color', $shoptimizer_font_settings['shoptimizer_typography2_h5_font_color'], '' );

		// Blockquote Font.
		$css->set_selector( 'blockquote p, .edit-post-visual-editor.editor-styles-wrapper .wp-block-quote p, .edit-post-visual-editor.editor-styles-wrapper .wp-block-quote' );
		$typog2_shoptimizer_typography2_blockquote_font_family_css = shoptimizer_get_font_family_css( 'typog2_shoptimizer_typography2_blockquote_fontfamily' );
		$css->add_property( 'font-family', $typog2_shoptimizer_typography2_blockquote_font_family_css );
		$css->add_property( 'font-weight', shoptimizer_get_font_property( $shoptimizer_font_settings['typog2_shoptimizer_typography2_blockquote_fontfamily'], 'regularweight' ) );
		if ( shoptimizer_maybe_font_italic_style( $shoptimizer_font_settings['typog2_shoptimizer_typography2_blockquote_fontfamily'], 'regularweight' ) ) {
			$css->add_property( 'font-style', 'italic', '' );
		}
		$css->add_property( 'font-size', $shoptimizer_font_settings['shoptimizer_typography2_blockquote_font_size'], '', 'px' );
		$css->add_property( 'letter-spacing', $shoptimizer_font_settings['shoptimizer_typography2_blockquote_font_letter_spacing'], '', 'px' );
		$css->add_property( 'text-transform', $shoptimizer_font_settings['shoptimizer_typography2_blockquote_font_text_transform'], '', '' );
		$css->add_property( 'line-height', $shoptimizer_font_settings['shoptimizer_typography2_blockquote_font_line_height'], '', '' );
		$css->add_property( 'color', $shoptimizer_font_settings['shoptimizer_typography2_blockquote_font_color'], '' );

		// Widget Title Font.
		$css->set_selector( '.widget .widget-title, .widget .widgettitle' );
		$typog2_shoptimizer_typography2_widget_title_font_family_css = shoptimizer_get_font_family_css( 'typog2_shoptimizer_typography2_widget_title_fontfamily' );
		$css->add_property( 'font-family', $typog2_shoptimizer_typography2_widget_title_font_family_css );
		$css->add_property( 'font-weight', shoptimizer_get_font_property( $shoptimizer_font_settings['typog2_shoptimizer_typography2_widget_title_fontfamily'], 'regularweight' ) );
		if ( shoptimizer_maybe_font_italic_style( $shoptimizer_font_settings['typog2_shoptimizer_typography2_widget_title_fontfamily'], 'regularweight' ) ) {
			$css->add_property( 'font-style', 'italic', '' );
		}
		$css->add_property( 'font-size', $shoptimizer_font_settings['shoptimizer_typography2_widget_title_font_size'], '', 'px' );
		$css->add_property( 'letter-spacing', $shoptimizer_font_settings['shoptimizer_typography2_widget_title_font_letter_spacing'], '', 'px' );
		$css->add_property( 'text-transform', $shoptimizer_font_settings['shoptimizer_typography2_widget_title_font_text_transform'], '', '' );
		$css->add_property( 'line-height', $shoptimizer_font_settings['shoptimizer_typography2_widget_title_font_line_height'], '', '' );
		$css->add_property( 'color', $shoptimizer_font_settings['shoptimizer_typography2_widget_title_font_color'], '' );

		// Blog Post Font.
		$css->set_selector( 'body.single-post h1' );
		$typog2_shoptimizer_typography2_blog_post_font_family_css = shoptimizer_get_font_family_css( 'typog2_shoptimizer_typography2_blog_post_fontfamily' );
		$css->add_property( 'font-family', $typog2_shoptimizer_typography2_widget_title_font_family_css );
		$css->add_property( 'font-weight', shoptimizer_get_font_property( $shoptimizer_font_settings['typog2_shoptimizer_typography2_blog_post_fontfamily'], 'regularweight' ) );
		if ( shoptimizer_maybe_font_italic_style( $shoptimizer_font_settings['typog2_shoptimizer_typography2_blog_post_fontfamily'], 'regularweight' ) ) {
			$css->add_property( 'font-style', 'italic', '' );
		}
		$css->add_property( 'font-size', $shoptimizer_font_settings['shoptimizer_typography2_blog_post_font_size'], '', 'px' );
		$css->add_property( 'letter-spacing', $shoptimizer_font_settings['shoptimizer_typography2_blog_post_font_letter_spacing'], '', 'px' );
		$css->add_property( 'text-transform', $shoptimizer_font_settings['shoptimizer_typography2_blog_post_font_text_transform'], '', '' );
		$css->add_property( 'line-height', $shoptimizer_font_settings['shoptimizer_typography2_blog_post_font_line_height'], '', '' );
		$css->add_property( 'color', $shoptimizer_font_settings['shoptimizer_typography2_blog_post_font_color'], '' );

		// Archives Category Description.
		$css->set_selector( '.term-description, .shoptimizer-category-banner .taxonomy-description' );
		$typog2_shoptimizer_typography2_woocommerce_archives_description_font_family_css = shoptimizer_get_font_family_css( 'typog2_shoptimizer_typography2_woocommerce_archives_description_fontfamily' );
		$css->add_property( 'font-family', $typog2_shoptimizer_typography2_woocommerce_archives_description_font_family_css );
		$css->add_property( 'font-weight', shoptimizer_get_font_property( $shoptimizer_font_settings['typog2_shoptimizer_typography2_woocommerce_archives_description_fontfamily'], 'regularweight' ) );
		if ( shoptimizer_maybe_font_italic_style( $shoptimizer_font_settings['typog2_shoptimizer_typography2_woocommerce_archives_description_fontfamily'], 'regularweight' ) ) {
			$css->add_property( 'font-style', 'italic', '' );
		}
		$css->add_property( 'font-size', $shoptimizer_font_settings['shoptimizer_typography2_woocommerce_archives_description_font_size'], '', 'px' );
		$css->add_property( 'letter-spacing', $shoptimizer_font_settings['shoptimizer_typography2_woocommerce_archives_description_font_letter_spacing'], '', 'px' );
		$css->add_property( 'text-transform', $shoptimizer_font_settings['shoptimizer_typography2_woocommerce_archives_description_font_text_transform'], '', '' );
		$css->add_property( 'line-height', $shoptimizer_font_settings['shoptimizer_typography2_woocommerce_archives_description_font_line_height'], '', '' );
		$css->add_property( 'color', $shoptimizer_font_settings['shoptimizer_typography2_woocommerce_archives_description_font_color'], '' );

		// Archives Product Title.
		$css->set_selector(
			'ul.products li.product .woocommerce-loop-product__title, ul.products li.product:not(.product-category) h2.woocommerce-loop-product__title,
			ul.products li.product .woocommerce-loop-product__title, ul.products li.product .woocommerce-loop-product__title,
			.main-navigation ul.menu ul li.product .woocommerce-loop-product__title a'
		);
		$typog2_shoptimizer_typography2_woocommerce_listings_title_font_family_css = shoptimizer_get_font_family_css( 'typog2_shoptimizer_typography2_woocommerce_listings_title_fontfamily' );
		$css->add_property( 'font-family', $typog2_shoptimizer_typography2_woocommerce_listings_title_font_family_css );
		$css->add_property( 'font-weight', shoptimizer_get_font_property( $shoptimizer_font_settings['typog2_shoptimizer_typography2_woocommerce_listings_title_fontfamily'], 'regularweight' ) );
		if ( shoptimizer_maybe_font_italic_style( $shoptimizer_font_settings['typog2_shoptimizer_typography2_woocommerce_listings_title_fontfamily'], 'regularweight' ) ) {
			$css->add_property( 'font-style', 'italic', '' );
		}
		$css->add_property( 'font-size', $shoptimizer_font_settings['shoptimizer_typography2_woocommerce_listings_title_font_size'], '', 'px' );
		$css->add_property( 'letter-spacing', $shoptimizer_font_settings['shoptimizer_typography2_woocommerce_listings_title_font_letter_spacing'], '', 'px' );
		$css->add_property( 'text-transform', $shoptimizer_font_settings['shoptimizer_typography2_woocommerce_listings_title_font_text_transform'], '', '' );
		$css->add_property( 'line-height', $shoptimizer_font_settings['shoptimizer_typography2_woocommerce_listings_title_font_line_height'], '', '' );
		$css->add_property( 'color', $shoptimizer_font_settings['shoptimizer_typography2_woocommerce_listings_title_font_color'], '' );

		// Single Product Title.
		$css->start_media_query( '(min-width:770px)' );
		$css->set_selector( '.single-product h1' );
		$typog2_shoptimizer_typography2_woocommerce_single_title_font_family_css = shoptimizer_get_font_family_css( 'typog2_shoptimizer_typography2_woocommerce_single_title_fontfamily' );
		$css->add_property( 'font-family', $typog2_shoptimizer_typography2_woocommerce_single_title_font_family_css );
		$css->add_property( 'font-weight', shoptimizer_get_font_property( $shoptimizer_font_settings['typog2_shoptimizer_typography2_woocommerce_single_title_fontfamily'], 'regularweight' ) );
		if ( shoptimizer_maybe_font_italic_style( $shoptimizer_font_settings['typog2_shoptimizer_typography2_woocommerce_single_title_fontfamily'], 'regularweight' ) ) {
			$css->add_property( 'font-style', 'italic', '' );
		}
		$css->add_property( 'font-size', $shoptimizer_font_settings['shoptimizer_typography2_woocommerce_single_title_font_size'], '', 'px' );
		$css->add_property( 'letter-spacing', $shoptimizer_font_settings['shoptimizer_typography2_woocommerce_single_title_font_letter_spacing'], '', 'px' );
		$css->add_property( 'text-transform', $shoptimizer_font_settings['shoptimizer_typography2_woocommerce_single_title_font_text_transform'], '', '' );
		$css->add_property( 'line-height', $shoptimizer_font_settings['shoptimizer_typography2_woocommerce_single_title_font_line_height'], '', '' );
		$css->add_property( 'color', $shoptimizer_font_settings['shoptimizer_typography2_woocommerce_single_title_font_color'], '' );
		$css->stop_media_query();

		// Primary Buttons.
		$css->set_selector(
			'body .woocommerce #respond input#submit.alt, 
			body .woocommerce a.button.alt, 
			body .woocommerce button.button.alt, 
			body .woocommerce input.button.alt,
			.product .cart .single_add_to_cart_button,
			.shoptimizer-sticky-add-to-cart__content-button a.button,
			.widget_shopping_cart a.button.checkout'
		);
		$typog2_shoptimizer_typography2_woocommerce_primary_button_font_family_css = shoptimizer_get_font_family_css( 'typog2_shoptimizer_typography2_woocommerce_primary_button_fontfamily' );
		$css->add_property( 'font-family', $typog2_shoptimizer_typography2_woocommerce_primary_button_font_family_css );
		$css->add_property( 'font-weight', shoptimizer_get_font_property( $shoptimizer_font_settings['typog2_shoptimizer_typography2_woocommerce_primary_button_fontfamily'], 'regularweight' ) );
		if ( shoptimizer_maybe_font_italic_style( $shoptimizer_font_settings['typog2_shoptimizer_typography2_woocommerce_primary_button_fontfamily'], 'regularweight' ) ) {
			$css->add_property( 'font-style', 'italic', '' );
		}
		$css->add_property( 'font-size', $shoptimizer_font_settings['shoptimizer_typography2_woocommerce_primary_button_font_size'], '', 'px' );
		$css->add_property( 'letter-spacing', $shoptimizer_font_settings['shoptimizer_typography2_woocommerce_primary_button_font_letter_spacing'], '', 'px' );
		$css->add_property( 'text-transform', $shoptimizer_font_settings['shoptimizer_typography2_woocommerce_primary_button_font_text_transform'], '', '' );
		//$css->add_property( 'color', $shoptimizer_font_settings['shoptimizer_typography2_woocommerce_primary_button_font_color'], '' );

		do_action( 'shoptimizer_typography2_css', $css );

		return apply_filters( 'shoptimizer_typography2_css_output', $css->css_output() );
	}
}

// ---------------------------------------------------------------------------
// Caching layer
// ---------------------------------------------------------------------------

/**
 * Return the compiled typography CSS, reading from the transient when available.
 *
 * This is the single public entry-point used by both front-end enqueue and the
 * customizer preview. The transient has no expiry (0) because it is explicitly
 * invalidated by shoptimizer_invalidate_css_transient() on every customizer
 * save, ensuring changes are always reflected immediately on the next request.
 *
 * @return string Compiled CSS string.
 */
function shoptimizer_get_dynamic_css() {
	$transient_key = shoptimizer_css_transient_key();

	// Return cached value on cache hit.
	$cached = get_transient( $transient_key );
	if ( false !== $cached ) {
		return apply_filters( 'shoptimizer_dynamic_css', $cached );
	}

	// Cache miss: generate, store, return.
	$css = wp_strip_all_tags( shoptimizer_typography2_css() );

	// Transient with no expiry (0) - invalidated explicitly on customizer save.
	set_transient( $transient_key, $css, 0 );

	return apply_filters( 'shoptimizer_dynamic_css', $css );
}

/**
 * Delete the CSS transient so the next front-end request regenerates it.
 *
 * Deleting (rather than overwriting) keeps this hook lightweight: it does not
 * need to bootstrap the full CSS generation pipeline during the admin save
 * request. The actual rebuild is deferred to the first front-end page load.
 */
function shoptimizer_invalidate_css_transient() {
	delete_transient( shoptimizer_css_transient_key() );
}
add_action( 'customize_save_after', 'shoptimizer_invalidate_css_transient' );

/**
 * After invalidation, immediately regenerate and persist the fonts preload list
 * so it stays consistent with the new settings without waiting for a page view.
 *
 * We hook at priority 11 so shoptimizer_invalidate_css_transient() (priority 10)
 * has already cleared the stale value before we regenerate.
 */
function shoptimizer_rebuild_css_after_customizer_save() {
	// Prime the transient with fresh CSS.
	shoptimizer_get_dynamic_css();

	// Regenerate preload font hints (unchanged behaviour from original).
	shoptimizer_fonts2_generate_preload_fonts();
}
add_action( 'customize_save_after', 'shoptimizer_rebuild_css_after_customizer_save', 11 );

// ---------------------------------------------------------------------------
// Enqueue
// ---------------------------------------------------------------------------

add_action( 'wp_enqueue_scripts', 'shoptimizer_enqueue_dynamic_css', 50 );
/**
 * Enqueue our dynamic CSS.
 *
 * During customizer previews WordPress never persists settings, so we always
 * regenerate directly there (bypassing the transient) to give live feedback.
 * On all normal front-end requests shoptimizer_get_dynamic_css() handles the
 * transient read-or-generate logic transparently.
 */
function shoptimizer_enqueue_dynamic_css() {
	if ( is_customize_preview() ) {
		// Bypass transient so live-preview changes are always reflected.
		$css = wp_strip_all_tags( shoptimizer_typography2_css() );
		wp_add_inline_style( 'preview-gfonts', $css );
	} else {
		$css = shoptimizer_get_dynamic_css();
		wp_add_inline_style( 'shoptimizer-dynamic-style', wp_strip_all_tags( $css ) );
	}
}
