<?php

if (!defined('ABSPATH')) {
    exit;
}

class AIEO_Google_Reviews_Block {

    private static $css_printed = false;
    private static $registered  = false;

    
    public static function register() {
        if (self::$registered) { return; }
        self::$registered = true;
        add_action('init', array(__CLASS__, 'register_block'));
        add_action('init', array(__CLASS__, 'register_shortcodes'));
        add_action('wp_enqueue_scripts', array(__CLASS__, 'maybe_enqueue_css'));
    }

    
    public static function register_shortcodes() {
        if (!function_exists('add_shortcode')) { return; }
        add_shortcode('aieo_google_reviews',        array(__CLASS__, 'shortcode_reviews'));
        add_shortcode('aieo_google_locations_grid', array(__CLASS__, 'shortcode_grid'));
    }

    
    private static function shortcode_bool($v, $default = false) {
        if ($v === '' || $v === null) { return (bool) $default; }
        return in_array(strtolower((string) $v), array('yes', 'true', '1', 'on'), true);
    }

    
    private static function shortcode_dispatch(array $atts, $mode_fallback) {
        $atts = shortcode_atts(array(
            'mode'             => '',
            'location'         => '',  
            'min_rating'       => 5,
            'max_count'        => 5,
            'layout'           => 'grid',
            'presentation'     => 'static',
            'autoplay_sec'     => 6,
            'show_overall'     => 'yes',
            'show_rate_us'     => 'yes',
            'show_maps_button' => 'no',
            'heading'          => '',
        ), $atts, 'aieo_google_reviews');

        $mode = (string) $atts['mode'];
        if ($mode === '') {
            $mode = !empty($atts['location']) ? 'single' : $mode_fallback;
        }

        return self::render(array(
            'mode'           => $mode,
            'locationSlug'   => (string) $atts['location'],
            'minRating'      => (int) $atts['min_rating'],
            'maxCount'       => (int) $atts['max_count'],
            'layout'         => (string) $atts['layout'],
            'presentation'   => (string) $atts['presentation'],
            'autoplaySec'    => (int) $atts['autoplay_sec'],
            'showOverall'    => self::shortcode_bool($atts['show_overall'], true),
            'showRateUs'     => self::shortcode_bool($atts['show_rate_us'], true),
            'showMapsButton' => self::shortcode_bool($atts['show_maps_button'], false),
            'heading'        => (string) $atts['heading'],
        ));
    }

    public static function shortcode_reviews($atts) {
        return self::shortcode_dispatch((array) $atts, 'all_mixed');
    }

    public static function shortcode_grid($atts) {
        
        $atts = (array) $atts;
        $atts['mode'] = 'cards_grid';
        return self::shortcode_dispatch($atts, 'cards_grid');
    }

