<?php
if (!defined('ABSPATH')) exit;

add_action('admin_menu', function(){
    add_menu_page(
        'Office Hours',
        'Office Hours',
        'read', // any logged-in user
        'ioh-office-hours',
        'ioh_render_admin_page',
        'dashicons-clock',
        59
    );
});

add_action('admin_enqueue_scripts', function($hook){
    if ($hook !== 'toplevel_page_ioh-office-hours') return;
    wp_enqueue_style('ioh-admin', IOH_URL . 'assets/admin.css', [], IOH_VERSION);
    wp_add_inline_style('ioh-admin', '
      .ioh-wrap .ioh-popup-control-row{display:grid!important;gap:12px!important;align-items:end!important;margin:8px 0!important;}
      .ioh-wrap .ioh-popup-schedule-row{grid-template-columns:repeat(2,minmax(220px,350px))!important;}
      .ioh-wrap .ioh-popup-style-row{grid-template-columns:minmax(220px,350px) minmax(190px,230px) minmax(210px,250px)!important;max-width:860px!important;}
      .ioh-wrap .ioh-popup-control-row>.ioh-popup-field,.ioh-wrap .ioh-popup-control-row>label{display:block!important;margin:0!important;min-width:0!important;}
      .ioh-wrap .ioh-popup-control-row>.ioh-popup-field>label{display:block!important;margin:0 0 4px!important;font-weight:400!important;}
      .ioh-wrap .ioh-popup-control-row>label>br{display:none!important;}
      .ioh-wrap .ioh-popup-control-row input[type="text"],.ioh-wrap .ioh-popup-control-row input[type="datetime-local"]{display:block!important;width:100%!important;max-width:100%!important;margin:4px 0 0!important;}
      .ioh-wrap .ioh-popup-color-controls{display:flex!important;gap:8px!important;align-items:center!important;margin:4px 0 0!important;}
      .ioh-wrap .ioh-popup-color-controls input[type="color"],.ioh-wrap .ioh-popup-style-row>label input[type="color"]{width:50px!important;min-height:34px!important;margin:4px 8px 0 0!important;vertical-align:top!important;}
      .ioh-wrap .ioh-popup-color-controls input[type="text"],.ioh-wrap .ioh-popup-style-row>label:nth-child(n+2) input[type="text"]{width:100px!important;text-transform:uppercase!important;display:inline-block!important;}
      @media (max-width:782px){.ioh-wrap .ioh-popup-schedule-row,.ioh-wrap .ioh-popup-style-row{grid-template-columns:1fr!important;max-width:none!important;}}
    ');
    wp_enqueue_media();
});

function ioh_admin_scan_transient_key(): string {
    return 'ioh_admin_scan_' . get_current_user_id();
}

function ioh_admin_scan_get_results(): array {
    $results = get_transient(ioh_admin_scan_transient_key());
    return is_array($results) ? $results : [];
}

function ioh_admin_scan_store_results(array $results): void {
    set_transient(ioh_admin_scan_transient_key(), ioh_scan_dedupe_results($results), 20 * MINUTE_IN_SECONDS);
}

function ioh_admin_scan_append_results(array $results): array {
    $stored = ioh_admin_scan_get_results();
    foreach ($results as $result) {
        if (is_array($result)) $stored[] = $result;
    }
    $stored = ioh_scan_dedupe_results($stored);
    ioh_admin_scan_store_results($stored);
    return $stored;
}

add_action('wp_ajax_ioh_scan_office_hours_batch', function() {
    if (!current_user_can('manage_options')) {
        wp_send_json_error(['message' => 'Only administrators can scan for office hours.'], 403);
    }
    if (!check_ajax_referer('ioh_scan_office_hours', 'nonce', false)) {
        wp_send_json_error(['message' => 'The office-hours scan session expired. Refresh the admin page and try again.'], 403);
    }

    try {
        ioh_prepare_long_office_hours_scan();

        $stage = sanitize_key(wp_unslash($_POST['stage'] ?? 'init'));
        $offset = absint($_POST['offset'] ?? 0);
        $batch = 12;
        $next_stage = $stage;
        $next_offset = 0;
        $done = false;
        $message = 'Scanning...';

        if ($stage === 'init') {
            delete_transient(ioh_admin_scan_transient_key());
            $next_stage = 'posts';
            $message = 'Preparing to scan saved content...';
        } elseif ($stage === 'posts') {
            $batch_result = ioh_find_replaceable_office_hours_posts_batch($offset, $batch);
            $results = ioh_admin_scan_append_results($batch_result['results'] ?? []);
            $next_offset = (int)($batch_result['next_offset'] ?? ($offset + $batch));
            $total = (int)($batch_result['total'] ?? 0);
            if ($next_offset >= $total) {
                $next_stage = 'layout_db';
                $next_offset = 0;
            }
            $message = sprintf('Scanning saved content... %d of %d checked.', min($next_offset, $total), $total);
        } elseif ($stage === 'layout_db') {
            $results = ioh_admin_scan_append_results(ioh_find_weekday_matches_in_layout_database(ioh_admin_scan_get_results()));
            $next_stage = 'page_db';
            $message = 'Scanning layout data...';
        } elseif ($stage === 'page_db') {
            $results = ioh_admin_scan_append_results(ioh_find_weekday_matches_in_page_post_database(ioh_admin_scan_get_results(), false));
            $next_stage = 'widgets';
            $message = 'Scanning page/post data...';
        } elseif ($stage === 'widgets') {
            $results = ioh_admin_scan_append_results(ioh_find_replaceable_office_hours_widgets());
            $next_stage = 'rendered_globals';
            $message = 'Scanning widgets and site options...';
        } elseif ($stage === 'rendered_globals') {
            $results = ioh_admin_scan_append_results(ioh_find_rendered_global_office_hours_areas(ioh_admin_scan_get_results()));
            $next_stage = 'done';
            $done = true;
            $message = count($results) > 0
                ? sprintf('Found %d area%s that may contain replaceable office hours.', count($results), count($results) === 1 ? '' : 's')
                : 'No replaceable office hours areas were found.';
        } else {
            $results = ioh_admin_scan_get_results();
            $next_stage = 'done';
            $done = true;
            $message = 'Scan complete.';
        }

        wp_send_json_success([
            'stage' => $next_stage,
            'offset' => $next_offset,
            'done' => $done,
            'message' => $message,
            'results' => array_values(ioh_admin_scan_get_results()),
        ]);
    } catch (Throwable $e) {
        wp_send_json_error(['message' => 'The office-hours scan failed: ' . $e->getMessage()], 500);
    }
});

add_action('wp_ajax_ioh_replace_office_hours_area', function() {
    if (!current_user_can('manage_options')) {
        wp_send_json_error(['message' => 'Only administrators can replace office hours.'], 403);
    }
    if (!check_ajax_referer('ioh_save', 'ioh_nonce', false)) {
        wp_send_json_error(['message' => 'The office-hours replacement session expired. Refresh the admin page and try again.'], 403);
    }

    $settings = ioh_get_settings();
    $replace_post_id = absint($_POST['ioh_replace_post_id'] ?? 0);
    $replace_area_key = sanitize_text_field(wp_unslash($_POST['ioh_replace_area_key'] ?? ''));
    $replace_area_label = sanitize_text_field(wp_unslash($_POST['ioh_replace_area_label'] ?? ''));
    [$replacement_shortcode, $shortcode_error] = ioh_admin_build_replacement_shortcode($settings);
    if ($shortcode_error !== '') {
        wp_send_json_error(['message' => $shortcode_error], 400);
    }

    [$replaced, $replace_message] = ioh_replace_office_hours_area_with_shortcode($replace_post_id, $replacement_shortcode, $replace_area_key, $replace_area_label);
    if (!$replaced) {
        wp_send_json_error(['message' => $replace_message], 400);
    }

    wp_send_json_success([
        'message' => $replace_message,
        'post_id' => $replace_post_id,
        'shortcode' => $replacement_shortcode,
    ]);
});

function ioh_admin_build_replacement_shortcode(array $settings): array {
    $locations = isset($settings['locations']) && is_array($settings['locations']) ? $settings['locations'] : [];
    $loc = sanitize_title(wp_unslash($_POST['ioh_replace_location'] ?? ($settings['default_location'] ?? 'main')));
    if (!isset($locations[$loc])) return ['', 'Choose a valid office-hours location.'];

    $format = sanitize_text_field(wp_unslash($_POST['ioh_replace_format'] ?? 'standard'));
    $format = in_array($format, ['standard', 'sidebar', 'compact'], true) ? $format : 'standard';

    $color_mode = sanitize_text_field(wp_unslash($_POST['ioh_replace_color_mode'] ?? 'black'));
    $color = $color_mode;
    if ($color_mode === 'custom') {
        $color = sanitize_text_field(wp_unslash($_POST['ioh_replace_custom_color'] ?? '#424242'));
    }
    if (!in_array($color, ['black', 'white'], true) && !preg_match('/^#[0-9a-fA-F]{3}([0-9a-fA-F]{3})?$/', $color)) {
        $color = 'black';
    }

    $size = sanitize_text_field(wp_unslash($_POST['ioh_replace_size'] ?? ($format === 'sidebar' ? '15px' : '16px')));
    if (!preg_match('/^\d{1,3}(?:\.\d{1,2})?(px|rem|em)$/i', $size)) $size = $format === 'sidebar' ? '15px' : '16px';

    $top_padding = sanitize_text_field(wp_unslash($_POST['ioh_replace_top_padding'] ?? '0px'));
    if (!preg_match('/^-?\d{1,3}(?:\.\d{1,2})?(px|rem|em)$/i', $top_padding)) $top_padding = '0px';

    $bottom_padding = sanitize_text_field(wp_unslash($_POST['ioh_replace_bottom_padding'] ?? '0px'));
    if (!preg_match('/^-?\d{1,3}(?:\.\d{1,2})?(px|rem|em)$/i', $bottom_padding)) $bottom_padding = '0px';

    $attrs = [
        'location="' . esc_attr($loc) . '"',
        'color="' . esc_attr($color) . '"',
        'size="' . esc_attr($size) . '"',
    ];
    if ($top_padding !== '0px') $attrs[] = 'top_padding="' . esc_attr($top_padding) . '"';
    if ($bottom_padding !== '0px') $attrs[] = 'bottom_padding="' . esc_attr($bottom_padding) . '"';

    if ($format === 'sidebar') {
        $title_color = sanitize_text_field(wp_unslash($_POST['ioh_replace_title_color'] ?? '#578ea7'));
        if (!preg_match('/^#[0-9a-fA-F]{3}([0-9a-fA-F]{3})?$/', $title_color)) $title_color = '#578ea7';

        $title_size = sanitize_text_field(wp_unslash($_POST['ioh_replace_title_size'] ?? '20px'));
        if (!preg_match('/^\d{1,3}(?:\.\d{1,2})?(px|rem|em)$/i', $title_size)) $title_size = '20px';

        $attrs[] = 'title_color="' . esc_attr($title_color) . '"';
        $attrs[] = 'title_size="' . esc_attr($title_size) . '"';
        return ['[ioh_office_hours_sidebar ' . implode(' ', $attrs) . ']', ''];
    }

    if ($format === 'compact') {
        return ['[ioh_office_hours_compact ' . implode(' ', $attrs) . ']', ''];
    }

    return ['[ioh_office_hours ' . implode(' ', $attrs) . ']', ''];
}

function ioh_render_admin_page(){
    if (!current_user_can('read')) wp_die('Not allowed.');

    $settings = ioh_get_settings();
    $current_slug = isset($_GET['loc']) ? sanitize_title(wp_unslash($_GET['loc'])) : ($settings['default_location'] ?? 'main');
    if (!isset($settings['locations'][$current_slug])) $current_slug = $settings['default_location'] ?? 'main';

    $notice = '';
    $generated_api_key = '';
    $sync_h_card_location = '';
    $office_hours_scan_results = null;

    // Handle POST
    if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['ioh_nonce']) && wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['ioh_nonce'])), 'ioh_save')) {
        $action = isset($_POST['ioh_action']) ? sanitize_text_field(wp_unslash($_POST['ioh_action'])) : 'save';

        $raw = get_option(IOH_OPT, []);
        if (!is_array($raw)) $raw = [];

        // IMPORTANT: do not re-inject default 'main' after deletion.
        // Merge defaults EXCEPT locations, then set locations from saved option.
        $defaults = ioh_default_settings();
        $defaults_no_locations = $defaults;
        unset($defaults_no_locations['locations']);

        $new = array_replace_recursive($defaults_no_locations, $raw);

        // Locations: use saved locations as-is; fall back to defaults only if none exist.
        if (isset($raw['locations']) && is_array($raw['locations']) && !empty($raw['locations'])) {
            $new['locations'] = $raw['locations'];
        } else {
            $new['locations'] = $defaults['locations'];
        }
// Locations add/delete/default + updates
        if ($action === 'generate_api_key') {
            if (!current_user_can('manage_options')) {
                $notice = 'Only administrators can generate the remote API key.';
            } else {
                $generated_api_key = ioh_generate_api_key();
                $new = ioh_reset_popup_banner_colors($new);
                $notice = 'Remote API key generated.';
            }
        } elseif ($action === 'revoke_api_key') {
            if (!current_user_can('manage_options')) {
                $notice = 'Only administrators can revoke the remote API key.';
            } else {
                ioh_revoke_api_key();
                $notice = 'Remote API key revoked.';
            }
        } elseif ($action === 'save_remote_sections') {
            if (!current_user_can('manage_options')) {
                $notice = 'Only administrators can manage remote editor sections.';
            } else {
                $new['remote_editor']['show_popup'] = !empty($_POST['ioh_remote_show_popup']) ? 1 : 0;
                $new['remote_editor']['show_hours'] = !empty($_POST['ioh_remote_show_hours']) ? 1 : 0;
                $new['remote_editor']['show_blog'] = !empty($_POST['ioh_remote_show_blog']) ? 1 : 0;
                if (
                    empty($new['remote_editor']['show_popup']) &&
                    empty($new['remote_editor']['show_hours']) &&
                    empty($new['remote_editor']['show_blog'])
                ) {
                    $new['remote_editor'] = $defaults['remote_editor'];
                    $notice = 'At least one remote editor section must stay visible. All sections were re-enabled.';
                } else {
                    $notice = 'Remote editor sections saved.';
                }
            }
        } elseif ($action === 'import_h_card_hours') {
            if (!current_user_can('manage_options')) {
                $notice = 'Only administrators can import H-Card office hours.';
            } else {
                [$new, $created_h_cards, $updated_h_cards, $found_h_cards, $removed_main] = ioh_import_h_card_office_hours($new);
                $total_h_cards = (int)$created_h_cards + (int)$updated_h_cards;
                if ($total_h_cards > 0) {
                    $notice = sprintf(
                        'Imported office hours from %d H-Card layout%s. Created %d location%s and updated %d existing location%s.%s',
                        $total_h_cards,
                        $total_h_cards === 1 ? '' : 's',
                        (int)$created_h_cards,
                        (int)$created_h_cards === 1 ? '' : 's',
                        (int)$updated_h_cards,
                        (int)$updated_h_cards === 1 ? '' : 's',
                        !empty($removed_main) ? ' Removed the default Main location.' : ''
                    );
                    $current_slug = $new['default_location'] ?? array_key_first($new['locations']);
                } else {
                    $notice = (int)$found_h_cards > 0
                        ? sprintf('Found %d H-Card layout%s, but no readable openingHours values were found.', (int)$found_h_cards, (int)$found_h_cards === 1 ? '' : 's')
                        : 'No H-Card layouts were found.';
                }
            }
        } elseif ($action === 'scan_office_hours_areas') {
            if (!current_user_can('manage_options')) {
                $notice = 'Only administrators can scan for office hours.';
            } else {
                $office_hours_scan_results = ioh_find_replaceable_office_hours_areas();
                $count = count($office_hours_scan_results);
                $notice = $count > 0
                    ? sprintf('Found %d area%s that may contain replaceable office hours.', $count, $count === 1 ? '' : 's')
                    : 'No replaceable office hours areas were found.';
            }
        } elseif ($action === 'replace_office_hours_area') {
            if (!current_user_can('manage_options')) {
                $notice = 'Only administrators can replace office hours.';
            } else {
                $replace_post_id = absint($_POST['ioh_replace_post_id'] ?? 0);
                $replace_area_key = sanitize_text_field(wp_unslash($_POST['ioh_replace_area_key'] ?? ''));
                $replace_area_label = sanitize_text_field(wp_unslash($_POST['ioh_replace_area_label'] ?? ''));
                [$replacement_shortcode, $shortcode_error] = ioh_admin_build_replacement_shortcode($new);
                if ($shortcode_error !== '') {
                    $notice = $shortcode_error;
                } else {
                    [$replaced, $replace_message] = ioh_replace_office_hours_area_with_shortcode($replace_post_id, $replacement_shortcode, $replace_area_key, $replace_area_label);
                    $notice = $replace_message;
                }
            }
        } elseif ($action === 'add_location') {
            $name = sanitize_text_field(wp_unslash($_POST['ioh_new_location_name'] ?? ''));
            if ($name !== '') {
                $slug = sanitize_title($name);
                if ($slug === '') $slug = 'location';
                $base = $slug; $i=2;
                while (isset($new['locations'][$slug])) { $slug = $base . '-' . $i; $i++; }
                $new['locations'][$slug] = [
                    'name' => $name,
                    'office_hours_title' => '',
                    'hours' => ioh_default_hours(),
                    'popup' => ['scope'=>'off','page_ids'=>[],'schedule_start'=>'','schedule_end'=>'','title'=>'ATTENTION','banner_color'=>ioh_default_popup_banner_color(),'banner_text_color'=>'#ffffff','text_size'=>'26px','html'=>''],
                ];
                $notice = 'Location added.';
                $current_slug = $slug;
            }
        } elseif ($action === 'delete_location') {
            $del = sanitize_title(wp_unslash($_POST['ioh_delete_slug'] ?? ''));
            if ($del && isset($new['locations'][$del])) {
                // prevent deleting last location
                if (count($new['locations']) <= 1) {
                    $notice = 'You cannot delete the only remaining location.';
                } else {
                    unset($new['locations'][$del]);
                    if (($new['default_location'] ?? 'main') === $del) {
                        $new['default_location'] = isset($new['locations']['main']) ? 'main' : array_key_first($new['locations']);
                    }
                    $notice = 'Location deleted.';
                    $current_slug = $new['default_location'];
                }
            }
        } else {
            // Save main settings
            $new['default_location'] = sanitize_title(wp_unslash($_POST['ioh_default_location'] ?? ($new['default_location'] ?? 'main')));

            // Display options
            if (array_key_exists('ioh_display_style', $_POST)) {
                $new['display']['style'] = in_array($_POST['ioh_display_style'] ?? 'list', ['list','stacked','table'], true) ? sanitize_text_field(wp_unslash($_POST['ioh_display_style'])) : 'list';
            }
            if (array_key_exists('ioh_display_template_html', $_POST)) {
                $new['display']['show_title'] = !empty($_POST['ioh_display_show_title']) ? 1 : 0;
                $new['display']['show_separators'] = !empty($_POST['ioh_display_show_separators']) ? 1 : 0;
                $new['display']['bold_days'] = !empty($_POST['ioh_display_bold_days']) ? 1 : 0;
                $new['display']['combine_closed_weekend'] = !empty($_POST['ioh_display_combine_closed_weekend']) ? 1 : 0;
                $new['display']['capitalize_day_names'] = !empty($_POST['ioh_display_capitalize_day_names']) ? 1 : 0;
                $new['display']['capitalize_hours'] = !empty($_POST['ioh_display_capitalize_hours']) ? 1 : 0;
                $new['display']['day_label_case'] = !empty($_POST['ioh_display_capitalize_day_names']) ? 'uppercase' : 'title';

                $tpl = (string)wp_unslash($_POST['ioh_display_template_html'] ?? '');
                $tpl = ioh_strip_wrappers($tpl);
                $tpl = wp_kses($tpl, ioh_allowed_editor_html());
                if (strpos($tpl, '{{OFFICE_HOURS}}') === false) {
                    $notice = 'Template must include {{OFFICE_HOURS}}. Your changes were saved but the placeholder was appended.';
                    $tpl .= '{{OFFICE_HOURS}}';
                }
                $new['display']['template_html'] = $tpl;
            }

            // Per-location form
            $loc = sanitize_title(wp_unslash($_POST['ioh_location'] ?? ''));
            if ($loc && isset($new['locations'][$loc])) {
                $has_popup_fields = array_key_exists('ioh_popup_scope', $_POST) || array_key_exists('ioh_popup_html', $_POST);
                $has_hours_fields = array_key_exists('ioh_hours', $_POST) && is_array($_POST['ioh_hours']) && !$has_popup_fields;
                if ($has_hours_fields) $sync_h_card_location = $loc;
                                // Per-location title
                if (array_key_exists('ioh_office_hours_title', $_POST)) {
                    $new['locations'][$loc]['office_hours_title'] = sanitize_text_field(wp_unslash($_POST['ioh_office_hours_title'] ?? ''));
                }

// Hours
                $incoming = $_POST['ioh_hours'] ?? [];
                if ($has_hours_fields && is_array($incoming)) {
                    foreach (ioh_days() as $day_key => $day_label) {
                        $d = $incoming[$day_key] ?? [];
                        if (!is_array($d)) $d = [];

                        $day = $new['locations'][$loc]['hours'][$day_key] ?? [];
                        $day['closed'] = !empty($d['closed']) ? 1 : 0;
                        $day['r1_start'] = sanitize_text_field($d['r1_start'] ?? '');
                        $day['r1_end'] = sanitize_text_field($d['r1_end'] ?? '');
                        $day['r2_start'] = sanitize_text_field($d['r2_start'] ?? '');
                        $day['r2_end'] = sanitize_text_field($d['r2_end'] ?? '');
                        $day['message'] = sanitize_text_field($d['message'] ?? '');
                        if ($day['message'] !== '') $day['closed'] = 0;
                        if (!empty($day['closed'])) $day['message'] = '';

                        [$ok, $msg] = ioh_validate_hours_day($day);
                        if (!$ok) {
                            $notice = 'Hours not saved: ' . $day_label . ' - ' . $msg;
                            // Keep old day values
                            continue;
                        }
                        $new['locations'][$loc]['hours'][$day_key] = $day;
                    }
                }

                // Popup
                if ($has_popup_fields) {
                    $scope = sanitize_text_field(wp_unslash($_POST['ioh_popup_scope'] ?? 'off'));
                    $scope = in_array($scope, ['off', 'homepage', 'sitewide', 'selected_pages'], true) ? $scope : 'off';
                    $page_ids = isset($_POST['ioh_popup_page_ids']) && is_array($_POST['ioh_popup_page_ids'])
                        ? array_values(array_filter(array_map('absint', wp_unslash($_POST['ioh_popup_page_ids']))))
                        : [];
                    $html = (string)wp_unslash($_POST['ioh_popup_html'] ?? '');
                    $html = wp_kses(ioh_strip_wrappers($html), ioh_allowed_editor_html());
                    $schedule_start = ioh_sanitize_datetime_local(wp_unslash($_POST['ioh_popup_schedule_start'] ?? ($new['locations'][$loc]['popup']['schedule_start'] ?? '')));
                    $schedule_end = ioh_sanitize_datetime_local(wp_unslash($_POST['ioh_popup_schedule_end'] ?? ($new['locations'][$loc]['popup']['schedule_end'] ?? '')));
                    $popup_title = sanitize_text_field(wp_unslash($_POST['ioh_popup_title'] ?? ($new['locations'][$loc]['popup']['title'] ?? 'ATTENTION')));
                    $banner_color_input = wp_unslash($_POST['ioh_popup_banner_color_hex'] ?? ($_POST['ioh_popup_banner_color'] ?? ($new['locations'][$loc]['popup']['banner_color'] ?? ioh_default_popup_banner_color())));
                    $banner_text_color_input = wp_unslash($_POST['ioh_popup_banner_text_color_hex'] ?? ($_POST['ioh_popup_banner_text_color'] ?? ($new['locations'][$loc]['popup']['banner_text_color'] ?? '#ffffff')));
                    $banner_color = ioh_sanitize_color_value($banner_color_input, ioh_default_popup_banner_color());
                    $banner_text_color = ioh_sanitize_color_value($banner_text_color_input, '#ffffff');

                    $new['locations'][$loc]['popup'] = [
                        'scope' => $scope,
                        'page_ids' => $page_ids,
                        'schedule_start' => $schedule_start,
                        'schedule_end' => $schedule_end,
                        'title' => $popup_title,
                        'banner_color' => $banner_color,
                        'banner_text_color' => $banner_text_color,
                        'text_size' => '26px',
                        'html' => $html,
                    ];
                }

                if ($notice === '') $notice = 'Saved.';
            }
        }

        update_option(IOH_OPT, $new, false);
        if ($sync_h_card_location !== '') ioh_sync_h_card_opening_hours($new, $sync_h_card_location);
        $settings = ioh_get_settings();
    }

    $locs = $settings['locations'];
    $current = $locs[$current_slug] ?? reset($locs);
    $site_domain = wp_parse_url(home_url('/'), PHP_URL_HOST) ?: home_url('/');

    ?>
    <div class="wrap ioh-wrap">
      <div class="ioh-admin-banner">
        <strong>Managing settings for <a href="<?php echo esc_url(home_url('/')); ?>" target="_blank" rel="noopener"><?php echo esc_html($site_domain); ?></a></strong>
      </div>

      <nav class="ioh-admin-tabs" aria-label="Office Hours admin sections">
        <a class="is-active" href="#ioh-admin-locations">Locations</a>
        <a href="#ioh-admin-hours">Office Hours</a>
        <a href="#ioh-admin-popup">Popup</a>
        <?php // Display section hidden from Admin view; settings are preserved below. ?>
        <?php if (false): ?><a href="#ioh-admin-display">Display</a><?php endif; ?>
        <?php // Remote API section hidden from Admin view; keep code below for future use. ?>
        <?php if (false): ?><a href="#ioh-admin-api">Remote API</a><?php endif; ?>
      </nav>

      <?php if ($notice): ?>
        <div class="notice notice-info is-dismissible"><p><?php echo esc_html($notice); ?></p></div>
      <?php endif; ?>

      <div class="ioh-grid">
        <div id="ioh-admin-locations" class="ioh-card">
          <div class="ioh-card-head">
            <h2>Locations</h2>
            <p>Add, remove, and choose the default location for this site.</p>
          </div>
          <form method="post">
            <?php wp_nonce_field('ioh_save','ioh_nonce'); ?>
            <input type="hidden" name="ioh_action" value="add_location" />
            <div class="ioh-row">
              <input type="text" name="ioh_new_location_name" placeholder="Add location name..." class="regular-text" />
              <button class="button button-primary" type="submit">Add</button>
            </div>
          </form>

          <?php if (current_user_can('manage_options')): ?>
            <form method="post" style="margin-top:14px;">
              <?php wp_nonce_field('ioh_save','ioh_nonce'); ?>
              <input type="hidden" name="ioh_action" value="import_h_card_hours" />
              <button class="button" type="submit">Import Hours from H-Cards</button>
              <p class="description">Finds Themer layouts named like City H-Card and imports their schema opening hours.</p>
            </form>

            <div class="ioh-scan-controls" style="margin-top:14px;">
              <button class="button" type="button" id="ioh_scan_office_hours_btn" data-nonce="<?php echo esc_attr(wp_create_nonce('ioh_scan_office_hours')); ?>">Find Office Hours on Site</button>
              <span class="ioh-scan-status" id="ioh_scan_status" aria-live="polite"></span>
              <p class="description">Lists pages, templates, sidebars, and footers that may be replaceable with office-hours shortcodes.</p>
            </div>
          <?php endif; ?>

          <form method="post" style="margin-top:14px;">
            <?php wp_nonce_field('ioh_save','ioh_nonce'); ?>
            <input type="hidden" name="ioh_action" value="save" />
            <label class="ioh-label">Default location</label>
            <select name="ioh_default_location" class="regular-text">
              <?php foreach ($locs as $slug => $loc): ?>
                <option value="<?php echo esc_attr($slug); ?>" <?php selected($settings['default_location'], $slug); ?>>
                  <?php echo esc_html($loc['name']); ?> (<?php echo esc_html($slug); ?>)
                </option>
              <?php endforeach; ?>
            </select>
            <p class="description">Used for the site popup and as a fallback when a shortcode location is missing.</p>
            <button class="button" type="submit" style="margin-top:10px;">Save Default</button>
          </form>

          <div class="ioh-loc-list">
            <?php foreach ($locs as $slug => $loc): ?>
              <div class="ioh-loc-item <?php echo $slug === $current_slug ? 'is-active' : ''; ?>">
                <a href="<?php echo esc_url(admin_url('admin.php?page=ioh-office-hours&loc=' . $slug)); ?>">
                  <strong><?php echo esc_html($loc['name']); ?></strong>
                  <span class="ioh-muted"><?php echo esc_html($slug); ?></span>
                </a>
                <form method="post" class="ioh-inline">
                  <?php wp_nonce_field('ioh_save','ioh_nonce'); ?>
                  <input type="hidden" name="ioh_action" value="delete_location" />
                  <input type="hidden" name="ioh_delete_slug" value="<?php echo esc_attr($slug); ?>" />
                  <button type="submit" class="button button-link-delete" onclick="return confirm('Delete location <?php echo esc_js($loc['name']); ?>?');">Delete</button>
                </form>
              </div>
            <?php endforeach; ?>
          </div>
        </div>

        <div class="ioh-main-column">
        <?php if (current_user_can('manage_options')): ?>
          <div class="ioh-card" id="ioh_scan_results_card" <?php echo is_array($office_hours_scan_results) ? '' : 'style="display:none;"'; ?>>
            <div class="ioh-card-head">
              <h2>Office Hours Found on Site</h2>
              <p>Review each match and use the page links to update office hours manually. Sidebar and footer matches are listed as their own areas, not as every page that displays them.</p>
            </div>
            <div class="ioh-scan-loading" id="ioh_scan_loading" style="display:none;" aria-live="polite">
              <img src="<?php echo esc_url(IOH_URL . 'assets/working-on-it.gif'); ?>" alt="Working on it" />
            </div>
            <p id="ioh_scan_empty_message" <?php echo empty($office_hours_scan_results) ? '' : 'style="display:none;"'; ?>>No likely replaceable office-hours areas were found.</p>
            <div class="ioh-scan-table-wrap" id="ioh_scan_table_wrap" <?php echo empty($office_hours_scan_results) ? 'style="display:none;"' : ''; ?>>
              <table class="widefat striped ioh-scan-table" style="table-layout:fixed;width:100%;">
                <colgroup>
                  <col class="ioh-scan-col-area" style="width:14%;" />
                  <col class="ioh-scan-col-type" style="width:12%;" />
                  <col class="ioh-scan-col-style" style="width:10%;" />
                  <col class="ioh-scan-col-links" style="width:120px;" />
                  <col class="ioh-scan-col-text" style="width:auto;" />
                </colgroup>
                <thead>
                  <tr>
                    <th>Area</th>
                    <th>Type</th>
                    <th>Detected Style</th>
                    <th>Page Links</th>
                    <th>Matched Text</th>
                  </tr>
                </thead>
                <tbody id="ioh_scan_results_body">
                  <?php foreach ((array)$office_hours_scan_results as $result): ?>
                    <?php if (
                      ioh_result_is_global_header_or_footer($result) &&
                      empty($result['has_actual_office_hour_times']) &&
                      !ioh_text_contains_actual_office_hour_times((string)($result['excerpt'] ?? ''))
                    ) continue; ?>
                    <?php if (ioh_source_is_slide_box_office_hours_label_metadata((string)($result['excerpt'] ?? ''))) continue; ?>
                    <tr data-post-id="<?php echo esc_attr((int)($result['id'] ?? 0)); ?>">
                      <td><?php echo esc_html($result['title']); ?></td>
                      <td><?php echo esc_html($result['type']); ?></td>
                      <td><?php echo esc_html($result['detected_style'] ?? 'Standard'); ?></td>
                      <td>
                        <?php if (!empty($result['view_url'])): ?>
                          <div class="ioh-scan-link-actions">
                            <a class="button" style="box-sizing:border-box;display:flex;align-items:center;justify-content:center;width:100%;height:34px;min-height:34px;padding:0 10px;line-height:1.15;text-align:center;white-space:normal;" href="<?php echo esc_url($result['view_url']); ?>" target="_blank" rel="noopener">View</a>
                            <a class="button" style="box-sizing:border-box;display:flex;align-items:center;justify-content:center;width:100%;height:34px;min-height:34px;padding:0 10px;line-height:1.15;text-align:center;white-space:normal;" href="<?php echo esc_url($result['builder_url'] ?? ''); ?>" target="_blank" rel="noopener">Beaver Builder</a>
                            <?php if (!empty($result['edit_url'])): ?>
                              <a class="button" style="box-sizing:border-box;display:flex;align-items:center;justify-content:center;width:100%;height:34px;min-height:34px;padding:0 10px;line-height:1.15;text-align:center;white-space:normal;" href="<?php echo esc_url($result['edit_url']); ?>" target="_blank" rel="noopener">Edit</a>
                            <?php endif; ?>
                          </div>
                        <?php else: ?>
                          <span class="ioh-muted">No page link</span>
                        <?php endif; ?>
                      </td>
                      <td class="ioh-scan-excerpt"><span>
                        <?php
                          $display_excerpt = (string)($result['excerpt'] ?? '');
                          $display_area_key = (string)($result['area_key'] ?? '');
                          if ($display_area_key !== '') {
                              $display_excerpt = 'Target: ' . $display_area_key . ' | ' . $display_excerpt;
                          }
                          echo esc_html($display_excerpt);
                        ?>
                      </span></td>
                    </tr>
                  <?php endforeach; ?>
                </tbody>
              </table>
            </div>
          </div>
        <?php endif; ?>

        <div class="ioh-card ioh-popup-location-card">
          <form method="post">
            <?php wp_nonce_field('ioh_save','ioh_nonce'); ?>
            <input type="hidden" name="ioh_action" value="save_popup" />
            <input type="hidden" name="ioh_location" value="<?php echo esc_attr($current_slug); ?>" />

            <section id="ioh-admin-popup" class="ioh-section-card">
            <div class="ioh-section-head">
              <h3>Popup (<?php echo esc_html($current['name'] ?? ''); ?>)</h3>
              <p>Control where your site's popup appears, when it runs, and what it says.</p>
            </div>
            <label class="ioh-label">Display scope</label>
            <select name="ioh_popup_scope" class="regular-text" id="ioh_popup_scope">
              <option value="off" <?php selected(($current['popup']['scope'] ?? 'off'), 'off'); ?>>Off</option>
              <option value="homepage" <?php selected(($current['popup']['scope'] ?? 'off'), 'homepage'); ?>>Homepage only</option>
              <option value="sitewide" <?php selected(($current['popup']['scope'] ?? 'off'), 'sitewide'); ?>>Sitewide</option>
              <option value="selected_pages" <?php selected(($current['popup']['scope'] ?? 'off'), 'selected_pages'); ?>>Selected pages</option>
            </select>
            <div class="ioh-popup-pages-wrap" style="margin-top:10px;">
              <label class="ioh-label">Selected pages</label>
              <select name="ioh_popup_page_ids[]" class="regular-text" multiple size="8" style="min-width:320px;">
                <?php
                  $selected_page_ids = isset($current['popup']['page_ids']) && is_array($current['popup']['page_ids']) ? array_map('absint', $current['popup']['page_ids']) : [];
                  $pages = get_pages(['sort_column' => 'post_title', 'sort_order' => 'ASC']);
                  foreach ($pages as $page):
                ?>
                  <option value="<?php echo esc_attr($page->ID); ?>" <?php selected(in_array((int)$page->ID, $selected_page_ids, true)); ?>>
                    <?php echo esc_html($page->post_title ?: ('Page #' . $page->ID)); ?>
                  </option>
                <?php endforeach; ?>
              </select>
              <p class="description">Used only when Display scope is set to Selected pages. Hold Ctrl or Cmd to select multiple pages.</p>
            </div>

            <div class="ioh-popup-schedule-wrap" style="margin-top:10px;">
              <label class="ioh-label">Schedule</label>
              <div class="ioh-popup-control-row ioh-popup-schedule-row">
                <div class="ioh-popup-field">
                  <label for="ioh_popup_schedule_start">Popup starts</label>
                  <input type="datetime-local" id="ioh_popup_schedule_start" name="ioh_popup_schedule_start" value="<?php echo esc_attr($current['popup']['schedule_start'] ?? ''); ?>" class="regular-text" />
                </div>
                <div class="ioh-popup-field">
                  <label for="ioh_popup_schedule_end">Popup ends</label>
                  <input type="datetime-local" id="ioh_popup_schedule_end" name="ioh_popup_schedule_end" value="<?php echo esc_attr($current['popup']['schedule_end'] ?? ''); ?>" class="regular-text" />
                </div>
              </div>
              <p class="description">Leave either field blank for no start or end limit. Times use this website's timezone.</p>
            </div>

            <div class="ioh-popup-style-wrap" style="margin-top:10px;">
              <label class="ioh-label">Popup style</label>
              <div class="ioh-popup-control-row ioh-popup-style-row">
                <div class="ioh-popup-field">
                  <label for="ioh_popup_title">Popup title</label>
                  <input type="text" id="ioh_popup_title" name="ioh_popup_title" value="<?php echo esc_attr($current['popup']['title'] ?? 'ATTENTION'); ?>" class="regular-text" placeholder="Leave blank for no title" />
                </div>
                <div class="ioh-popup-field">
                  <label for="ioh_popup_banner_color">Banner color</label>
                  <span class="ioh-popup-color-controls">
                    <input type="color" id="ioh_popup_banner_color" name="ioh_popup_banner_color" value="<?php echo esc_attr($current['popup']['banner_color'] ?? ioh_default_popup_banner_color()); ?>" />
                    <input type="text" id="ioh_popup_banner_color_hex" name="ioh_popup_banner_color_hex" value="<?php echo esc_attr($current['popup']['banner_color'] ?? ioh_default_popup_banner_color()); ?>" class="regular-text" maxlength="7" />
                  </span>
                </div>
                <div class="ioh-popup-field">
                  <label for="ioh_popup_banner_text_color">Banner text color</label>
                  <span class="ioh-popup-color-controls">
                    <input type="color" id="ioh_popup_banner_text_color" name="ioh_popup_banner_text_color" value="<?php echo esc_attr($current['popup']['banner_text_color'] ?? '#ffffff'); ?>" />
                    <input type="text" id="ioh_popup_banner_text_color_hex" name="ioh_popup_banner_text_color_hex" value="<?php echo esc_attr($current['popup']['banner_text_color'] ?? '#ffffff'); ?>" class="regular-text" maxlength="7" />
                  </span>
                </div>
              </div>
            </div>

            <div class="ioh-popup-html-wrap" style="margin-top:10px;">
              <?php $popup_html = (string)($current['popup']['html'] ?? ''); ?>
              <label class="ioh-label" for="ioh_popup_editor">Popup content</label>
              <div class="ioh-popup-toolbar" aria-label="Popup content formatting">
                <button type="button" class="button" data-ioh-popup-command="bold"><strong>B</strong></button>
                <button type="button" class="button" data-ioh-popup-command="italic"><em>I</em></button>
                <button type="button" class="button" data-ioh-popup-command="underline"><u>U</u></button>
                <select id="ioh_popup_inline_text_size" aria-label="Text size">
                  <option value="">Size</option>
                  <option value="16px">16px</option>
                  <option value="18px">18px</option>
                  <option value="20px">20px</option>
                  <option value="24px">24px</option>
                  <option value="28px">28px</option>
                  <option value="32px">32px</option>
                  <option value="36px">36px</option>
                </select>
                <button type="button" class="button" data-ioh-popup-command="insertUnorderedList">Bullets</button>
                <button type="button" class="button" data-ioh-popup-command="insertOrderedList">Numbers</button>
                <button type="button" class="button" id="ioh_popup_link_btn">Link</button>
                <button type="button" class="button" id="ioh_popup_image_btn">Photo</button>
                <button type="button" class="button" id="ioh_popup_html_toggle_btn">HTML</button>
              </div>
              <div id="ioh_popup_editor" class="ioh-popup-rich-editor" contenteditable="true"></div>
              <div id="ioh_popup_image_tools" class="ioh-popup-image-tools">
                <span class="ioh-muted">Selected photo size</span>
                <input id="ioh_popup_image_width" type="range" min="10" max="100" step="5" value="100" />
                <span id="ioh_popup_image_width_label" class="ioh-muted">100%</span>
                <button type="button" class="button" data-ioh-image-size="25">25%</button>
                <button type="button" class="button" data-ioh-image-size="50">50%</button>
                <button type="button" class="button" data-ioh-image-size="75">75%</button>
                <button type="button" class="button" data-ioh-image-size="100">100%</button>
              </div>
              <textarea id="ioh_popup_html" name="ioh_popup_html" class="ioh-popup-html-textarea"><?php echo esc_textarea($popup_html); ?></textarea>
              <p class="description">Use Photo to insert an uploaded image. Select an inserted image to adjust its size. Use HTML to add trusted video embed code.</p>
            </div>

            <button type="submit" class="button button-primary" style="margin-top:16px;">Save Popup</button>
            </section>
          </form>
        </div>

        <div class="ioh-card ioh-edit-location-card">
          <div class="ioh-card-head">
            <h2>Edit Location: <?php echo esc_html($current['name'] ?? ''); ?></h2>
            <p>Update office hours, popup behavior, shortcode output, and display settings for this location.</p>
          </div>
          <p class="description">Shortcode example: <code>[ioh_office_hours location="<?php echo esc_html($current_slug); ?>"]</code></p>
          <div class="ioh-shortcode-generator">
            <h3 style="margin:0 0 10px;">Office Hours Shortcodes</h3>
            <p class="description" style="margin-top:0;">Office hours shortcodes always use <code>font-family: "Raleway", sans-serif;</code>.</p>
            <div style="display:flex; gap:12px; flex-wrap:wrap; align-items:flex-end;">
              <label>
                Format<br>
                <select id="ioh_shortcode_format">
                  <option value="standard">Standard</option>
                  <option value="compact">Compact</option>
                  <option value="sidebar">Sidebar</option>
                </select>
              </label>
              <label>
                Text color<br>
                <select id="ioh_shortcode_color_mode">
                  <option value="black">Black text</option>
                  <option value="white">White text</option>
                  <option value="custom">Custom color</option>
                </select>
              </label>
              <label id="ioh_shortcode_custom_color_wrap" style="display:none;">
                Custom color<br>
                <input type="text" id="ioh_shortcode_custom_color" value="#424242" placeholder="#424242" class="regular-text" style="width:120px;" />
              </label>
              <label>
                Text size<br>
                <input type="text" id="ioh_shortcode_size" value="16px" class="regular-text" style="width:90px;" />
              </label>
              <label>
                Top padding<br>
                <input type="text" id="ioh_shortcode_top_padding" value="0px" class="regular-text" style="width:90px;" />
              </label>
              <label>
                Bottom padding<br>
                <input type="text" id="ioh_shortcode_bottom_padding" value="0px" class="regular-text" style="width:90px;" />
              </label>
              <label id="ioh_shortcode_title_color_wrap" style="display:none;">
                Title color<br>
                <input type="text" id="ioh_shortcode_title_color" value="#578ea7" class="regular-text" style="width:120px;" />
              </label>
              <label id="ioh_shortcode_title_size_wrap" style="display:none;">
                Title size<br>
                <input type="text" id="ioh_shortcode_title_size" value="20px" class="regular-text" style="width:90px;" />
              </label>
            </div>
            <div class="ioh-top-option-row ioh-shortcode-options">
              <div class="ioh-option-grid">
                <label class="ioh-option-check"><input type="checkbox" id="ioh_shortcode_bold_days" /> <span>Bold day names</span></label>
                <label class="ioh-option-check"><input type="checkbox" id="ioh_shortcode_capitalize_day_names" /> <span>Capitalize Day Names</span></label>
                <label class="ioh-option-check"><input type="checkbox" id="ioh_shortcode_combine_closed_weekend" /> <span>Combine Saturday &amp; Sunday when both are closed</span></label>
                <label class="ioh-option-check"><input type="checkbox" id="ioh_shortcode_capitalize_hours" /> <span>Capitalize Hours</span></label>
              </div>
              <p class="description">These choices apply only to the shortcode generated below. Custom messages stay unchanged.</p>
            </div>
            <p style="margin:10px 0 4px;"><strong>Generated shortcode</strong></p>
            <div class="ioh-shortcode-copy-row" style="display:flex;flex-direction:column;align-items:center;gap:8px;">
              <input type="text" id="ioh_shortcode_generated" readonly class="large-text code" value="" onclick="this.select();" style="width:100%;" />
              <button type="button" class="button" id="ioh_shortcode_copy_btn" style="align-self:center;margin-left:auto;margin-right:auto;min-width:110px;">Copy</button>
            </div>
            <div class="ioh-shortcode-preview-wrap" style="display:flex;flex-direction:column;align-items:center;margin-top:16px;">
              <div class="ioh-shortcode-preview-label" style="width:100%;max-width:560px;margin:0 0 8px;color:#344054;font-weight:700;">Preview</div>
              <div id="ioh_shortcode_preview" class="ioh-shortcode-preview" aria-live="polite" style="box-sizing:border-box;width:100%;max-width:560px;min-height:72px;padding:14px 16px;border:1px solid #d0d7de;border-radius:6px;background:#fff;font-family:&quot;Raleway&quot;, sans-serif;line-height:1.4;"></div>
            </div>
          </div>

          <form method="post">
            <?php wp_nonce_field('ioh_save','ioh_nonce'); ?>
            <input type="hidden" name="ioh_action" value="save" />
            <input type="hidden" name="ioh_location" value="<?php echo esc_attr($current_slug); ?>" />

            <section id="ioh-admin-hours" class="ioh-section-card">
            <div class="ioh-section-head">
              <h3>Office Hours</h3>
              <p>Update your weekly business hours for this location.</p>
            </div>
            <div style="margin:8px 0 12px;">
              <label class="ioh-label" style="margin:0 0 6px;">Location title</label>
              <div style="display:flex; gap:12px; align-items:center; flex-wrap:wrap;">
                <input type="text" name="ioh_office_hours_title" value="<?php echo esc_attr($current['office_hours_title'] ?? ''); ?>" class="regular-text" style="max-width:420px;" />
                <label style="display:flex; align-items:center; gap:6px; margin:0;">
                  <input type="checkbox" name="ioh_display_show_title" value="1" <?php checked(!empty($settings['display']['show_title'])); ?> />
                  <span>Show title</span>
                </label>
              </div>
              <p class="description" style="margin-top:6px;">This title is per-location. Toggle "Show title" to display it.</p>
            </div>
            <table class="widefat fixed striped ioh-hours-table">
              <thead><tr>
                <th>Day</th><th>Closed</th><th>Hours / Message</th>
              </tr></thead>
              <tbody>
              <?php foreach (ioh_days() as $day_key => $day_label): 
                $d = $current['hours'][$day_key] ?? [];
                ?>
                <tr>
                  <td><strong><?php echo esc_html($day_label); ?></strong></td>
                  <td><label><input type="checkbox" class="ioh-day-closed" data-day="<?php echo esc_attr($day_key); ?>" name="ioh_hours[<?php echo esc_attr($day_key); ?>][closed]" value="1" <?php checked(!empty($d['closed'])); ?> /> Closed</label></td>
                  <td>
                    <div class="ioh-range ioh-day-time" data-day="<?php echo esc_attr($day_key); ?>" style="margin-bottom:6px;">
                      <input type="time" name="ioh_hours[<?php echo esc_attr($day_key); ?>][r1_start]" value="<?php echo esc_attr($d['r1_start'] ?? ''); ?>" />
                      <span>to</span>
                      <input type="time" name="ioh_hours[<?php echo esc_attr($day_key); ?>][r1_end]" value="<?php echo esc_attr($d['r1_end'] ?? ''); ?>" />
                    </div>
                    <div class="ioh-range ioh-day-time" data-day="<?php echo esc_attr($day_key); ?>">
                      <input type="time" name="ioh_hours[<?php echo esc_attr($day_key); ?>][r2_start]" value="<?php echo esc_attr($d['r2_start'] ?? ''); ?>" />
                      <span>to</span>
                      <input type="time" name="ioh_hours[<?php echo esc_attr($day_key); ?>][r2_end]" value="<?php echo esc_attr($d['r2_end'] ?? ''); ?>" />
                      <span class="ioh-muted" style="margin-left:6px;">(optional)</span>
                    </div>
                    <div class="ioh-day-message-wrap" data-day="<?php echo esc_attr($day_key); ?>" style="margin-top:8px;">
                      <input type="text" name="ioh_hours[<?php echo esc_attr($day_key); ?>][message]" value="<?php echo esc_attr($d['message'] ?? ''); ?>" class="regular-text ioh-day-message" data-day="<?php echo esc_attr($day_key); ?>" placeholder="Custom message, e.g. By appointment only" />
                      <p class="description" style="margin:4px 0 0;">Leave blank to use the time ranges. Closed still displays "Closed".</p>
                    </div>
                  </td>
                </tr>
              <?php endforeach; ?>
              </tbody>
            </table>
            </section>

            <input type="hidden" name="ioh_display_style" value="list" />
            <textarea name="ioh_display_template_html" hidden><?php echo esc_textarea((string)($settings['display']['template_html'] ?? '{{OFFICE_HOURS}}')); ?></textarea>

            <?php // Display section hidden from Admin view; code intentionally retained. ?>
            <?php if (false): ?>
            <section id="ioh-admin-display" class="ioh-section-card">
            <div class="ioh-section-head">
              <h3>Display</h3>
              <p>Control how office hours shortcodes and templates appear on the site.</p>
            </div>

            <textarea name="ioh_display_template_html" hidden><?php echo esc_textarea((string)($settings['display']['template_html'] ?? '{{OFFICE_HOURS}}')); ?></textarea>

            <h3 style="margin-top:0;">Display Preset</h3>
            <label class="ioh-label">Style</label>
            <select name="ioh_display_style" class="regular-text">
              <option value="list" <?php selected(($settings['display']['style'] ?? 'list'), 'list'); ?>>List</option>
              <option value="stacked" <?php selected(($settings['display']['style'] ?? 'list'), 'stacked'); ?>>Stacked</option>
              <option value="table" <?php selected(($settings['display']['style'] ?? 'list'), 'table'); ?>>Table</option>
            </select>
            <div style="margin-top:10px;">
              <label><input type="checkbox" name="ioh_display_show_separators" value="1" <?php checked(!empty($settings['display']['show_separators'])); ?> /> Show separators (stacked only)</label>
            </div>
            </section>
            <?php endif; ?>

            <button type="submit" class="button button-primary" style="margin-top:16px;">Save All</button>
          </form>
        </div>
        </div>
      </div>

      <?php // Remote API section hidden from Admin view; code intentionally retained. ?>
      <?php if (false): ?>
      <div id="ioh-admin-api" class="ioh-card" style="margin-top:18px;">
        <div class="ioh-card-head">
          <h2>Remote API</h2>
          <p>Generate API access, copy embed code, and choose which remote editor sections are visible.</p>
        </div>
        <?php if (current_user_can('manage_options')): ?>
          <?php $api_settings = ioh_get_api_settings(); ?>
          <?php if ($generated_api_key !== ''): ?>
            <div class="notice notice-warning inline">
              <p><strong>API key generated.</strong> It is also shown below for copying.</p>
              <p><input type="text" readonly class="large-text code" value="<?php echo esc_attr($generated_api_key); ?>" onclick="this.select();" /></p>
            </div>
          <?php endif; ?>

          <p>
            Status:
            <strong><?php echo ioh_has_api_key() ? 'Enabled' : 'No API key generated'; ?></strong>
            <?php if (!empty($api_settings['created_at'])): ?>
              <span class="ioh-muted">Created <?php echo esc_html($api_settings['created_at']); ?></span>
            <?php endif; ?>
          </p>

          <form method="post" class="ioh-section-card">
            <?php wp_nonce_field('ioh_save','ioh_nonce'); ?>
            <input type="hidden" name="ioh_action" value="save_remote_sections" />
            <h3 style="margin:0 0 8px;">Remote Editor Sections</h3>
            <p class="description" style="margin-top:0;">Choose which sections appear inside the remote iframe editor.</p>
            <div style="display:flex; gap:18px; flex-wrap:wrap; margin:10px 0 12px;">
              <label><input type="checkbox" name="ioh_remote_show_popup" value="1" <?php checked(!empty($settings['remote_editor']['show_popup'])); ?> /> Popup</label>
              <label><input type="checkbox" name="ioh_remote_show_hours" value="1" <?php checked(!empty($settings['remote_editor']['show_hours'])); ?> /> Office Hours</label>
              <label><input type="checkbox" name="ioh_remote_show_blog" value="1" <?php checked(!empty($settings['remote_editor']['show_blog'])); ?> /> Blog Maker</label>
            </div>
            <button class="button button-primary" type="submit">Save Section Visibility</button>
          </form>

          <?php
            $display_api_key = ioh_get_display_api_key();
            $embed_api_key = $generated_api_key !== '' ? $generated_api_key : $display_api_key;
            $remote_editor_url = $embed_api_key !== ''
                ? add_query_arg(['ioh_remote_editor' => '1', 'ioh_api_key' => $embed_api_key], home_url('/'))
                : home_url('/?ioh_remote_editor=1');
          ?>
          <?php if ($display_api_key !== ''): ?>
            <label class="ioh-label">Current API key</label>
            <div class="ioh-copy-row">
              <input type="text" readonly class="large-text code" value="<?php echo esc_attr($display_api_key); ?>" onclick="this.select();" />
              <button type="button" class="button" onclick="navigator.clipboard && navigator.clipboard.writeText(this.previousElementSibling.value); this.previousElementSibling.select();">Copy</button>
            </div>
          <?php elseif (ioh_has_api_key()): ?>
            <div class="notice notice-warning inline">
              <p>This key was generated by an older build that stored only a hash. Regenerate the API key to make it visible here.</p>
            </div>
          <?php endif; ?>

          <form method="post" class="ioh-row" style="margin:10px 0;">
            <?php wp_nonce_field('ioh_save','ioh_nonce'); ?>
            <input type="hidden" name="ioh_action" value="generate_api_key" />
            <button class="button button-primary" type="submit">
              <?php echo ioh_has_api_key() ? 'Regenerate API Key' : 'Generate API Key'; ?>
            </button>
          </form>

          <?php if (ioh_has_api_key()): ?>
            <form method="post" style="margin:10px 0;">
              <?php wp_nonce_field('ioh_save','ioh_nonce'); ?>
              <input type="hidden" name="ioh_action" value="revoke_api_key" />
              <button class="button button-link-delete" type="submit" onclick="return confirm('Revoke the remote API key? Existing integrations will stop working.');">Revoke API Key</button>
            </form>
          <?php endif; ?>
          <?php
            $remote_embed_code = '<iframe id="ioh-remote-editor" src="' . esc_url($remote_editor_url) . '" data-min-height="1000" style="width:100%; min-height:1000px; height:1000px; border:0; overflow:hidden;" scrolling="no" loading="lazy"></iframe>' . "\n" .
                '<script src="' . esc_url(IOH_URL . 'assets/remote-editor-embed.js?ver=' . IOH_VERSION) . '"></script>';
          ?>
          <p class="description">Iframe embed code for the second website:</p>
          <div class="ioh-copy-row">
            <textarea id="ioh_remote_embed_code" readonly class="large-text code" rows="3" onclick="this.select();"><?php echo esc_textarea($remote_embed_code); ?></textarea>
            <button type="button" class="button" id="ioh_remote_embed_copy_btn">Copy</button>
          </div>
        <?php else: ?>
          <p>Only administrators can manage the remote API key.</p>
        <?php endif; ?>
      </div>
      <?php endif; ?>
    </div>
      <?php
      $shortcode_preview_rows = function_exists('ioh_build_rows_for_location') ? ioh_build_rows_for_location($settings, $current_slug) : [];
      $shortcode_preview_data = [];
      foreach (ioh_days() as $day_key => $day_label) {
          $row = $shortcode_preview_rows[$day_key] ?? [
              'closed' => true,
              'lines' => ['Closed'],
              'single' => 'Closed',
              'source' => 'closed',
          ];
          $shortcode_preview_data[] = [
              'key' => $day_key,
              'label' => $day_label,
              'closed' => !empty($row['closed']),
              'lines' => array_values((array)($row['lines'] ?? [])),
              'single' => (string)($row['single'] ?? ''),
              'source' => (string)($row['source'] ?? 'hours'),
          ];
      }
      ?>
    <script>
      (function(){
        document.querySelectorAll('.ioh-admin-tabs a').forEach(function(tab){
          tab.addEventListener('click', function(){
            document.querySelectorAll('.ioh-admin-tabs a').forEach(function(item){
              item.classList.remove('is-active');
            });
            tab.classList.add('is-active');
          });
        });

        var popupEditor = document.getElementById('ioh_popup_editor');
        var popupHtml = document.getElementById('ioh_popup_html');
        var popupHtmlToggle = document.getElementById('ioh_popup_html_toggle_btn');
        var popupInlineTextSize = document.getElementById('ioh_popup_inline_text_size');
        var popupImageButton = document.getElementById('ioh_popup_image_btn');
        var popupImageTools = document.getElementById('ioh_popup_image_tools');
        var popupImageWidth = document.getElementById('ioh_popup_image_width');
        var popupImageWidthLabel = document.getElementById('ioh_popup_image_width_label');
        var selectedPopupImage = null;
        var savedPopupRange = null;
        var popupMediaFrame = null;

        function resizePopupHtmlTextarea(){
          if (!popupHtml) return;
          popupHtml.style.height = 'auto';
          popupHtml.style.height = Math.max(150, popupHtml.scrollHeight + 2) + 'px';
        }

        function resizePopupEditor(){
          if (!popupEditor) return;
          popupEditor.style.height = 'auto';
          popupEditor.style.height = Math.max(180, popupEditor.scrollHeight + 2) + 'px';
        }

        function resizePopupEditorSoon(){
          resizePopupEditor();
          window.requestAnimationFrame(function(){
            resizePopupEditor();
          });
          window.setTimeout(resizePopupEditor, 120);
          window.setTimeout(resizePopupEditor, 400);
        }

        function bindPopupEditorImageLoadEvents(){
          if (!popupEditor) return;
          popupEditor.querySelectorAll('img').forEach(function(image){
            if (image.dataset.iohResizeBound === '1') return;
            image.dataset.iohResizeBound = '1';
            image.addEventListener('load', resizePopupEditorSoon);
            image.addEventListener('error', resizePopupEditorSoon);
            if (image.complete) resizePopupEditorSoon();
          });
        }

        function syncPopupHtmlFromEditor(){
          if (!popupEditor || !popupHtml || popupEditor.style.display === 'none') return;
          var clone = popupEditor.cloneNode(true);
          clone.querySelectorAll('img.is-selected').forEach(function(image){
            image.classList.remove('is-selected');
          });
          popupHtml.value = clone.innerHTML;
          bindPopupEditorImageLoadEvents();
          resizePopupEditorSoon();
          resizePopupHtmlTextarea();
        }

        function syncPopupEditorFromHtml(){
          if (!popupEditor || !popupHtml) return;
          popupEditor.innerHTML = popupHtml.value || '';
          selectedPopupImage = null;
          updatePopupImageTools();
          bindPopupEditorImageLoadEvents();
          resizePopupEditorSoon();
          resizePopupHtmlTextarea();
        }

        function runPopupCommand(command, value){
          if (!popupEditor) return;
          popupEditor.focus();
          restorePopupSelection();
          document.execCommand(command, false, value || null);
          syncPopupHtmlFromEditor();
        }

        function savePopupSelection(){
          if (!popupEditor) return;
          var selection = window.getSelection();
          if (!selection || !selection.rangeCount) return;
          var range = selection.getRangeAt(0);
          if (popupEditor.contains(range.commonAncestorContainer)) {
            savedPopupRange = range.cloneRange();
          }
        }

        function restorePopupSelection(){
          if (!savedPopupRange) return;
          var selection = window.getSelection();
          if (!selection) return;
          selection.removeAllRanges();
          selection.addRange(savedPopupRange);
        }

        function selectPopupImage(image){
          if (selectedPopupImage) selectedPopupImage.classList.remove('is-selected');
          selectedPopupImage = image || null;
          if (selectedPopupImage) selectedPopupImage.classList.add('is-selected');
          updatePopupImageTools();
        }

        function popupImageWidthPercent(image){
          if (!image) return 100;
          var width = String(image.style.width || '').trim();
          var match = width.match(/^(\d+(?:\.\d+)?)%$/);
          return match ? Math.round(Number(match[1])) : 100;
        }

        function updatePopupImageTools(){
          if (!popupImageTools) return;
          var visible = !!selectedPopupImage && popupHtml && popupHtml.style.display === 'none';
          popupImageTools.classList.toggle('is-visible', visible);
          if (!visible || !popupImageWidth || !popupImageWidthLabel) return;
          var width = popupImageWidthPercent(selectedPopupImage);
          popupImageWidth.value = String(width);
          popupImageWidthLabel.textContent = width + '%';
        }

        function resizeSelectedPopupImage(value){
          if (!selectedPopupImage) return;
          var width = Math.min(100, Math.max(10, parseInt(value, 10) || 100));
          selectedPopupImage.style.width = width + '%';
          selectedPopupImage.style.maxWidth = '100%';
          selectedPopupImage.style.height = 'auto';
          if (popupImageWidth) popupImageWidth.value = String(width);
          if (popupImageWidthLabel) popupImageWidthLabel.textContent = width + '%';
          resizePopupEditorSoon();
          syncPopupHtmlFromEditor();
        }

        document.querySelectorAll('[data-ioh-popup-command]').forEach(function(button){
          button.addEventListener('mousedown', function(event){
            event.preventDefault();
          });
          button.addEventListener('click', function(){
            runPopupCommand(button.dataset.iohPopupCommand);
          });
        });

        if (popupInlineTextSize) {
          popupInlineTextSize.addEventListener('change', function(){
            var size = popupInlineTextSize.value;
            if (!size) return;
            runPopupCommand('fontSize', '7');
            if (popupEditor) {
              popupEditor.querySelectorAll('font[size="7"]').forEach(function(node){
                var span = document.createElement('span');
                span.style.fontSize = size;
                span.innerHTML = node.innerHTML;
                node.replaceWith(span);
              });
            }
            popupInlineTextSize.value = '';
            syncPopupHtmlFromEditor();
          });
        }

        var popupLinkButton = document.getElementById('ioh_popup_link_btn');
        if (popupLinkButton) {
          popupLinkButton.addEventListener('mousedown', function(event){
            event.preventDefault();
          });
          popupLinkButton.addEventListener('click', function(){
            var url = window.prompt('Enter a URL for this link.');
            if (!url) return;
            if (!/^https?:\/\//i.test(url)) url = 'https://' + url;
            runPopupCommand('createLink', url);
          });
        }

        if (popupImageButton) {
          popupImageButton.addEventListener('mousedown', function(event){
            event.preventDefault();
          });
          popupImageButton.addEventListener('click', function(){
            if (!window.wp || !window.wp.media) return;
            if (!popupMediaFrame) {
              popupMediaFrame = window.wp.media({
                title: 'Choose Popup Photo',
                button: {text: 'Insert Photo'},
                library: {type: 'image'},
                multiple: false
              });
              popupMediaFrame.on('select', function(){
                var attachment = popupMediaFrame.state().get('selection').first();
                if (!attachment) return;
                attachment = attachment.toJSON();
                var image = document.createElement('img');
                image.src = attachment.url;
                image.alt = attachment.alt || attachment.title || '';
                image.style.maxWidth = '100%';
                image.style.height = 'auto';
                image.style.width = '100%';
                popupEditor.focus();
                restorePopupSelection();
                var selection = window.getSelection();
                if (selection && selection.rangeCount) {
                  var range = selection.getRangeAt(0);
                  range.deleteContents();
                  range.insertNode(image);
                  range.setStartAfter(image);
                  range.collapse(true);
                  selection.removeAllRanges();
                  selection.addRange(range);
                } else {
                  popupEditor.appendChild(image);
                }
                selectPopupImage(image);
                bindPopupEditorImageLoadEvents();
                resizePopupEditorSoon();
                syncPopupHtmlFromEditor();
              });
            }
            popupMediaFrame.open();
          });
        }

        if (popupHtmlToggle) {
          popupHtmlToggle.addEventListener('mousedown', function(event){
            event.preventDefault();
          });
          popupHtmlToggle.addEventListener('click', function(){
            if (!popupEditor || !popupHtml) return;
            var htmlVisible = popupHtml.style.display !== 'none';
            if (htmlVisible) {
              syncPopupEditorFromHtml();
              popupHtml.style.display = 'none';
              popupEditor.style.display = 'block';
              popupHtmlToggle.textContent = 'HTML';
              resizePopupEditorSoon();
              popupEditor.focus();
            } else {
              syncPopupHtmlFromEditor();
              popupEditor.style.display = 'none';
              popupHtml.style.display = 'block';
              popupHtmlToggle.textContent = 'Visual';
              resizePopupHtmlTextarea();
              popupHtml.focus();
            }
            updatePopupImageTools();
          });
        }

        if (popupEditor) {
          popupEditor.addEventListener('input', syncPopupHtmlFromEditor);
          popupEditor.addEventListener('click', function(event){
            selectPopupImage(event.target && event.target.tagName === 'IMG' ? event.target : null);
            savePopupSelection();
          });
          popupEditor.addEventListener('mouseup', savePopupSelection);
          popupEditor.addEventListener('focus', savePopupSelection);
          popupEditor.addEventListener('keyup', savePopupSelection);
          popupEditor.addEventListener('keyup', resizePopupEditorSoon);
        }

        if (popupHtml) {
          popupHtml.style.display = 'none';
          popupHtml.addEventListener('input', function(){
            syncPopupEditorFromHtml();
            resizePopupHtmlTextarea();
          });
        }

        if (popupImageWidth) {
          popupImageWidth.addEventListener('input', function(){
            resizeSelectedPopupImage(popupImageWidth.value);
          });
        }

        document.querySelectorAll('[data-ioh-image-size]').forEach(function(button){
          button.addEventListener('click', function(){
            resizeSelectedPopupImage(button.dataset.iohImageSize);
          });
        });

        document.querySelectorAll('form').forEach(function(form){
          form.addEventListener('submit', function(){
            syncPopupHtmlFromEditor();
          });
        });

        syncPopupEditorFromHtml();
        if (popupHtml) popupHtml.style.display = 'none';
        window.addEventListener('load', resizePopupEditorSoon);

        function updatePopupFields(){
          var scope = document.getElementById('ioh_popup_scope');
          var htmlWrap = document.querySelector('.ioh-popup-html-wrap');
          var pagesWrap = document.querySelector('.ioh-popup-pages-wrap');
          var scheduleWrap = document.querySelector('.ioh-popup-schedule-wrap');
          var styleWrap = document.querySelector('.ioh-popup-style-wrap');
          if (!scope) return;
          if (htmlWrap) htmlWrap.style.display = scope.value === 'off' ? 'none' : '';
          if (pagesWrap) pagesWrap.style.display = scope.value === 'selected_pages' ? '' : 'none';
          if (scheduleWrap) scheduleWrap.style.display = scope.value === 'off' ? 'none' : '';
          if (styleWrap) styleWrap.style.display = scope.value === 'off' ? 'none' : '';
        }

        function updateDay(day){
          var closed = document.querySelector('.ioh-day-closed[data-day="' + day + '"]');
          if (!closed) return;
          document.querySelectorAll('.ioh-day-time[data-day="' + day + '"], .ioh-day-message-wrap[data-day="' + day + '"]').forEach(function(el){
            el.style.display = closed.checked ? 'none' : '';
          });
        }

        document.querySelectorAll('.ioh-day-closed').forEach(function(input){
          input.addEventListener('change', function(){
            if (input.checked) {
              var message = document.querySelector('.ioh-day-message[data-day="' + input.dataset.day + '"]');
              if (message) message.value = '';
            }
            updateDay(input.dataset.day);
          });
          updateDay(input.dataset.day);
        });

        document.querySelectorAll('.ioh-day-message').forEach(function(input){
          input.addEventListener('input', function(){
            if (input.value.trim() !== '') {
              var closed = document.querySelector('.ioh-day-closed[data-day="' + input.dataset.day + '"]');
              if (closed) closed.checked = false;
              updateDay(input.dataset.day);
            }
          });
        });

        var popupScope = document.getElementById('ioh_popup_scope');
        if (popupScope) popupScope.addEventListener('change', updatePopupFields);
        updatePopupFields();

        function ajaxJson(response, context){
          var contentType = response.headers && response.headers.get ? (response.headers.get('content-type') || '') : '';
          return response.text().then(function(text){
            var trimmed = (text || '').trim();
            if (contentType.indexOf('application/json') !== -1 || trimmed.charAt(0) === '{' || trimmed.charAt(0) === '[') {
              try {
                return JSON.parse(trimmed || '{}');
              } catch (error) {
                throw new Error((context || 'Request') + ' returned invalid JSON: ' + error.message);
              }
            }

            var preview = trimmed.replace(/\s+/g, ' ').slice(0, 220);
            if (!preview) preview = response.statusText || 'Empty response';
            throw new Error((context || 'Request') + ' returned HTTP ' + response.status + ' instead of JSON. Response starts: ' + preview);
          });
        }




        var scanButton = document.getElementById('ioh_scan_office_hours_btn');
        var scanStatus = document.getElementById('ioh_scan_status');
        var scanCard = document.getElementById('ioh_scan_results_card');
        var scanBody = document.getElementById('ioh_scan_results_body');
        var scanLoading = document.getElementById('ioh_scan_loading');
        var scanTableWrap = document.getElementById('ioh_scan_table_wrap');
        var scanEmpty = document.getElementById('ioh_scan_empty_message');

        function escapeHtml(value){
          return String(value == null ? '' : value).replace(/[&<>"']/g, function(char){
            return {'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#039;'}[char];
          });
        }

        function scanLinksHtml(result){
          if (!result.view_url) return '<span class="ioh-muted">No page link</span>';
          var html = '<div class="ioh-scan-link-actions">';
          html += '<a class="button" style="box-sizing:border-box;display:flex;align-items:center;justify-content:center;width:100%;height:34px;min-height:34px;padding:0 10px;line-height:1.15;text-align:center;white-space:normal;" href="' + escapeHtml(result.view_url) + '" target="_blank" rel="noopener">View</a>';
          if (result.builder_url) html += '<a class="button" style="box-sizing:border-box;display:flex;align-items:center;justify-content:center;width:100%;height:34px;min-height:34px;padding:0 10px;line-height:1.15;text-align:center;white-space:normal;" href="' + escapeHtml(result.builder_url) + '" target="_blank" rel="noopener">Beaver Builder</a>';
          if (result.edit_url) html += '<a class="button" style="box-sizing:border-box;display:flex;align-items:center;justify-content:center;width:100%;height:34px;min-height:34px;padding:0 10px;line-height:1.15;text-align:center;white-space:normal;" href="' + escapeHtml(result.edit_url) + '" target="_blank" rel="noopener">Edit</a>';
          html += '</div>';
          return html;
        }


        function matchedTextHtml(result){
          var text = String(result && result.excerpt || '');
          var areaKey = String(result && result.area_key || '');
          if (areaKey) text = 'Target: ' + areaKey + ' | ' + text;
          return escapeHtml(text);
        }


        function isSlideBoxOfficeHoursLabelMetadata(result){
          var excerpt = String(result && result.excerpt || '');
          if (/\b\d{1,2}(?::\d{2})?\s*(?:am|pm|a\.m\.|p\.m\.)?\s*(?:-|\u2013|\u2014|to)\s*\d{1,2}(?::\d{2})?\s*(?:am|pm|a\.m\.|p\.m\.)?\b/i.test(excerpt)) return false;
          if (/(?:^|\s)[MTWFS]\s*:\s*(?:Closed|\d{1,2}(?::\d{2})?\s*(?:am|pm|a\.m\.|p\.m\.))/i.test(excerpt)) return false;
          return /title_front[\s\S]{0,100}office\s+hours/i.test(excerpt) &&
            /(?:desc_front|image_type|icon_color|icon_hover_color|icon_size|ua-icon|uabb)/i.test(excerpt);
        }

        function globalHeaderOrFooterHasActualTimes(result){
          var type = String(result && result.type || '').toLowerCase();
          if (type !== 'header area' && type !== 'footer area') return true;
          if (result && result.has_actual_office_hour_times) return true;
          var excerpt = String(result && result.excerpt || '');
          return /\b\d{1,2}(?::\d{2})?\s*(?:am|pm|a\.m\.|p\.m\.)?\s*(?:-|\u2013|\u2014|to)\s*\d{1,2}(?::\d{2})?\s*(?:am|pm|a\.m\.|p\.m\.)?\b/i.test(excerpt);
        }

        function renderScanResults(results){
          if (!scanCard || !scanBody) return;
          results = Array.isArray(results) ? results : [];
          results = results.filter(function(result){
            return globalHeaderOrFooterHasActualTimes(result) &&
              !isSlideBoxOfficeHoursLabelMetadata(result);
          });
          scanCard.style.display = '';
          if (scanLoading) scanLoading.style.display = 'none';
          if (scanTableWrap) scanTableWrap.style.display = results.length ? '' : 'none';
          if (scanEmpty) scanEmpty.style.display = results.length ? 'none' : '';
          scanBody.innerHTML = results.map(function(result){
            return '<tr data-post-id="' + escapeHtml(result.id || 0) + '">' +
              '<td>' + escapeHtml(result.title) + '</td>' +
              '<td>' + escapeHtml(result.type) + '</td>' +
              '<td>' + escapeHtml(result.detected_style || 'Standard') + '</td>' +
              '<td>' + scanLinksHtml(result) + '</td>' +
              '<td class="ioh-scan-excerpt"><span>' + matchedTextHtml(result) + '</span></td>' +
            '</tr>';
          }).join('');
        }

        function showScanLoading(){
          if (scanCard) scanCard.style.display = '';
          if (scanLoading) scanLoading.style.display = '';
          if (scanTableWrap) scanTableWrap.style.display = 'none';
          if (scanEmpty) scanEmpty.style.display = 'none';
          if (scanBody) scanBody.innerHTML = '';
        }

        function hideScanLoading(){
          if (scanLoading) scanLoading.style.display = 'none';
        }


        var scanProgressTimer = null;
        var scanStartedAt = 0;
        var scanCurrentMessage = '';

        function scanStageMessage(stage, offset){
          if (stage === 'init') return 'Preparing scan...';
          if (stage === 'posts') return 'Scanning saved content' + (offset ? ' starting at item ' + (offset + 1) : '') + '...';
          if (stage === 'layout_db') return 'Checking layout data...';
          if (stage === 'page_db') return 'Checking page and post data...';
          if (stage === 'widgets') return 'Checking widgets and site options...';
          if (stage === 'rendered_globals') return 'Scanning global headers and footers...';
          return 'Finishing scan...';
        }

        function setScanProgress(message){
          scanCurrentMessage = message || 'Scanning...';
          if (scanStatus) scanStatus.textContent = scanCurrentMessage;
        }

        function startScanProgressTimer(){
          stopScanProgressTimer();
          scanStartedAt = Date.now();
          scanProgressTimer = window.setInterval(function(){
            if (!scanStatus || !scanCurrentMessage) return;
            var seconds = Math.max(1, Math.floor((Date.now() - scanStartedAt) / 1000));
            scanStatus.textContent = scanCurrentMessage + ' Still working (' + seconds + 's)...';
          }, 5000);
        }

        function stopScanProgressTimer(){
          if (scanProgressTimer) window.clearInterval(scanProgressTimer);
          scanProgressTimer = null;
        }

        function runScanBatch(stage, offset){
          setScanProgress(scanStageMessage(stage, offset || 0));
          var body = new URLSearchParams();
          body.set('action', 'ioh_scan_office_hours_batch');
          body.set('nonce', scanButton ? scanButton.dataset.nonce : '');
          body.set('stage', stage);
          body.set('offset', String(offset || 0));
          return fetch(ajaxurl, {
            method: 'POST',
            credentials: 'same-origin',
            headers: {'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'},
            body: body.toString()
          }).then(function(response){
            return ajaxJson(response, 'Office-hours scan request');
          }).then(function(payload){
            if (!payload || !payload.success) {
              throw new Error(payload && payload.data && payload.data.message ? payload.data.message : 'The scan stopped before it could finish.');
            }
            var data = payload.data || {};
            if (scanStatus) scanStatus.textContent = data.message || 'Scanning...';
            if (data.done) {
              stopScanProgressTimer();
              renderScanResults(data.results || []);
              if (scanButton) {
                scanButton.disabled = false;
                scanButton.textContent = 'Find Office Hours on Site';
              }
              return;
            }
            return runScanBatch(data.stage || 'done', data.offset || 0);
          });
        }

        if (scanButton) {
          scanButton.addEventListener('click', function(){
            scanButton.disabled = true;
            scanButton.textContent = 'Scanning...';
            setScanProgress('Preparing scan...');
            showScanLoading();
            startScanProgressTimer();
            runScanBatch('init', 0).catch(function(error){
              stopScanProgressTimer();
              hideScanLoading();
              if (scanStatus) scanStatus.textContent = error.message || 'The scan stopped before it could finish.';
              scanButton.disabled = false;
              scanButton.textContent = 'Find Office Hours on Site';
            });
          });
        }

        function normalizeHexColor(value){
          value = String(value || '').trim();
          if (value !== '' && value.charAt(0) !== '#') value = '#' + value;
          return /^#[0-9a-fA-F]{6}$/.test(value) ? value.toUpperCase() : '';
        }

        function bindColorHex(colorId, hexId){
          var color = document.getElementById(colorId);
          var hex = document.getElementById(hexId);
          if (!color || !hex) return;
          color.addEventListener('input', function(){
            hex.value = color.value.toUpperCase();
          });
          hex.addEventListener('change', function(){
            var normalized = normalizeHexColor(hex.value);
            if (normalized) {
              color.value = normalized.toLowerCase();
              hex.value = normalized;
            } else {
              hex.value = color.value.toUpperCase();
            }
          });
        }

        bindColorHex('ioh_popup_banner_color', 'ioh_popup_banner_color_hex');
        bindColorHex('ioh_popup_banner_text_color', 'ioh_popup_banner_text_color_hex');

        var shortcodeLocation = <?php echo wp_json_encode($current_slug); ?>;
        var shortcodeFormat = document.getElementById('ioh_shortcode_format');
        var shortcodeColorMode = document.getElementById('ioh_shortcode_color_mode');
        var shortcodeCustomColorWrap = document.getElementById('ioh_shortcode_custom_color_wrap');
        var shortcodeCustomColor = document.getElementById('ioh_shortcode_custom_color');
        var shortcodeSize = document.getElementById('ioh_shortcode_size');
        var shortcodeTopPadding = document.getElementById('ioh_shortcode_top_padding');
        var shortcodeBottomPadding = document.getElementById('ioh_shortcode_bottom_padding');
        var shortcodeTitleColorWrap = document.getElementById('ioh_shortcode_title_color_wrap');
        var shortcodeTitleColor = document.getElementById('ioh_shortcode_title_color');
        var shortcodeTitleSizeWrap = document.getElementById('ioh_shortcode_title_size_wrap');
        var shortcodeTitleSize = document.getElementById('ioh_shortcode_title_size');
        var shortcodeBoldDays = document.getElementById('ioh_shortcode_bold_days');
        var shortcodeCapitalizeDayNames = document.getElementById('ioh_shortcode_capitalize_day_names');
        var shortcodeCapitalizeHours = document.getElementById('ioh_shortcode_capitalize_hours');
        var shortcodeCombineClosedWeekend = document.getElementById('ioh_shortcode_combine_closed_weekend');
        var shortcodeGenerated = document.getElementById('ioh_shortcode_generated');
        var shortcodeCopyButton = document.getElementById('ioh_shortcode_copy_btn');
        var shortcodePreview = document.getElementById('ioh_shortcode_preview');
        var shortcodePreviewRows = <?php echo wp_json_encode($shortcode_preview_data); ?>;
        var shortcodePreviewTitle = <?php echo wp_json_encode((string)($current['office_hours_title'] ?? '')); ?>;
        var shortcodePreviewShowTitle = <?php echo !empty($settings['display']['show_title']) ? 'true' : 'false'; ?>;
        var remoteEmbedCode = document.getElementById('ioh_remote_embed_code');
        var remoteEmbedCopyButton = document.getElementById('ioh_remote_embed_copy_btn');

        function escapePreviewText(value){
          return String(value == null ? '' : value).replace(/[&<>"']/g, function(character){
            return {'&':'&amp;', '<':'&lt;', '>':'&gt;', '"':'&quot;', "'":'&#039;'}[character];
          });
        }

        function formatPreviewTime(value){
          var parts = String(value || '').split(':');
          if (parts.length < 2) return '';
          var hour = parseInt(parts[0], 10);
          var minute = parseInt(parts[1], 10);
          if (isNaN(hour) || isNaN(minute)) return '';
          var suffix = hour >= 12 ? 'pm' : 'am';
          var displayHour = hour % 12;
          if (displayHour === 0) displayHour = 12;
          return displayHour + ':' + String(minute).padStart(2, '0') + suffix;
        }

        function formatPreviewRange(start, end){
          var startText = formatPreviewTime(start);
          var endText = formatPreviewTime(end);
          return startText && endText ? startText + ' - ' + endText : '';
        }

        function getFormFieldByName(name){
          var fields = document.getElementsByName(name);
          return fields && fields.length ? fields[0] : null;
        }

        function getCurrentPreviewSourceRows(){
          return (shortcodePreviewRows || []).map(function(row){
            var key = row.key;
            var closedInput = getFormFieldByName('ioh_hours[' + key + '][closed]');
            var messageInput = getFormFieldByName('ioh_hours[' + key + '][message]');
            var r1Start = getFormFieldByName('ioh_hours[' + key + '][r1_start]');
            var r1End = getFormFieldByName('ioh_hours[' + key + '][r1_end]');
            var r2Start = getFormFieldByName('ioh_hours[' + key + '][r2_start]');
            var r2End = getFormFieldByName('ioh_hours[' + key + '][r2_end]');
            var closed = closedInput ? closedInput.checked : !!row.closed;
            var message = messageInput ? String(messageInput.value || '').trim() : '';
            var lines = [];
            var source = 'hours';

            if (closed) {
              lines = ['Closed'];
              source = 'closed';
            } else if (message !== '') {
              lines = [message];
              source = 'message';
            } else if (r1Start || r1End || r2Start || r2End) {
              var firstRange = formatPreviewRange(r1Start ? r1Start.value : '', r1End ? r1End.value : '');
              var secondRange = formatPreviewRange(r2Start ? r2Start.value : '', r2End ? r2End.value : '');
              if (firstRange) lines.push(firstRange);
              if (secondRange) lines.push(secondRange);
              if (!lines.length) {
                lines = ['Closed'];
                source = 'closed';
                closed = true;
              }
            } else {
              lines = Array.isArray(row.lines) ? row.lines.slice() : ['Closed'];
              source = row.source || 'hours';
            }

            return {
              key: key,
              label: row.label,
              closed: closed,
              lines: lines,
              single: lines.join(' / '),
              source: source
            };
          });
        }

        function getPreviewRows(options){
          var rows = getCurrentPreviewSourceRows().map(function(row){
            var lines = Array.isArray(row.lines) ? row.lines.slice() : [];
            if (options.capitalizeHours && row.source !== 'message') {
              lines = lines.map(function(line){ return String(line).toUpperCase(); });
            }
            return {
              key: row.key,
              label: options.capitalizeDayNames ? String(row.label).toUpperCase() : row.label,
              closed: !!row.closed,
              lines: lines,
              single: lines.join(' / '),
              source: row.source
            };
          });

          var saturdayIndex = rows.findIndex(function(row){ return row.key === 'sat'; });
          var sundayIndex = rows.findIndex(function(row){ return row.key === 'sun'; });
          if (options.combineClosedWeekend && saturdayIndex !== -1 && sundayIndex !== -1 && rows[saturdayIndex].closed && rows[sundayIndex].closed) {
            rows[saturdayIndex] = {
              key: 'weekend',
              label: options.capitalizeDayNames ? 'SATURDAY & SUNDAY' : 'Saturday & Sunday',
              closed: true,
              lines: rows[saturdayIndex].lines,
              single: rows[saturdayIndex].single,
              source: rows[saturdayIndex].source
            };
            rows.splice(sundayIndex, 1);
          }
          return rows;
        }

        function updateShortcodePreview(options){
          if (!shortcodePreview) return;
          var rows = getPreviewRows(options);
          var dayWeight = options.boldDays ? '700' : '400';
          var titleInput = getFormFieldByName('ioh_office_hours_title');
          var showTitleInput = getFormFieldByName('ioh_display_show_title');
          var titleIsVisible = showTitleInput ? showTitleInput.checked : shortcodePreviewShowTitle;
          var title = titleIsVisible ? String(titleInput ? titleInput.value : shortcodePreviewTitle || '').trim() : '';
          var html = '';

          shortcodePreview.style.boxSizing = 'border-box';
          shortcodePreview.style.width = '100%';
          shortcodePreview.style.maxWidth = '560px';
          shortcodePreview.style.minHeight = '72px';
          shortcodePreview.style.padding = '14px 16px';
          shortcodePreview.style.paddingTop = options.topPadding;
          shortcodePreview.style.paddingBottom = options.bottomPadding;
          shortcodePreview.style.border = '1px solid #d0d7de';
          shortcodePreview.style.borderRadius = '6px';
          shortcodePreview.style.background = '#fff';
          shortcodePreview.style.fontFamily = '"Raleway", sans-serif';
          shortcodePreview.style.lineHeight = options.format === 'sidebar' ? '20px' : '1.4';
          shortcodePreview.style.color = options.color;
          shortcodePreview.style.fontSize = options.size;

          if (options.format === 'sidebar') {
            shortcodePreview.className = 'ioh-shortcode-preview is-sidebar-preview';
            shortcodePreview.style.textAlign = 'center';
            var separator = '<hr style="width:calc(100% - 100px);min-width:80px;height:1px;margin:5px auto;border:0;background:#ccc;" />';
            if (title) {
              html += '<p class="ioh-preview-sidebar-title" style="margin:0 0 16px;color:' + escapePreviewText(options.titleColor) + ';font-size:' + escapePreviewText(options.titleSize) + ';font-weight:700;line-height:1.25;">' + escapePreviewText(title) + '</p>' + separator;
            }
            rows.forEach(function(row, index){
              html += '<p class="ioh-preview-sidebar-row" style="margin:14px 0;text-align:center;line-height:20px;"><span style="display:block;font-weight:' + dayWeight + ';">' + escapePreviewText(row.label) + '</span>';
              row.lines.forEach(function(line){
                html += '<span style="display:block;">' + escapePreviewText(line) + '</span>';
              });
              html += '</p>';
              if (index < rows.length - 1) html += separator;
            });
          } else if (options.format === 'compact') {
            shortcodePreview.className = 'ioh-shortcode-preview is-compact-preview';
            shortcodePreview.style.textAlign = 'left';
            var compactLabels = {mon:'M', tue:'T', wed:'W', thu:'T', fri:'F', sat:'S', sun:'S'};
            rows.forEach(function(row){
              var label = row.key === 'weekend' ? row.label : (compactLabels[row.key] || row.label);
              html += '<div><span style="font-weight:' + dayWeight + ';">' + escapePreviewText(label) + ':</span> ' + escapePreviewText(row.single) + '</div>';
            });
          } else {
            shortcodePreview.className = 'ioh-shortcode-preview is-list-preview';
            shortcodePreview.style.textAlign = 'left';
            if (title) html += '<div class="ioh-preview-title" style="margin:0 0 22px;font-size:22px;font-weight:700;line-height:1.2;">' + escapePreviewText(title) + '</div>';
            rows.forEach(function(row){
              html += '<div class="ioh-preview-row" style="display:flex;gap:24px;align-items:flex-start;justify-content:space-between;padding:4px 0;line-height:1.45;">';
              html += '<div style="flex:0 0 auto;font-weight:' + dayWeight + ';">' + escapePreviewText(row.label) + '</div>';
              html += '<div style="flex:1 1 auto;min-width:0;text-align:right;">';
              row.lines.forEach(function(line){
                html += '<span style="display:block;margin:0;">' + escapePreviewText(line) + '</span>';
              });
              html += '</div></div>';
            });
          }
          shortcodePreview.innerHTML = html;
        }

        function updateShortcodeGenerator(){
          if (!shortcodeColorMode || !shortcodeSize || !shortcodeGenerated) return;
          var format = shortcodeFormat ? shortcodeFormat.value : 'standard';
          var isSidebar = format === 'sidebar';
          var color = shortcodeColorMode.value;
          if (shortcodeCustomColorWrap) shortcodeCustomColorWrap.style.display = color === 'custom' ? '' : 'none';
          if (shortcodeTitleColorWrap) shortcodeTitleColorWrap.style.display = isSidebar ? '' : 'none';
          if (shortcodeTitleSizeWrap) shortcodeTitleSizeWrap.style.display = isSidebar ? '' : 'none';
          if (color === 'custom') color = shortcodeCustomColor && shortcodeCustomColor.value ? shortcodeCustomColor.value : '#424242';
          var size = shortcodeSize.value || '16px';
          var topPadding = shortcodeTopPadding && shortcodeTopPadding.value ? shortcodeTopPadding.value : '0px';
          var bottomPadding = shortcodeBottomPadding && shortcodeBottomPadding.value ? shortcodeBottomPadding.value : '0px';
          var titleColor = shortcodeTitleColor && shortcodeTitleColor.value ? shortcodeTitleColor.value : '#578ea7';
          var titleSize = shortcodeTitleSize && shortcodeTitleSize.value ? shortcodeTitleSize.value : '20px';
          var spacing = '" top_padding="' + topPadding + '" bottom_padding="' + bottomPadding;
          var displayOptions = '';
          var boldDays = !!(shortcodeBoldDays && shortcodeBoldDays.checked);
          var capitalizeDayNames = !!(shortcodeCapitalizeDayNames && shortcodeCapitalizeDayNames.checked);
          var capitalizeHours = !!(shortcodeCapitalizeHours && shortcodeCapitalizeHours.checked);
          var combineClosedWeekend = !!(shortcodeCombineClosedWeekend && shortcodeCombineClosedWeekend.checked);
          if (boldDays) displayOptions += '" bold_days="1';
          if (capitalizeDayNames) displayOptions += '" capitalize_day_names="1';
          if (capitalizeHours) displayOptions += '" capitalize_hours="1';
          if (combineClosedWeekend) displayOptions += '" combine_closed_weekend="1';
          if (format === 'compact') {
            shortcodeGenerated.value = '[ioh_office_hours_compact location="' + shortcodeLocation + '" color="' + color + '" size="' + size + spacing + displayOptions + '"]';
          } else if (isSidebar) {
            shortcodeGenerated.value = '[ioh_office_hours_sidebar location="' + shortcodeLocation + '" color="' + color + '" size="' + size + spacing + '" title_color="' + titleColor + '" title_size="' + titleSize + displayOptions + '"]';
          } else {
            shortcodeGenerated.value = '[ioh_office_hours location="' + shortcodeLocation + '" color="' + color + '" size="' + size + spacing + displayOptions + '"]';
          }
          updateShortcodePreview({
            format: format,
            color: color,
            size: size,
            topPadding: topPadding,
            bottomPadding: bottomPadding,
            titleColor: titleColor,
            titleSize: titleSize,
            boldDays: boldDays,
            capitalizeDayNames: capitalizeDayNames,
            capitalizeHours: capitalizeHours,
            combineClosedWeekend: combineClosedWeekend
          });
        }
        [shortcodeFormat, shortcodeColorMode, shortcodeCustomColor, shortcodeSize, shortcodeTopPadding, shortcodeBottomPadding, shortcodeTitleColor, shortcodeTitleSize, shortcodeBoldDays, shortcodeCapitalizeDayNames, shortcodeCapitalizeHours, shortcodeCombineClosedWeekend].forEach(function(input){
          if (input) input.addEventListener('input', updateShortcodeGenerator);
          if (input) input.addEventListener('change', updateShortcodeGenerator);
        });
        document.querySelectorAll('input[name^="ioh_hours["], input[name="ioh_office_hours_title"], input[name="ioh_display_show_title"]').forEach(function(input){
          input.addEventListener('input', updateShortcodeGenerator);
          input.addEventListener('change', updateShortcodeGenerator);
        });
        function setShortcodeCopyStatus(message){
          if (!shortcodeCopyButton) return;
          shortcodeCopyButton.textContent = message || 'Copy';
          if (message) {
            window.clearTimeout(shortcodeCopyButton._iohTimer);
            shortcodeCopyButton._iohTimer = window.setTimeout(function(){
              shortcodeCopyButton.textContent = 'Copy';
            }, 2200);
          }
        }

        function fallbackCopyShortcode(){
          if (!shortcodeGenerated) return false;
          shortcodeGenerated.focus();
          shortcodeGenerated.select();
          try {
            return document.execCommand('copy');
          } catch (error) {
            return false;
          }
        }

        if (shortcodeCopyButton) {
          shortcodeCopyButton.addEventListener('click', function(){
            if (!shortcodeGenerated || !shortcodeGenerated.value) return;
            if (navigator.clipboard && navigator.clipboard.writeText) {
              navigator.clipboard.writeText(shortcodeGenerated.value).then(function(){
                setShortcodeCopyStatus('Copied!');
              }).catch(function(){
                setShortcodeCopyStatus(fallbackCopyShortcode() ? 'Copied!' : 'Copy failed');
              });
            } else {
              setShortcodeCopyStatus(fallbackCopyShortcode() ? 'Copied!' : 'Copy failed');
            }
          });
        }
        function setButtonCopyStatus(button, message){
          if (!button) return;
          button.textContent = message || 'Copy';
          if (message) {
            window.clearTimeout(button._iohTimer);
            button._iohTimer = window.setTimeout(function(){
              button.textContent = 'Copy';
            }, 2200);
          }
        }

        function copyFieldValue(field, button){
          if (!field || !field.value) return;
          var fallback = function(){
            field.focus();
            field.select();
            try {
              return document.execCommand('copy');
            } catch (error) {
              return false;
            }
          };
          if (navigator.clipboard && navigator.clipboard.writeText) {
            navigator.clipboard.writeText(field.value).then(function(){
              setButtonCopyStatus(button, 'Copied!');
            }).catch(function(){
              setButtonCopyStatus(button, fallback() ? 'Copied!' : 'Copy failed');
            });
          } else {
            setButtonCopyStatus(button, fallback() ? 'Copied!' : 'Copy failed');
          }
        }

        if (remoteEmbedCopyButton) {
          remoteEmbedCopyButton.addEventListener('click', function(){
            copyFieldValue(remoteEmbedCode, remoteEmbedCopyButton);
          });
        }
        updateShortcodeGenerator();
      })();
    </script>
    <?php
}

function ioh_days(): array {
    return [
        'mon' => 'Monday',
        'tue' => 'Tuesday',
        'wed' => 'Wednesday',
        'thu' => 'Thursday',
        'fri' => 'Friday',
        'sat' => 'Saturday',
        'sun' => 'Sunday',
    ];
}