    public static function register_block() {
        
        if (!class_exists('AIEO_Block_Header')) {
            $hp = AIEO_DIR . 'includes/class-aieo-block-header.php';
            if (file_exists($hp)) { require_once $hp; }
        }
        $hdr_rel = 'assets/js/aieo-block-header.js';
        $hdr_abs = AIEO_DIR . $hdr_rel;
        if (file_exists($hdr_abs) && !wp_script_is('aieo-block-header', 'registered')) {
            wp_register_script('aieo-block-header', plugins_url($hdr_rel, AIEO_FILE), array('wp-element', 'wp-components', 'wp-i18n'), (string) filemtime($hdr_abs), true);
        }

        
        
        
        
        
        
        $editor_path = 'assets/js/aieo-google-reviews-editor.js';
        $editor_abs  = AIEO_DIR . $editor_path;
        $editor_url  = plugins_url($editor_path, AIEO_FILE);
        $editor_ver  = file_exists($editor_abs) ? (string) filemtime($editor_abs) : '1.0';
        wp_register_script(
            'aieo-google-reviews-editor',
            $editor_url,
            array('wp-blocks', 'wp-element', 'wp-block-editor', 'wp-components', 'wp-i18n', 'wp-server-side-render', 'aieo-block-header'),
            $editor_ver,
            true
        );

        register_block_type('aieo/google-reviews', array(
            'api_version'     => 3,
            'title'           => __('AIEO Google Reviews', 'ai-eshop-optimizer'),
            'description'     => __('Live Google reviews pulled from the local cache. Single location, mixed feed, or cards grid.', 'ai-eshop-optimizer'),
            'category'        => 'widgets',
            'icon'            => 'star-filled',
            'editor_script'   => 'aieo-google-reviews-editor',
            'keywords'        => array('google', 'reviews', 'rating', 'stars', 'store', 'location'),
            'supports'        => array(
                'align'      => array('wide', 'full'),
                'anchor'     => true,
                
                
                
                'spacing'    => array('margin' => true, 'padding' => true),
                'typography' => array('fontSize' => true, 'lineHeight' => true),
                'color'      => array('background' => true, 'text' => true),
            ),
            
            
            
            
            
            'uses_context'    => array('postId', 'postType', 'queryId'),
            'attributes'      => array_merge(array(
                'mode'           => array('type' => 'string', 'default' => 'single'),
                'locationSlug'   => array('type' => 'string', 'default' => ''),
                'minRating'      => array('type' => 'number', 'default' => 5),
                'maxCount'       => array('type' => 'number', 'default' => 5),
                'showOverall'    => array('type' => 'boolean','default' => true),
                'showRateUs'     => array('type' => 'boolean','default' => true),
                'showMapsButton' => array('type' => 'boolean','default' => false),
                'layout'         => array('type' => 'string', 'default' => 'grid'),
                
                
                
                'presentation'   => array('type' => 'string', 'default' => 'static'),
                'autoplaySec'    => array('type' => 'number', 'default' => 6),
                'heading'        => array('type' => 'string', 'default' => ''),
            ), class_exists('AIEO_Block_Header') ? AIEO_Block_Header::block_attributes() : array()),
            'render_callback' => array(__CLASS__, 'render'),
        ));
    }

    public static function render($attrs, $content = '', $block = null) {
        $attrs = wp_parse_args(is_array($attrs) ? $attrs : array(), array(
            'mode'           => 'single',
            'locationSlug'   => '',
            'minRating'      => 5,
            'maxCount'       => 5,
            'showOverall'    => true,
            'showRateUs'     => true,
            'showMapsButton' => false,
            'layout'         => 'grid',
            'presentation'   => 'static',
            'autoplaySec'    => 6,
            'heading'        => '',
        ));

        $header = class_exists('AIEO_Block_Header') ? AIEO_Block_Header::render($attrs) : '';

        $mode      = in_array($attrs['mode'], array('single','all_mixed','cards_grid'), true) ? $attrs['mode'] : 'single';
        $min       = max(0, min(5, (int) $attrs['minRating']));
        if ($min < 1) { $min = 1; }
        $count     = max(0, min(50, (int) $attrs['maxCount']));
        $layout    = in_array($attrs['layout'], array('grid','list','carousel'), true) ? $attrs['layout'] : 'grid';
        $overall   = !empty($attrs['showOverall']);
        $rate_us   = !empty($attrs['showRateUs']);
        $maps_btn  = !empty($attrs['showMapsButton']);
        $heading   = (string) $attrs['heading'];

        
        
        
        
        $cache_scope = 'all';
        $resolved_loc = null;

        if ($mode === 'single') {
            $resolved_loc = self::resolve_single_location($attrs['locationSlug'], $block);
            if (!$resolved_loc) {
                
                
                
                $all = AIEO_Google_Reviews_Locations::list_all(true);
                $n = is_array($all) ? count($all) : 0;
                if ($n === 0) {
                    $msg = __('No Google Reviews locations configured yet. Add one under e-shop Manager → Google Reviews → Locations.', 'ai-eshop-optimizer');
                } else {
                    $msg = sprintf(
                        
                        __('This block is in "Single location" mode but no location is selected. You have %1$d locations configured — pick one via the block\'s sidebar (locationSlug attribute), or switch the block / shortcode to "All locations (mixed)" / "Cards grid" mode to render all of them.', 'ai-eshop-optimizer'),
                        $n
                    );
                }
                return self::finalize(self::empty_state($msg), $header, $attrs, $block);
            }
            $cache_scope = (int) $resolved_loc['id'];
        }

        $settings = AIEO_Google_Reviews_Settings::get_all();
        if (!empty($settings['block_cache_enabled'])) {
            $cache_attrs = array_merge($attrs, array('mode' => $mode));
            $hash = AIEO_Google_Reviews_Helpers::cache_hash($cache_attrs);
            $cached = AIEO_Google_Reviews_Cache::render_get($cache_scope, $hash);
            if ($cached !== false && is_string($cached)) {
                return self::finalize($cached, $header, $attrs, $block);
            }
        }

        $presentation = in_array($attrs['presentation'], array('static', 'slider', 'rotator'), true) ? $attrs['presentation'] : 'static';
        $autoplay     = max(2, min(60, (int) $attrs['autoplaySec']));

        switch ($mode) {
            case 'cards_grid': $html = self::render_cards_grid($min, $count); break;
            case 'all_mixed':  $html = self::render_all_mixed($min, $count, $layout, $heading, $overall, $presentation, $autoplay); break;
            case 'single':
            default:           $html = self::render_single($resolved_loc, $min, $count, $layout, $heading, $overall, $rate_us, $maps_btn, $presentation, $autoplay);
        }

        if (!empty($settings['block_cache_enabled']) && isset($hash)) {
            AIEO_Google_Reviews_Cache::render_set($cache_scope, $hash, $html);
        }
        
        
        
        return self::finalize($html, $header, $attrs, $block);
    }

    
    private static function finalize($body, $header, $attrs, $block = null) {
        $out = $header . $body;
        
        
        
        if (function_exists('get_block_wrapper_attributes') && $block instanceof WP_Block) {
            $out = '<div ' . get_block_wrapper_attributes() . '>' . $out . '</div>';
        } else {
            $align = isset($attrs['align']) ? sanitize_html_class((string) $attrs['align']) : '';
            if ($align === 'full' || $align === 'wide') {
                $out = '<div class="align' . $align . '">' . $out . '</div>';
            }
        }
        return $out;
    }

    private static function resolve_single_location($slug, $block = null) {
        $slug = trim((string) $slug);
        if ($slug !== '') {
            return AIEO_Google_Reviews_Locations::get_by_slug($slug);
        }
        
        
        
        
        $pid = 0;
        if (is_object($block) && isset($block->context['postId'])) {
            $pid = (int) $block->context['postId'];
        }
        
        if ($pid <= 0 && is_singular()) {
            $pid = (int) get_queried_object_id();
        }
        
        
        if ($pid <= 0) {
            $gp = get_post();
            if ($gp instanceof WP_Post) { $pid = (int) $gp->ID; }
        }
        if ($pid > 0) {
            $loc = AIEO_Google_Reviews_Helpers::resolve_location_for_post($pid);
            if ($loc) { return $loc; }
        }
        
        
        
        
        
        
        $all = AIEO_Google_Reviews_Locations::list_all(true);
        if (is_array($all) && count($all) === 1) {
            return reset($all);
        }
        return null;
    }

    private static function render_single($loc, $min, $count, $layout, $heading, $overall, $rate_us, $maps_btn = false, $presentation = 'static', $autoplay = 6) {
        $reviews = $count > 0
            ? AIEO_Google_Reviews_Helpers::fetch_reviews_for_location((int) $loc['id'], $count, $min)
            : array();

        $out  = '<section class="aieo-grv aieo-grv--single aieo-grv--' . esc_attr($layout) . '" data-location="' . esc_attr($loc['slug']) . '">';
        if ($heading !== '') {
            $out .= '<h2 class="aieo-grv__heading">' . esc_html($heading) . '</h2>';
        }
        
        
        
        
        if ($overall || $rate_us) {
            $out .= self::overall_header($loc, $rate_us, false, $overall);
        }
        if ($maps_btn) {
            $out .= self::maps_button_row($loc);
        }
        if ($count > 0) {
            $out .= self::reviews_block($reviews, $layout, false, $presentation, $autoplay);
        }
        $out .= '</section>';
        return $out;
    }

    
    private static function maps_button_row(array $loc) {
        $maps = AIEO_Google_Reviews_Helpers::maps_url($loc);
        if ($maps === '') { return ''; }
        $out  = '<div class="wp-block-buttons aieo-grv-buttons aieo-grv-buttons--maps-row" style="margin:10px 0 14px;">';
        $out .= '<div class="wp-block-button is-style-outline has-custom-font-size has-sm-font-size">';
        $out .= '<a class="wp-block-button__link wp-element-button aieo-grv-btn aieo-grv-btn--maps" href="' . esc_url($maps) . '" target="_blank" rel="noopener noreferrer">' . esc_html__('Open in Google Maps', 'ai-eshop-optimizer') . '</a>';
        $out .= '</div></div>';
        return $out;
    }

    private static function render_all_mixed($min, $count, $layout, $heading, $overall, $presentation = 'static', $autoplay = 6) {
        $reviews = AIEO_Google_Reviews_Helpers::fetch_reviews_mixed($count, $min);

        $out = '<section class="aieo-grv aieo-grv--all aieo-grv--' . esc_attr($layout) . '">';
        if ($heading !== '') {
            $out .= '<h2 class="aieo-grv__heading">' . esc_html($heading) . '</h2>';
        }
        if ($overall) {
            $out .= self::aggregate_all_header();
        }
        $out .= self::reviews_block($reviews, $layout, true, $presentation, $autoplay);
        $out .= '</section>';
        return $out;
    }

    private static function render_cards_grid($min, $count_per_card) {
        $locations = AIEO_Google_Reviews_Locations::list_all(true);
        if (empty($locations)) {
            return self::empty_state(__('No enabled locations yet.', 'ai-eshop-optimizer'));
        }

        $out = '<section class="aieo-grv aieo-grv--cards"><div class="aieo-grv-cards">';
        foreach ($locations as $loc) {
            $reviews = AIEO_Google_Reviews_Helpers::fetch_reviews_for_location((int) $loc['id'], $count_per_card, $min);
            $rating = $loc['baseline_rating'] !== null ? (float) $loc['baseline_rating'] : 0.0;
            $count  = $loc['baseline_review_count'] !== null ? (int) $loc['baseline_review_count'] : 0;
            $maps   = AIEO_Google_Reviews_Helpers::maps_url($loc);
            $review = AIEO_Google_Reviews_Helpers::review_url($loc);

            $detail_url = function_exists('roosterx_store_post_url_for_location')
                ? roosterx_store_post_url_for_location($loc)
                : '';

            $out .= '<article class="aieo-grv-card">';
            $out .= '<header class="aieo-grv-card__header">';
            $out .= '<h3 class="aieo-grv-card__title">';
            if ($detail_url !== '') {
                $out .= '<a href="' . esc_url($detail_url) . '">' . esc_html($loc['label']) . '</a>';
            } else {
                $out .= esc_html($loc['label']);
            }
            $out .= '</h3>';
            if ($rating > 0) {
                $out .= '<div class="aieo-grv-card__rating">';
                $out .= AIEO_Google_Reviews_Helpers::star_html($rating);
                $out .= '<span class="aieo-grv-card__rating-text">' . esc_html(number_format_i18n($rating, 1)) . ' (' . esc_html($count) . ')</span>';
                $out .= '</div>';
            } else {
                $out .= '<p class="aieo-grv-card__pending"><em>' . esc_html__('No reviews yet — fetch on the Locations tab.', 'ai-eshop-optimizer') . '</em></p>';
            }
            $out .= '</header>';

            
            if (!empty($reviews)) {
                $out .= '<details class="aieo-grv-card__reviews">';
                $out .= '<summary>' . esc_html(sprintf(
                    
                    _n('Show %d most recent review', 'Show %d most recent reviews', count($reviews), 'ai-eshop-optimizer'),
                    count($reviews)
                )) . '</summary>';
                $out .= self::reviews_block($reviews, 'list', false);
                $out .= '</details>';
            }

            $out .= '<div class="aieo-grv-card__cta">';
            $out .= self::buttons_markup($maps, $review);
            $out .= '</div>';
            $out .= '</article>';
        }
        $out .= '</div></section>';
        return $out;
    }

    private static function overall_header(array $loc, $rate_us, $maps_btn = false, $show_rating = true) {
        $rating = $loc['baseline_rating'] !== null ? (float) $loc['baseline_rating'] : 0.0;
        $count  = $loc['baseline_review_count'] !== null ? (int) $loc['baseline_review_count'] : 0;
        $review = AIEO_Google_Reviews_Helpers::review_url($loc);
        $maps   = AIEO_Google_Reviews_Helpers::maps_url($loc);

        if (!$show_rating && !$rate_us && !$maps_btn) { return ''; }
        if ($show_rating && $rating <= 0 && $count <= 0 && $review === '' && !$maps_btn) { return ''; }

        $out = '<div class="aieo-grv__overall">';
        if ($show_rating && $rating > 0) {
            $out .= '<div class="aieo-grv__overall-rating">';
            $out .= '<span class="aieo-grv__overall-source">' . esc_html__('Google reviews', 'ai-eshop-optimizer') . '</span>';
            $out .= AIEO_Google_Reviews_Helpers::star_html($rating);
            $out .= '<span class="aieo-grv__overall-num">' . esc_html(number_format_i18n($rating, 1)) . '</span>';
            $out .= '<span class="aieo-grv__overall-count">' . esc_html(sprintf(
                
                _n('%d review', '%d reviews', $count, 'ai-eshop-optimizer'),
                $count
            )) . '</span>';
            $out .= '</div>';
        }
        if (($maps_btn && $maps !== '') || ($rate_us && $review !== '')) {
            $out .= self::buttons_markup($maps_btn ? $maps : '', $rate_us ? $review : '');
        }
        $out .= '</div>';
        return $out;
    }

    
    private static function buttons_markup($maps_url, $review_url) {
        if ($maps_url === '' && $review_url === '') { return ''; }
        $out = '<div class="wp-block-buttons aieo-grv-buttons" style="margin-top:8px;">';
        if ($maps_url !== '') {
            $out .= '<div class="wp-block-button is-style-outline has-custom-font-size has-sm-font-size">';
            $out .= '<a class="wp-block-button__link wp-element-button aieo-grv-btn aieo-grv-btn--maps" href="' . esc_url($maps_url) . '" target="_blank" rel="noopener noreferrer">' . esc_html__('Open in Google Maps', 'ai-eshop-optimizer') . '</a>';
            $out .= '</div>';
        }
        if ($review_url !== '') {
            $out .= '<div class="wp-block-button has-custom-font-size has-sm-font-size">';
            $out .= '<a class="wp-block-button__link wp-element-button aieo-grv-btn aieo-grv-btn--review" href="' . esc_url($review_url) . '" target="_blank" rel="noopener noreferrer">' . esc_html__('Αξιολογηστε μας!', 'ai-eshop-optimizer') . '</a>';
            $out .= '</div>';
        }
        $out .= '</div>';
        return $out;
    }

    private static function aggregate_all_header() {
        global $wpdb;
        $loc = $wpdb->prefix . 'aieo_google_locations';
        $row = $wpdb->get_row(
            "SELECT
                ROUND(SUM(baseline_rating * baseline_review_count) / NULLIF(SUM(baseline_review_count),0), 1) AS rating,
                SUM(baseline_review_count) AS total
             FROM {$loc} WHERE enabled = 1 AND baseline_rating IS NOT NULL",
            ARRAY_A
        );
        if (!is_array($row) || empty($row['rating'])) { return ''; }

        $out  = '<div class="aieo-grv__overall">';
        $out .= '<div class="aieo-grv__overall-rating">';
        $out .= AIEO_Google_Reviews_Helpers::star_html((float) $row['rating']);
        $out .= '<span class="aieo-grv__overall-num">' . esc_html(number_format_i18n((float) $row['rating'], 1)) . '</span>';
        $out .= '<span class="aieo-grv__overall-count">' . esc_html(sprintf(
            
            _n('%d review across all locations', '%d reviews across all locations', (int) $row['total'], 'ai-eshop-optimizer'),
            (int) $row['total']
        )) . '</span>';
        $out .= '</div></div>';
        return $out;
    }

    private static function reviews_block(array $reviews, $layout, $show_location_label, $presentation = 'static', $autoplay = 6) {
        if (empty($reviews)) {
            return '<p class="aieo-grv__empty"><em>' . esc_html__('No reviews to display yet.', 'ai-eshop-optimizer') . '</em></p>';
        }

        
        
        
        $presentation = in_array($presentation, array('static', 'slider', 'rotator'), true) ? $presentation : 'static';
        $autoplay     = max(2, min(60, (int) $autoplay));

        $list_class = 'aieo-grv-list aieo-grv-list--' . esc_attr($layout);
        if ($presentation === 'slider')  { $list_class .= ' aieo-grv-list--slider'; }
        if ($presentation === 'rotator') { $list_class .= ' aieo-grv-list--rotator'; }

        $out = '';
        if ($presentation === 'slider') {
            
            
            $out .= '<div class="aieo-grv-slider" data-aieo-grv-pres="slider">';
            $out .= '<ul class="' . $list_class . '" style="--aieo-grv-slider-dur:' . (count($reviews) * 5) . 's;">';
        } elseif ($presentation === 'rotator') {
            $out .= '<div class="aieo-grv-rotator" data-aieo-grv-pres="rotator" data-autoplay="' . esc_attr((string) ($autoplay * 1000)) . '">';
            $out .= '<ul class="' . $list_class . '">';
        } else {
            $out .= '<ul class="' . $list_class . '">';
        }

        
        $loops = $presentation === 'slider' ? 2 : 1;
        for ($i = 0; $i < $loops; $i++) {
            foreach ($reviews as $r) {
                $aria = $i > 0 ? ' aria-hidden="true"' : '';
                $out .= '<li class="aieo-grv-item"' . $aria . '>';
                $out .= '<div class="aieo-grv-item__author">';
                if (!empty($r['profile_photo_url'])) {
                    $out .= '<img src="' . esc_url($r['profile_photo_url']) . '" alt="" class="aieo-grv-item__avatar" loading="lazy" referrerpolicy="no-referrer">';
                }
                $out .= '<div class="aieo-grv-item__byline">';
                if (!empty($r['author_url'])) {
                    $out .= '<a href="' . esc_url($r['author_url']) . '" target="_blank" rel="noopener noreferrer" class="aieo-grv-item__name">' . esc_html($r['author_name']) . '</a>';
                } else {
                    $out .= '<span class="aieo-grv-item__name">' . esc_html($r['author_name']) . '</span>';
                }
                if ($show_location_label && !empty($r['location_label'])) {
                    $out .= '<span class="aieo-grv-item__loc"> · ' . esc_html($r['location_label']) . '</span>';
                }
                if (!empty($r['relative_time'])) {
                    $out .= '<span class="aieo-grv-item__time"> · ' . esc_html($r['relative_time']) . '</span>';
                }
                $out .= '</div></div>';
                $out .= '<div class="aieo-grv-item__rating">' . AIEO_Google_Reviews_Helpers::star_html((int) $r['rating']) . '</div>';
                if (!empty($r['review_text'])) {
                    $out .= '<p class="aieo-grv-item__text">' . esc_html($r['review_text']) . '</p>';
                }
                $out .= '</li>';
            }
        }
        $out .= '</ul>';
        if ($presentation === 'slider' || $presentation === 'rotator') {
            $out .= '</div>';
        }
        return $out;
    }

    private static function empty_state($message) {
        return '<p class="aieo-grv__empty"><em>' . esc_html($message) . '</em></p>';
    }

    
    public static function maybe_enqueue_css() {
        wp_register_style('aieo-google-reviews', false); 
        wp_enqueue_style('aieo-google-reviews');
        wp_add_inline_style('aieo-google-reviews', self::inline_css());

        
        
        add_action('wp_footer', array(__CLASS__, 'maybe_print_rotator_js'), 30);
    }

    public static function maybe_print_rotator_js() {
        
        
        static $printed = false;
        if ($printed) { return; }
        $printed = true;
        ?>
<script id="aieo-grv-rotator-js">
(function(){
    var rotators = document.querySelectorAll('[data-aieo-grv-pres="rotator"]');
    if (!rotators.length) return;
    rotators.forEach(function(box){
        var items = box.querySelectorAll('.aieo-grv-list--rotator > .aieo-grv-item');
        if (items.length < 2) { if (items[0]) items[0].classList.add('is-active'); return; }
        var i = 0, ms = parseInt(box.getAttribute('data-autoplay') || '6000', 10);
        items[0].classList.add('is-active');
        function tick(){
            var cur = items[i], next = items[(i + 1) % items.length];
            cur.classList.add('is-leaving');
            cur.classList.remove('is-active');
            next.classList.add('is-active');
            setTimeout(function(){ cur.classList.remove('is-leaving'); }, 600);
            i = (i + 1) % items.length;
        }
        var timer = setInterval(tick, ms);
        // Pause on hover/focus so readers can finish.
        box.addEventListener('mouseenter', function(){ clearInterval(timer); });
        box.addEventListener('mouseleave', function(){ timer = setInterval(tick, ms); });
    });
})();
</script>
        <?php
    }

    private static function inline_css() {
        return '
.aieo-grv{--aieo-grv-star:#f59e0b;--aieo-grv-star-empty:#d1d5db;font:inherit}
.aieo-grv-align.alignfull{margin-left:calc(50% - 50vw);margin-right:calc(50% - 50vw);max-width:100vw}
.aieo-grv__heading{margin:0 0 .5em;font-size:1.5rem;font-weight:700}
.aieo-grv__overall{display:flex;flex-wrap:wrap;align-items:center;gap:14px;padding:10px 12px;background:#f8fafc;border-left:3px solid #f59e0b;border-radius:4px;margin-bottom:14px}
/* Vertically centre the button row inside the rating ribbon — without
   these overrides the theme\'s default `wp-block-buttons` margin
   pushes the button slightly off the rating text baseline. */
.aieo-grv__overall>.wp-block-buttons{margin:0 !important;align-self:center}
.aieo-grv__overall>.wp-block-buttons>.wp-block-button{margin:0 !important;align-self:center}
.aieo-grv__overall>.wp-block-buttons>.wp-block-button>.wp-block-button__link{margin:0 !important}
.aieo-grv__overall>.aieo-grv__overall-rating{align-self:center}
.aieo-grv__overall-rating{display:flex;align-items:center;flex-wrap:wrap;gap:8px}
/* "Google reviews" caption — small, muted, separated from the rating
   numbers by a thin vertical rule so it reads as a source label. */
.aieo-grv__overall-source{font-size:.78rem;font-weight:600;text-transform:uppercase;letter-spacing:.06em;color:#6b7280;padding-right:10px;border-right:1px solid #d1d5db;margin-right:2px}
.aieo-grv__overall-num{font-weight:700;font-size:1.1rem}
.aieo-grv__overall-count{color:#475569;font-size:.95rem}
.aieo-grv-stars{display:inline-flex;gap:1px}
.aieo-grv-star{font-size:1rem;line-height:1;color:var(--aieo-grv-star-empty)}
.aieo-grv-star-full{color:var(--aieo-grv-star)}
.aieo-grv-star-half{position:relative;color:var(--aieo-grv-star-empty)}
.aieo-grv-star-half::before{content:"★";color:var(--aieo-grv-star);position:absolute;top:0;left:0;width:50%;overflow:hidden}
.aieo-grv-list{list-style:none;margin:0;padding:0}
.aieo-grv-list--grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:14px}
.aieo-grv-list--list>.aieo-grv-item{margin-bottom:12px}
/* Carousel layout, manual (Static presentation) = a real native horizontal
   scroller the visitor swipes/drags — distinct from the auto-marquee (slider)
   and the rotator. The recos "Slider style" pink progress bar attaches to this
   real scroller. Scoped so it never collides with slider/rotator. */
.aieo-grv-list--carousel:not(.aieo-grv-list--slider):not(.aieo-grv-list--rotator){display:flex;flex-wrap:nowrap;gap:14px;overflow-x:auto;scroll-snap-type:x mandatory;-webkit-overflow-scrolling:touch;padding-bottom:6px;scrollbar-width:none}
.aieo-grv-list--carousel:not(.aieo-grv-list--slider):not(.aieo-grv-list--rotator)::-webkit-scrollbar{display:none}
.aieo-grv-list--carousel:not(.aieo-grv-list--slider):not(.aieo-grv-list--rotator)>.aieo-grv-item{flex:0 0 300px;width:300px;scroll-snap-align:start;margin:0}
.aieo-grv-item{background:#fff;border:1px solid #e5e7eb;border-radius:6px;padding:12px 14px}
.aieo-grv-item__author{display:flex;align-items:center;gap:10px;margin-bottom:6px}
.aieo-grv-item__avatar{width:36px;height:36px;border-radius:50%;object-fit:cover}
.aieo-grv-item__byline{display:flex;flex-wrap:wrap;align-items:baseline;gap:2px;font-size:.92rem}
.aieo-grv-item__name{font-weight:600;color:#111}
.aieo-grv-item__loc,.aieo-grv-item__time{color:#64748b;font-size:.85rem}
.aieo-grv-item__rating{margin:2px 0 6px}
.aieo-grv-item__text{margin:0;color:#334155;font-size:.95rem;line-height:1.5;white-space:pre-line}
.aieo-grv-cards{display:grid;grid-template-columns:repeat(auto-fill,minmax(300px,1fr));gap:18px}
.aieo-grv-card{background:#fff;border:1px solid #e5e7eb;border-radius:8px;padding:16px;display:flex;flex-direction:column;gap:10px}
.aieo-grv-card__header{display:flex;flex-direction:column;gap:4px}
.aieo-grv-card__title{margin:0;font-size:1.15rem;font-weight:700}
.aieo-grv-card__rating{display:flex;align-items:center;gap:6px;font-size:.95rem}
.aieo-grv-card__rating-text{color:#475569}
.aieo-grv-card__pending{color:#92400e;font-size:.88rem;margin:0}
.aieo-grv-card__reviews>summary{cursor:pointer;color:#1d4ed8;font-size:.9rem;outline:none;padding:4px 0}
.aieo-grv-card__reviews[open]>summary{margin-bottom:8px}
.aieo-grv-card__cta{display:flex;flex-wrap:wrap;gap:8px;margin-top:auto}
.aieo-grv-buttons{display:flex;flex-wrap:wrap;gap:8px}
/* Override the theme\'s default-button style for the Maps button so the
   pair shows the secondary/primary contrast operators expect (matches
   the category buttons elsewhere on the site). Rate-us inherits the
   theme\'s default which is the accent-on-fill look. */
.aieo-grv-btn--review.wp-block-button__link,
.wp-block-button.has-style-review .wp-block-button__link{
    background-color:var(--wp--preset--color--accent,#F46767) !important;
    color:#fff !important;
}
.aieo-grv-btn--review.wp-block-button__link:hover{
    background-color:var(--wp--preset--color--accent-2,#1a1a1a) !important;
    color:#fff !important;
}
.aieo-grv-btn--maps.wp-block-button__link{
    background-color:transparent !important;
    color:var(--wp--preset--color--accent,#F46767) !important;
    border:2px solid var(--wp--preset--color--accent,#F46767) !important;
    padding-top:calc(var(--wp--preset--spacing--3) - 2px);
    padding-bottom:calc(var(--wp--preset--spacing--3) - 2px);
}
.aieo-grv-btn--maps.wp-block-button__link:hover{
    background-color:var(--wp--preset--color--accent,#F46767) !important;
    color:#fff !important;
}
.aieo-grv__empty{color:#64748b;font-style:italic}

/* ── Presentation: SLIDER (CSS-only RTL marquee) ── */
.aieo-grv-slider{overflow:hidden;position:relative;mask-image:linear-gradient(to right,transparent,#000 5%,#000 95%,transparent);}
.aieo-grv-list--slider{display:flex !important;flex-wrap:nowrap !important;gap:14px;padding:0;margin:0;list-style:none;width:max-content;animation:aieo-grv-marquee var(--aieo-grv-slider-dur,30s) linear infinite}
.aieo-grv-slider:hover .aieo-grv-list--slider{animation-play-state:paused}
.aieo-grv-list--slider>.aieo-grv-item{flex:0 0 320px;margin:0;width:320px}
@keyframes aieo-grv-marquee{from{transform:translateX(0)}to{transform:translateX(-50%)}}
@media (prefers-reduced-motion: reduce){.aieo-grv-list--slider{animation-duration:0s !important;animation-play-state:paused}}

/* ── Presentation: ROTATOR (single card, fades up bottom→top) ── */
.aieo-grv-rotator{position:relative;min-height:160px}
.aieo-grv-list--rotator{position:relative;list-style:none;padding:0;margin:0;display:block}
.aieo-grv-list--rotator>.aieo-grv-item{position:absolute;inset:0;opacity:0;transform:translateY(20px);transition:opacity .55s ease,transform .55s ease;pointer-events:none}
.aieo-grv-list--rotator>.aieo-grv-item.is-active{opacity:1;transform:translateY(0);pointer-events:auto;position:relative}
.aieo-grv-list--rotator>.aieo-grv-item.is-leaving{opacity:0;transform:translateY(-20px)}
';
    }
}
