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

add_action('template_redirect', function() {
    if (!isset($_GET['ioh_remote_editor'])) return;

    if (!defined('DONOTCACHEPAGE')) define('DONOTCACHEPAGE', true);
    if (!defined('DONOTMINIFY')) define('DONOTMINIFY', true);
    if (!defined('DONOTCDN')) define('DONOTCDN', true);
    if (!defined('DONOTOPTIMIZE')) define('DONOTOPTIMIZE', true);

    status_header(200);
    nocache_headers();
    header('Content-Type: text/html; charset=' . get_bloginfo('charset'));

    $settings_url = rest_url('inception-office-hours/v1/settings');
    $location_url_base = rest_url('inception-office-hours/v1/locations/');
    $image_upload_url = rest_url('inception-office-hours/v1/uploads/image');
    $home_url = home_url('/');
    $site_domain = wp_parse_url(home_url(), PHP_URL_HOST);
    if (!$site_domain) $site_domain = home_url();
    $pages = get_pages(['sort_column' => 'post_title', 'sort_order' => 'ASC']);
    $page_options = array_map(function($page) {
        return [
            'id' => (int)$page->ID,
            'title' => $page->post_title ?: ('Page #' . $page->ID),
            'url' => get_permalink($page),
        ];
    }, $pages);
    ?>
<!doctype html>
<html <?php language_attributes(); ?>>
<head>
  <meta charset="<?php bloginfo('charset'); ?>" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <title>Office Hours Remote Editor</title>
  <!--noptimize--><link rel="stylesheet" data-pagespeed-no-defer data-two-no-delay data-no-optimize="1" href="<?php echo esc_url(IOH_URL . 'assets/remote-editor.css?ver=' . IOH_VERSION); ?>" /><!--/noptimize-->
  <!--noptimize--><style id="ioh-remote-editor-inline-css" data-pagespeed-no-defer data-two-no-delay data-no-optimize="1">
    :root{color-scheme:light; --border:#d7dce2; --text:#17202a; --muted:#5e6b78; --accent:#1d6fb8; --bg:#F2F2F2; --panel:#fff;}
    html,body{background:#F2F2F2!important;}
    *{box-sizing:border-box;}
    [hidden]{display:none!important;}
    body{margin:0!important; background:var(--bg)!important; color:var(--text); font-family:system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif!important; font-size:15px; line-height:1.45;}
    .ioh-remote{max-width:980px; margin:0 auto; padding:18px; font-family:system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif!important;}
    .ioh-remote h1,.ioh-remote h2,.ioh-remote h3,.ioh-remote h4,.ioh-remote h5,.ioh-remote h6,.ioh-remote p,.ioh-remote label,.ioh-remote input,.ioh-remote select,.ioh-remote textarea,.ioh-remote button{font-family:system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif!important;}
    .domain-banner{display:none; margin-bottom:14px; background:#102a43; color:#fff; border-radius:8px; padding:12px 14px; font-weight:700;}
    .domain-banner a{color:#fff; text-decoration:underline; text-underline-offset:3px;}
    .domain-banner.is-visible{display:block;}
    .bar{display:flex; gap:10px; align-items:flex-end; flex-wrap:wrap; background:var(--panel); border:1px solid var(--border); border-radius:8px; padding:14px;}
    label{display:block; font-weight:650; margin:0 0 5px;}
    input, select, textarea{width:100%; border:1px solid var(--border); border-radius:6px; padding:8px 9px; font:inherit; background:#fff; color:var(--text);}
    input[type="checkbox"]{width:auto;}
    button,.ioh-remote button{appearance:none; -webkit-appearance:none; border:1px solid #185f9d!important; border-radius:6px!important; background:var(--accent)!important; background-image:none!important; color:#fff!important; cursor:pointer; font:inherit; font-weight:650!important; font-size:15px!important; line-height:1.25!important; text-transform:none!important; text-decoration:none!important; letter-spacing:0!important; box-shadow:none!important; text-shadow:none!important; padding:9px 13px!important; min-height:0!important; height:auto!important;}
    button.secondary{background:#fff!important; color:var(--accent)!important;}
    button:disabled{opacity:.55; cursor:not-allowed;}
    .toolbar{display:flex; gap:6px; flex-wrap:wrap; align-items:center; margin-top:8px; padding:8px; border:1px solid var(--border); border-radius:6px; background:#f8fafc;}
    .toolbar button{background:#fff!important; color:var(--text)!important; border-color:var(--border)!important; padding:6px 9px!important; min-width:34px;}
    .toolbar button:hover{border-color:var(--accent); color:var(--accent);}
    .field{flex:1 1 220px;}
    .panel{margin-top:14px; background:var(--panel); border:1px solid var(--border); border-radius:8px; padding:14px;}
    .section-tabs{position:relative; display:flex; gap:28px; flex-wrap:wrap; margin:0 0 22px; border-bottom:1px solid var(--border);}
    .ioh-remote .section-tabs button.section-tab,.section-tabs button.section-tab{appearance:none!important; -webkit-appearance:none!important; background:transparent!important; background-image:none!important; color:#334155!important; border:0!important; border-radius:0!important; box-shadow:none!important; text-shadow:none!important; padding:0 0 11px!important; margin:0!important; min-width:0!important; min-height:0!important; width:auto!important; height:auto!important; font-size:13px!important; font-weight:500!important; line-height:1.35!important; text-transform:uppercase!important; letter-spacing:0!important;}
    .ioh-remote .section-tabs button.section-tab.is-active,.section-tabs button.section-tab.is-active{background:transparent!important; color:#006cff!important;}
    .section-tab-indicator{position:absolute; left:0; bottom:-1px; width:0; height:2px; background:#006cff; transition:transform .24s ease, width .24s ease;}
    .section-panel{margin-top:18px; background:var(--panel); border:1px solid var(--border); border-radius:8px; padding:0; overflow:hidden;}
    .section-tabs + .section-panel{margin-top:0;}
    .section-head{display:flex; justify-content:space-between; gap:12px; align-items:flex-start; padding:14px 16px; background:#eef3f8; border-bottom:1px solid var(--border);}
    .section-head h2{margin:0; font-size:18px; line-height:1.25;}
    .section-head p{margin:4px 0 0; color:var(--muted); font-size:13px;}
    .section-body{padding:16px;}
    .blog-section{border:1px solid var(--border); border-radius:8px; padding:12px; margin-top:12px; background:#fbfcfe;}
    .blog-section-grid{display:grid; grid-template-columns:1fr; gap:10px;}
    .blog-editor{min-height:130px; border:1px solid var(--border); border-radius:6px; padding:10px; background:#fff; overflow:auto;}
    .blog-editor:focus{outline:2px solid rgba(29,111,184,.22); border-color:var(--accent);}
    .blog-actions{display:flex; gap:10px; align-items:center; flex-wrap:wrap; margin-top:14px;}
    .blog-image-row{display:flex; gap:12px; align-items:center; flex-wrap:wrap;}
    .blog-image-help{color:var(--muted); font-size:13px;}
    .blog-image-thumb{display:none; width:92px; height:64px; object-fit:cover; border:1px solid var(--border); border-radius:6px; background:#fff;}
    .blog-image-thumb.is-visible{display:block;}
    .schedule-wrap{flex:0 1 0; max-width:0; opacity:0; overflow:hidden; transition:max-width .24s ease, opacity .18s ease; margin:0;}
    .schedule-wrap.is-visible{flex-basis:260px; max-width:260px; opacity:1;}
    .schedule-wrap label{width:260px;}
    .rich-editor{min-height:150px; border:1px solid var(--border); border-radius:6px; padding:10px; background:#fff; margin-top:8px; overflow:auto; text-align:center;}
    .rich-editor:focus{outline:2px solid rgba(29,111,184,.22); border-color:var(--accent);}
    .rich-editor img{max-width:100%; height:auto;}
    .rich-editor img.is-selected{outline:3px solid rgba(29,111,184,.35); outline-offset:3px;}
    .timezone-note{display:inline; color:var(--muted); font-size:12px; font-weight:500; margin-left:4px;}
    .popup-preview-wrap{position:absolute; top:18px; right:18px; z-index:50; width:300px; min-width:80px;}
    .popup-preview-wrap.is-hidden{display:none;}
    .popup-preview-bar{display:flex; align-items:center; justify-content:space-between; gap:8px; margin:0 0 8px; background:rgba(255,255,255,.96); border:1px solid var(--border); border-radius:6px; padding:6px 7px 6px 9px; box-shadow:0 6px 18px rgba(15,23,42,.12); cursor:move; user-select:none;}
    .popup-preview-bar strong{font-size:13px;}
    .popup-preview-bar button{background:#fff!important; color:var(--accent)!important; border-color:var(--border)!important; border-radius:5px!important; padding:2px 8px!important; min-width:30px!important; line-height:1.4!important;}
    .popup-preview-stage{position:relative; overflow:hidden; background:linear-gradient(135deg,#d9e4ef,#f7fafc); border:1px solid var(--border); border-radius:8px; padding:0;}
    .popup-preview-wrap.is-minimized .popup-preview-stage{display:none;}
    .popup-preview-shell{position:absolute; top:24px; left:16px; max-width:none; width:625px; margin:0; background:<?php echo esc_html(ioh_default_popup_banner_color()); ?>; padding:0 5px 5px; box-shadow:0 8px 24px rgba(15,23,42,.18); transform-origin:top left;}
    .popup-preview-close{position:absolute; top:-18px; right:-10px; color:#fff; font-size:34px; font-weight:800; line-height:1; text-shadow:0 1px 3px rgba(0,0,0,.35); pointer-events:none;}
    .popup-preview-scroll{max-height:830px; overflow-y:auto;}
    .popup-preview-banner{background:<?php echo esc_html(ioh_default_popup_banner_color()); ?>; color:#fff; font-family:Arial,Helvetica,sans-serif; font-size:28px; line-height:1.25; font-weight:800; text-align:center; padding:10px 12px 11px; letter-spacing:.01em;}
    .popup-preview-body{background:#fff; color:#444; width:100%; padding:34px 24px 28px;}
    .popup-preview-content{font-family:Arial,Helvetica,sans-serif; font-size:26px; font-weight:400; line-height:1.45; text-align:center;}
    .popup-preview-content p{margin:0 0 10px;}
    .popup-preview-content img{display:block; max-width:58%; height:auto; margin:10px auto 0;}
    .popup-preview-resize{position:absolute; right:0; bottom:0; width:18px; height:18px; cursor:nwse-resize;}
    .popup-preview-resize:before{content:""; position:absolute; right:4px; bottom:4px; width:10px; height:10px; border-right:2px solid rgba(23,32,42,.45); border-bottom:2px solid rgba(23,32,42,.45);}
    .image-tools{display:none; gap:8px; align-items:center; flex-wrap:wrap; margin-top:8px; padding:8px; border:1px solid var(--border); border-radius:6px; background:#fff;}
    .image-tools.is-visible{display:flex; position:absolute; left:18px; top:18px; z-index:55; width:min(430px, calc(100vw - 36px)); box-shadow:0 10px 28px rgba(15,23,42,.18);}
    .image-tools input[type="range"]{width:180px;}
    .image-tools button{background:#fff!important; color:var(--accent)!important; border-color:var(--border)!important; padding:6px 9px!important;}
    .popup-color-field{position:relative; padding-left:0;}
    .popup-color-field input[type="color"]{height:28px; padding:3px; background:var(--popup-swatch-color,#fff); border-color:var(--popup-swatch-color,var(--border)); cursor:pointer;}
    .popup-color-field input[type="color"]::-webkit-color-swatch-wrapper{padding:0;}
    .popup-color-field input[type="color"]::-webkit-color-swatch{border:0; border-radius:3px;}
    .popup-color-field input[type="color"]::-moz-color-swatch{border:0; border-radius:3px;}
    .grid{display:grid; grid-template-columns:150px 110px 150px 1fr; gap:8px 12px; align-items:center;}
    .head{font-weight:700; color:var(--muted); border-bottom:1px solid var(--border); padding-bottom:7px;}
    .range{display:flex; gap:8px; align-items:center; flex-wrap:wrap;}
    .range.is-closed > *{display:none;}
    .day-hours{display:flex; flex-direction:column; gap:8px; align-items:flex-start;}
    .primary-time,.additional-time{display:grid; grid-template-columns:130px max-content 130px; gap:8px; align-items:center; justify-content:start;}
    .additional-time{grid-template-columns:max-content 130px max-content 130px;}
    .additional-label{color:var(--muted); font-size:13px; align-self:center; white-space:nowrap;}
    .message-input{display:none;}
    .range.is-message .day-hours{display:none;}
    .range.is-message .message-input{display:block;}
    .range input{width:130px;}
    .muted{color:var(--muted); font-size:13px;}
    .status{margin-top:10px; min-height:22px;}
    .ok{color:#176b34;}
    .err{color:#9d1c1c;}
    .actions{display:flex; gap:10px; align-items:center; flex-wrap:wrap; margin-top:14px;}
    .modal-backdrop{display:none; position:fixed; inset:0; z-index:999; align-items:center; justify-content:center; padding:20px; background:rgba(15,23,42,.45);}
    .modal-backdrop.is-visible{display:flex;}
    #settingsSuccessModal{align-items:flex-start; padding-top:110px;}
    #blogSuccessModal{align-items:flex-start; padding-top:110px;}
    .modal{width:min(520px, 100%); background:#fff; border:1px solid var(--border); border-radius:8px; box-shadow:0 20px 50px rgba(15,23,42,.22); padding:20px;}
    .modal h2{margin:0 0 8px; font-size:22px;}
    .modal p{margin:0 0 14px; color:var(--muted);}
    .modal-link{word-break:break-word; display:inline-block; font-weight:700;}
    .modal-actions{display:flex; justify-content:flex-end; margin-top:18px;}
    .https-link-row{display:flex; align-items:center; border:1px solid var(--border); border-radius:6px; overflow:hidden; background:#fff;}
    .https-link-prefix{flex:0 0 auto; padding:8px 10px; background:#eef3f8; color:var(--muted); border-right:1px solid var(--border); font-weight:650;}
    .https-link-row input{border:0; border-radius:0; min-width:0;}
    .https-link-row input:focus{outline:none;}
    .processing-overlay{display:none; position:fixed; inset:0; z-index:998; align-items:center; justify-content:center; padding:20px; background:rgba(15,23,42,.28);}
    .processing-overlay.is-visible{display:flex;}
    .processing-card{width:min(360px, 100%); background:#fff; border:1px solid var(--border); border-radius:8px; box-shadow:0 18px 45px rgba(15,23,42,.22); padding:20px; text-align:center;}
    .processing-spinner{width:34px; height:34px; margin:0 auto 12px; border:3px solid #dbe4ee; border-top-color:var(--accent); border-radius:50%; animation:iohSpin .8s linear infinite;}
    .processing-card strong{display:block; font-size:18px; margin-bottom:5px;}
    .processing-card p{margin:0; color:var(--muted); font-size:14px;}
    @keyframes iohSpin{to{transform:rotate(360deg);}}
    textarea{min-height:110px; resize:vertical;}
    @media (max-width:720px){
      .grid{grid-template-columns:1fr;}
      .head{display:none;}
      .day-hours{grid-template-columns:1fr;}
      .primary-time,.additional-time{grid-template-columns:1fr; gap:8px;}
      .range input{width:100%;}
      .popup-preview-wrap{position:static; width:auto; margin-top:18px;}
      .image-tools.is-visible{position:static; width:auto; box-shadow:none;}
      #settingsSuccessModal{padding-top:48px;}
      #blogSuccessModal{padding-top:48px;}
    }
  </style><!--/noptimize-->
</head>
<body>
  <!--noptimize--><style id="ioh-remote-editor-body-css" data-pagespeed-no-defer data-two-no-delay data-no-optimize="1">
<?php
    $ioh_remote_css = IOH_DIR . 'assets/remote-editor.css';
    if (is_readable($ioh_remote_css)) {
        echo file_get_contents($ioh_remote_css); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
    }
?>
  </style><!--/noptimize-->
  <main class="ioh-remote">
    <div id="domainBanner" class="domain-banner">Managing settings for <a href="<?php echo esc_url($home_url); ?>" target="_blank" rel="noopener"><?php echo esc_html($site_domain); ?></a></div>
    <div class="bar" id="apiKeyBar">
      <div class="field">
        <label for="apiKey">API Key</label>
        <input id="apiKey" type="password" autocomplete="off" />
      </div>
      <div>
        <label style="font-weight:500;"><input id="rememberKey" type="checkbox" /> Remember in this browser</label>
        <button id="loadBtn" type="button">Load Hours</button>
      </div>
    </div>
    <div id="status" class="status"></div>
    <div id="errorModal" class="modal-backdrop" role="alertdialog" aria-modal="true" aria-labelledby="errorModalTitle" aria-hidden="true">
      <div class="modal">
        <h2 id="errorModalTitle">Error!</h2>
        <p id="errorModalMessage"></p>
        <div class="modal-actions">
          <button id="errorModalCloseBtn" type="button">Done</button>
        </div>
      </div>
    </div>
    <div id="blogSuccessModal" class="modal-backdrop" role="dialog" aria-modal="true" aria-labelledby="blogSuccessTitle" aria-hidden="true">
      <div class="modal">
        <h2 id="blogSuccessTitle">Blog saved</h2>
        <p id="blogSuccessMessage"></p>
        <div id="blogSuccessLinkWrap" hidden>
          <a id="blogSuccessLink" class="modal-link" href="#" target="_blank" rel="noopener"></a>
        </div>
        <div class="modal-actions">
          <button id="blogSuccessCloseBtn" type="button">Done</button>
        </div>
      </div>
    </div>
    <div id="settingsSuccessModal" class="modal-backdrop" role="dialog" aria-modal="true" aria-labelledby="settingsSuccessTitle" aria-hidden="true">
      <div class="modal">
        <h2 id="settingsSuccessTitle">Changes saved</h2>
        <p id="settingsSuccessMessage"></p>
        <div class="modal-actions">
          <button id="settingsSuccessCloseBtn" type="button">Done</button>
        </div>
      </div>
    </div>
    <div id="blogLinkModal" class="modal-backdrop" role="dialog" aria-modal="true" aria-labelledby="blogLinkTitle" aria-hidden="true">
      <div class="modal">
        <h2 id="blogLinkTitle">Add Link</h2>
        <p>Enter a secure URL for this link.</p>
        <label for="blogLinkPath">Link URL</label>
        <div class="https-link-row">
          <span class="https-link-prefix">https://</span>
          <input id="blogLinkPath" type="text" autocomplete="url" placeholder="www.example.com/page" />
        </div>
        <div class="modal-actions">
          <button id="blogLinkCancelBtn" type="button" class="secondary">Cancel</button>
          <button id="blogLinkApplyBtn" type="button">Add Link</button>
        </div>
      </div>
    </div>
    <div id="blogProcessingOverlay" class="processing-overlay" role="status" aria-live="polite" aria-hidden="true">
      <div class="processing-card">
        <div class="processing-spinner" aria-hidden="true"></div>
        <strong id="blogProcessingTitle">Working on your blog</strong>
        <p id="blogProcessingMessage">Please wait while this finishes.</p>
      </div>
    </div>

    <section id="editor" hidden>
      <div class="section-tabs" role="tablist" aria-label="Editor sections">
        <button class="section-tab is-active" type="button" data-section-tab="popup" role="tab" aria-selected="true">Popup</button>
        <button class="section-tab" type="button" data-section-tab="hours" role="tab" aria-selected="false">Office Hours</button>
        <button class="section-tab" type="button" data-section-tab="blog" role="tab" aria-selected="false">Blog Maker</button>
        <span class="section-tab-indicator" aria-hidden="true"></span>
      </div>

      <div class="section-panel" data-section-panel="popup">
        <div class="section-head">
          <div>
            <h2>Popup</h2>
            <p>Control where your site's popup appears, when it runs, and what it says.</p>
          </div>
        </div>
        <div class="section-body">
        <label for="popupScope">Popup Scope</label>
        <select id="popupScope" style="max-width:260px;">
          <option value="off">Off</option>
          <option value="homepage">Homepage Only</option>
          <option value="sitewide">Sitewide</option>
          <option value="selected_pages">Selected Pages</option>
        </select>
        <div id="popupPagesWrap" style="margin-top:10px;">
              <label for="popupPages">Selected Pages</label>
          <select id="popupPages" multiple size="8"></select>
          <div class="muted" style="margin-top:6px;">Used only when Popup Scope is set to Selected Pages. Hold Ctrl or Cmd to select more than one.</div>
        </div>
        <div id="popupScheduleWrap" style="margin-top:10px;">
          <div class="bar" style="padding:0; border:0; background:transparent;">
            <div class="field">
              <label for="popupScheduleStart">Popup Starts <span class="timezone-note" data-timezone-label></span></label>
              <input id="popupScheduleStart" type="datetime-local" />
            </div>
            <div class="field">
              <label for="popupScheduleEnd">Popup Ends <span class="timezone-note" data-timezone-label></span></label>
              <input id="popupScheduleEnd" type="datetime-local" />
            </div>
          </div>
          <div class="muted" style="margin-top:6px;">Leave either field blank for no start or end limit. Times are converted to the website timezone when saved.</div>
        </div>
        <div id="popupHtmlWrap">
          <div class="bar" style="padding:0; border:0; background:transparent; margin-top:10px;">
            <div class="field">
              <label for="popupTitle">Popup Title</label>
              <input id="popupTitle" type="text" placeholder="Leave blank for no title" />
            </div>
            <div class="field popup-color-field" id="popupBannerColorField">
              <label for="popupBannerColor">Banner Color</label>
              <input id="popupBannerColor" type="color" value="<?php echo esc_attr(ioh_default_popup_banner_color()); ?>" />
            </div>
            <div class="field popup-color-field" id="popupBannerTextColorField">
              <label for="popupBannerTextColor">Banner Text Color</label>
              <input id="popupBannerTextColor" type="color" value="#ffffff" />
            </div>
          </div>
          <label for="popupEditor" style="margin-top:10px;">Popup Content</label>
          <div class="toolbar" aria-label="Popup content formatting">
            <button type="button" data-command="bold"><strong>B</strong></button>
            <button type="button" data-command="italic"><em>I</em></button>
            <button type="button" data-command="underline"><u>U</u></button>
            <select id="popupInlineTextSize" aria-label="Text size" style="width:auto; min-width:92px;">
              <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" data-command="insertUnorderedList">Bullets</button>
            <button type="button" data-command="insertOrderedList">Numbers</button>
            <button type="button" id="linkBtn">Link</button>
            <button type="button" id="imageBtn">Photo</button>
            <button type="button" id="htmlToggleBtn">HTML</button>
          </div>
          <div id="popupEditor" class="rich-editor" contenteditable="true"></div>
          <div id="imageTools" class="image-tools">
            <span class="muted">Selected Photo Size</span>
            <input id="imageWidth" type="range" min="10" max="100" step="5" value="100" />
            <span id="imageWidthLabel" class="muted">100%</span>
            <button type="button" data-image-size="25">25%</button>
            <button type="button" data-image-size="50">50%</button>
            <button type="button" data-image-size="75">75%</button>
            <button type="button" data-image-size="100">100%</button>
          </div>
          <textarea id="popupHtml" style="display:none;"></textarea>
          <input id="imageUpload" type="file" accept="image/jpeg,image/png,image/gif,image/webp" style="display:none;" />
          <div class="muted" style="margin-top:6px;">Use Photo to upload a JPG, PNG, GIF, or WebP image up to 2MB.</div>
        </div>
        <div class="actions">
          <button id="savePopupBtn" type="button">Save Changes</button>
        </div>
        <div id="popupPreviewWrap" class="popup-preview-wrap">
          <div id="popupPreviewBar" class="popup-preview-bar">
            <strong>Popup Preview</strong>
            <button id="popupPreviewMinimize" type="button" aria-label="Minimize popup preview">-</button>
          </div>
          <div class="popup-preview-stage">
            <div id="popupPreviewShell" class="popup-preview-shell">
              <div class="popup-preview-close">&times;</div>
              <div id="popupPreviewScroll" class="popup-preview-scroll">
                <div id="popupPreviewBanner" class="popup-preview-banner">ATTENTION</div>
                <div class="popup-preview-body">
                  <div id="popupPreviewContent" class="popup-preview-content"></div>
                </div>
              </div>
            </div>
          </div>
          <div id="popupPreviewResize" class="popup-preview-resize" aria-hidden="true"></div>
        </div>
        </div>
      </div>

      <div class="section-panel" data-section-panel="hours" hidden>
        <div class="section-head">
          <div>
            <h2>Office Hours</h2>
            <p>Update your weekly business hours.</p>
          </div>
        </div>
        <div class="section-body">
      <div id="locationFields" class="bar" style="padding:0; border:0; background:transparent;">
        <div class="field">
          <label for="location">Location</label>
          <select id="location"></select>
        </div>
        <div class="field">
          <label for="title">Location Title</label>
          <input id="title" type="text" />
        </div>
        <div>
          <label style="font-weight:500;"><input id="makeDefault" type="checkbox" /> Make Default</label>
        </div>
      </div>

      <div style="margin-top:16px;">
        <div class="grid">
          <div class="head">Day</div>
          <div class="head">Closed</div>
          <div class="head">Message</div>
          <div class="head">Hours / Message</div>
          <?php foreach (ioh_days() as $day_key => $day_label): ?>
            <div><strong><?php echo esc_html($day_label); ?></strong></div>
            <div><label style="font-weight:500;"><input type="checkbox" data-day="<?php echo esc_attr($day_key); ?>" data-field="closed" /> Closed</label></div>
            <div><label style="font-weight:500;"><input type="checkbox" data-day="<?php echo esc_attr($day_key); ?>" data-field="use_message" /> Display Message</label></div>
            <div class="range" data-day-details="<?php echo esc_attr($day_key); ?>">
              <div class="day-hours" data-day-hours="<?php echo esc_attr($day_key); ?>">
                <div class="primary-time">
                  <input type="time" data-day="<?php echo esc_attr($day_key); ?>" data-field="r1_start" />
                  <span>to</span>
                  <input type="time" data-day="<?php echo esc_attr($day_key); ?>" data-field="r1_end" />
                </div>
                <div class="additional-time">
                  <span class="additional-label">optional additional times</span>
                  <input type="time" data-day="<?php echo esc_attr($day_key); ?>" data-field="r2_start" />
                  <span>to</span>
                  <input type="time" data-day="<?php echo esc_attr($day_key); ?>" data-field="r2_end" />
                </div>
              </div>
              <input class="message-input" type="text" data-day="<?php echo esc_attr($day_key); ?>" data-field="message" placeholder="Custom message, e.g. By appointment only" style="width:100%;" />
            </div>
          <?php endforeach; ?>
        </div>
      </div>
      <div class="actions">
        <button id="saveBtn" type="button">Save Changes</button>
      </div>
        </div>
      </div>

      <div class="section-panel" data-section-panel="blog" hidden>
        <div class="section-head">
          <div>
            <h2>Blog Maker</h2>
            <p>Preview, schedule, or publish your blog posts from here.</p>
          </div>
        </div>
        <div class="section-body">
          <div class="bar" style="padding:0; border:0; background:transparent;">
            <div class="field">
              <label for="blogTitle">Blog Title</label>
              <input id="blogTitle" type="text" />
            </div>
            <div class="field">
              <label for="blogSlug">Slug</label>
              <input id="blogSlug" type="text" autocomplete="off" />
            </div>
          </div>
          <div class="bar" style="padding:0; border:0; background:transparent; margin-top:12px;">
            <div class="field" hidden>
              <label for="blogCategories">Categories</label>
              <select id="blogCategories" multiple size="6"></select>
            </div>
            <div class="field">
              <label for="blogExcerpt">Meta Description</label>
              <textarea id="blogExcerpt" rows="6"></textarea>
            </div>
          </div>
          <div style="margin-top:12px;">
            <label>Blog Image</label>
            <div class="blog-image-row">
              <button id="blogImageBtn" type="button" class="secondary">Upload Photo</button>
              <span id="blogImageHelp" class="blog-image-help">Use Upload Photo to upload a JPG, PNG, GIF, or WebP image up to 2MB.</span>
              <img id="blogImageThumb" class="blog-image-thumb" alt="Selected blog image preview" />
              <input id="blogImageUpload" type="file" accept="image/jpeg,image/png,image/gif,image/webp" style="display:none;" />
              <input id="blogImageUrl" type="hidden" />
            </div>
          </div>

          <div id="blogSections">
            <div class="blog-section" data-blog-section>
              <div class="blog-section-grid">
                <label>Section Content</label>
                <div class="toolbar" aria-label="Blog content formatting">
                  <button type="button" data-blog-command="bold"><strong>B</strong></button>
                  <button type="button" data-blog-command="italic"><em>I</em></button>
                  <button type="button" data-blog-command="underline"><u>U</u></button>
                  <button type="button" data-blog-command="insertUnorderedList">Bullets</button>
                  <button type="button" data-blog-command="insertOrderedList">Numbers</button>
                  <button type="button" data-blog-plain-text>Plain Text</button>
                  <button type="button" data-blog-link>Link</button>
                </div>
                <div class="blog-editor" contenteditable="true" data-blog-body></div>
              </div>
            </div>
          </div>

          <div class="blog-actions">
            <button id="addBlogSectionBtn" type="button" class="secondary">Add Section</button>
            <button id="previewBlogBtn" type="button" class="secondary">Preview Blog</button>
            <div id="blogScheduleWrap" class="schedule-wrap">
              <label style="margin:0;">
                Schedule Date/Time <span class="timezone-note" data-timezone-label></span>
                <input id="blogScheduleAt" type="datetime-local" style="min-width:220px;" />
              </label>
            </div>
            <button id="scheduleBlogBtn" type="button" class="secondary">Schedule Blog</button>
            <button id="publishBlogBtn" type="button">Publish Blog</button>
          </div>
          <div id="blogStatus" class="status" hidden></div>
        </div>
      </div>
    </section>
  </main>

  <script>
    const settingsUrl = <?php echo wp_json_encode($settings_url); ?>;
    const locationUrlBase = <?php echo wp_json_encode($location_url_base); ?>;
    const imageUploadUrl = <?php echo wp_json_encode($image_upload_url); ?>;
    const blogOptionsUrl = <?php echo wp_json_encode(rest_url('inception-office-hours/v1/blog/options')); ?>;
    const blogPostsUrl = <?php echo wp_json_encode(rest_url('inception-office-hours/v1/blog/posts')); ?>;
    const defaultPopupBannerColor = <?php echo wp_json_encode(ioh_default_popup_banner_color()); ?>;
    const days = <?php echo wp_json_encode(array_keys(ioh_days())); ?>;
    const pages = <?php echo wp_json_encode($page_options); ?>;
    const sectionOrder = ['popup', 'hours', 'blog'];
    let settings = null;
    let selectedImage = null;
    let activeBlogEditor = null;
    let pendingBlogLinkRange = null;
    let blogScheduleVisible = false;
    let blogProcessing = false;
    let parentViewportTop = null;
    let popupPreviewOffsetY = 0;
    let popupPreviewPositioned = false;
    let popupPreviewDrag = null;
    let popupPreviewResize = null;
    let popupPreviewScale = 300 / 657;
    const popupPreviewBaseWidth = 625;
    const popupPreviewStagePaddingX = 32;
    const popupPreviewStagePaddingY = 48;
    const popupPreviewMinHeight = 50;
    const userTimeZone = Intl.DateTimeFormat().resolvedOptions().timeZone || '';
    const defaultSiteTimeZone = 'America/Chicago';

    const $ = (id) => document.getElementById(id);
    const siteTimeZone = () => (settings && settings.site_timezone) || defaultSiteTimeZone;
    const datePartsInZone = (date, timeZone) => {
      const parts = new Intl.DateTimeFormat('en-US', {
        timeZone,
        year: 'numeric',
        month: '2-digit',
        day: '2-digit',
        hour: '2-digit',
        minute: '2-digit',
        hourCycle: 'h23'
      }).formatToParts(date).reduce((out, part) => {
        out[part.type] = part.value;
        return out;
      }, {});
      return {
        year: Number(parts.year),
        month: Number(parts.month),
        day: Number(parts.day),
        hour: Number(parts.hour),
        minute: Number(parts.minute)
      };
    };
    const formatDateTimeInZone = (date, timeZone) => {
      if (!date || Number.isNaN(date.getTime()) || !timeZone) return '';
      const p = datePartsInZone(date, timeZone);
      return String(p.year).padStart(4, '0') + '-' + String(p.month).padStart(2, '0') + '-' + String(p.day).padStart(2, '0') + 'T' + String(p.hour).padStart(2, '0') + ':' + String(p.minute).padStart(2, '0');
    };
    const parseDateTimeValue = (value) => {
      const match = String(value || '').match(/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2})$/);
      if (!match) return null;
      return {
        year: Number(match[1]),
        month: Number(match[2]),
        day: Number(match[3]),
        hour: Number(match[4]),
        minute: Number(match[5])
      };
    };
    const wallTimeInZoneToDate = (value, timeZone) => {
      const wanted = parseDateTimeValue(value);
      if (!wanted || !timeZone) return null;
      let date = new Date(Date.UTC(wanted.year, wanted.month - 1, wanted.day, wanted.hour, wanted.minute));
      for (let i = 0; i < 3; i++) {
        const actual = datePartsInZone(date, timeZone);
        const wantedUtc = Date.UTC(wanted.year, wanted.month - 1, wanted.day, wanted.hour, wanted.minute);
        const actualUtc = Date.UTC(actual.year, actual.month - 1, actual.day, actual.hour, actual.minute);
        date = new Date(date.getTime() + wantedUtc - actualUtc);
      }
      return date;
    };
    const siteDateTimeToUserInput = (value) => {
      if (!value || !userTimeZone) return value || '';
      const date = wallTimeInZoneToDate(value, siteTimeZone());
      return date ? formatDateTimeInZone(date, userTimeZone) : value;
    };
    const userInputToSiteDateTime = (value) => {
      if (!value || !userTimeZone) return value || '';
      const date = wallTimeInZoneToDate(value, userTimeZone);
      return date ? formatDateTimeInZone(date, siteTimeZone()) : value;
    };
    const updateTimezoneLabels = () => {
      const label = userTimeZone ? userTimeZone.replace(/_/g, ' ') : 'Local Time';
      document.querySelectorAll('[data-timezone-label]').forEach((node) => {
        node.textContent = '(' + label + ')';
      });
    };
    const showErrorModal = (message) => {
      if (!message) return;
      $('errorModalMessage').textContent = message;
      $('errorModal').classList.add('is-visible');
      $('errorModal').setAttribute('aria-hidden', 'false');
      $('errorModalCloseBtn').focus();
    };
    const hideErrorModal = () => {
      $('errorModal').classList.remove('is-visible');
      $('errorModal').setAttribute('aria-hidden', 'true');
    };
    const status = (message, ok = true) => {
      $('status').textContent = ok ? message : '';
      $('status').className = ok ? 'status ok' : 'status err';
      if (!ok) showErrorModal(message);
    };
    const showSettingsSuccessModal = (section) => {
      const sectionName = section === 'popup' ? 'Popup' : 'Office Hours';
      $('settingsSuccessTitle').textContent = sectionName + ' saved';
      $('settingsSuccessMessage').textContent = 'Your changes were successfully saved.';
      $('settingsSuccessModal').classList.add('is-visible');
      $('settingsSuccessModal').setAttribute('aria-hidden', 'false');
      $('settingsSuccessCloseBtn').focus();
      window.clearTimeout(window.iohSettingsSuccessTimer);
      window.iohSettingsSuccessTimer = window.setTimeout(hideSettingsSuccessModal, 3000);
    };
    const hideSettingsSuccessModal = () => {
      window.clearTimeout(window.iohSettingsSuccessTimer);
      $('settingsSuccessModal').classList.remove('is-visible');
      $('settingsSuccessModal').setAttribute('aria-hidden', 'true');
    };
    const blogStatus = (message, ok = true) => {
      $('blogStatus').textContent = '';
      $('blogStatus').className = ok ? 'status ok' : 'status err';
      if (!ok) showErrorModal(message);
    };
    const blogStatusWithLink = (message, url, ok = true) => {
      $('blogStatus').textContent = '';
      $('blogStatus').className = ok ? 'status ok' : 'status err';
      if (!ok) showErrorModal(message);
      if (!url) return;
    };
    let blogLinkResolver = null;
    const cleanHttpsLinkPath = (value) => String(value || '')
      .trim()
      .replace(/^https?:\/\//i, '')
      .replace(/^\/+/, '');
    const hideBlogLinkModal = (value = '') => {
      $('blogLinkModal').classList.remove('is-visible');
      $('blogLinkModal').setAttribute('aria-hidden', 'true');
      if (blogLinkResolver) {
        blogLinkResolver(value);
        blogLinkResolver = null;
      }
    };
    const requestHttpsBlogLink = () => new Promise((resolve) => {
      blogLinkResolver = resolve;
      $('blogLinkPath').value = '';
      $('blogLinkModal').classList.add('is-visible');
      $('blogLinkModal').setAttribute('aria-hidden', 'false');
      window.setTimeout(() => $('blogLinkPath').focus(), 0);
    });
    const applyHttpsBlogLink = () => {
      const path = cleanHttpsLinkPath($('blogLinkPath').value);
      if (!path) {
        showErrorModal('Enter the rest of the URL after https://.');
        $('blogLinkPath').focus();
        return;
      }
      hideBlogLinkModal('https://' + path);
    };
    const blogProcessingText = (mode) => {
      if (mode === 'preview') return {
        title: 'Creating preview',
        message: 'Opening the blog preview as soon as it is ready.'
      };
      if (mode === 'schedule') return {
        title: 'Scheduling blog',
        message: 'Saving the scheduled publish time now.'
      };
      return {
        title: 'Publishing blog',
        message: 'Publishing the blog post now.'
      };
    };
    const setBlogActionButtonsDisabled = (disabled) => {
      ['previewBlogBtn', 'scheduleBlogBtn', 'publishBlogBtn', 'addBlogSectionBtn'].forEach((id) => {
        if ($(id)) $(id).disabled = disabled;
      });
    };
    const showBlogProcessingOverlay = (mode) => {
      const text = blogProcessingText(mode);
      $('blogProcessingTitle').textContent = text.title;
      $('blogProcessingMessage').textContent = text.message;
      $('blogProcessingOverlay').classList.add('is-visible');
      $('blogProcessingOverlay').setAttribute('aria-hidden', 'false');
      setBlogActionButtonsDisabled(true);
      blogProcessing = true;
    };
    const hideBlogProcessingOverlay = () => {
      $('blogProcessingOverlay').classList.remove('is-visible');
      $('blogProcessingOverlay').setAttribute('aria-hidden', 'true');
      setBlogActionButtonsDisabled(false);
      blogProcessing = false;
    };
    const showBlogSuccessModal = ({mode, url, scheduledAt}) => {
      $('blogSuccessTitle').textContent = mode === 'publish' ? 'Blog published' : 'Blog scheduled';
      $('blogSuccessMessage').textContent = mode === 'publish'
        ? 'Your blog was successfully published.'
        : 'Your blog was successfully scheduled for ' + scheduledAt + '.';
      if (mode === 'publish' && url) {
        $('blogSuccessLink').href = url;
        $('blogSuccessLink').textContent = url;
        $('blogSuccessLinkWrap').hidden = false;
      } else {
        $('blogSuccessLinkWrap').hidden = true;
      }
      $('blogSuccessModal').classList.add('is-visible');
      $('blogSuccessModal').setAttribute('aria-hidden', 'false');
      $('blogSuccessCloseBtn').focus();
    };
    const hideBlogSuccessModal = () => {
      $('blogSuccessModal').classList.remove('is-visible');
      $('blogSuccessModal').setAttribute('aria-hidden', 'true');
    };
    const formatScheduleDateTime = (value) => {
      if (!value) return '';
      const parsed = new Date(value);
      if (Number.isNaN(parsed.getTime())) return value.replace('T', ' ');
      return parsed.toLocaleString([], {
        year: 'numeric',
        month: 'short',
        day: 'numeric',
        hour: 'numeric',
        minute: '2-digit'
      }) + (userTimeZone ? ' ' + userTimeZone.replace(/_/g, ' ') : '');
    };
    const key = () => $('apiKey').value.trim();

    const request = async (url, options = {}) => {
      const isGet = !options.method || String(options.method).toUpperCase() === 'GET';
      const requestUrl = isGet ? url + (url.includes('?') ? '&' : '?') + '_ioh=' + Date.now() : url;
      const response = await fetch(requestUrl, {
        ...options,
        cache: 'no-store',
        headers: {
          'X-IOH-API-Key': key(),
          'Content-Type': 'application/json',
          ...(options.headers || {})
        }
      });
      const data = await response.json().catch(() => ({}));
      if (!response.ok) throw new Error(data.message || 'Request failed.');
      return data;
    };

    const sendFrameHeight = () => {
      const height = Math.max(
        1000,
        document.documentElement.scrollHeight,
        document.body ? document.body.scrollHeight : 0
      );
      window.parent.postMessage({type: 'ioh-frame-height', height}, '*');
    };
    const queueFrameHeight = () => {
      window.requestAnimationFrame(sendFrameHeight);
    };
    const requestParentScrollTop = () => {
      window.parent.postMessage({type: 'ioh-scroll-top'}, '*');
      window.scrollTo({top: 0, behavior: 'smooth'});
    };

    const uploadImage = async (file) => {
      if (!file) return null;
      if (file.size > 2 * 1024 * 1024) throw new Error('Image uploads are limited to 2MB.');
      if (!['image/jpeg', 'image/png', 'image/gif', 'image/webp'].includes(file.type)) {
        throw new Error('Only JPG, PNG, GIF, and WebP images are allowed.');
      }

      const form = new FormData();
      form.append('file', file);
      const response = await fetch(imageUploadUrl, {
        method: 'POST',
        headers: {'X-IOH-API-Key': key()},
        body: form
      });
      const data = await response.json().catch(() => ({}));
      if (!response.ok) throw new Error(data.message || 'Image upload failed.');
      return data;
    };

    const currentSlug = () => $('location').value;
    const currentLocation = () => settings.locations[currentSlug()];
    const sanitizeBlogSlug = (value, final = false) => {
      let slug = String(value || '')
      .toLowerCase()
      .replace(/[^0-9a-z-]+/g, '-')
      .replace(/^-+/g, '');
      if (final) slug = slug.replace(/-+$/g, '');
      return slug;
    };

    const popupHasExpired = (popup) => {
      const end = popup && popup.schedule_end ? String(popup.schedule_end) : '';
      const siteNow = settings && settings.site_datetime ? String(settings.site_datetime) : '';
      return end !== '' && siteNow !== '' && end < siteNow;
    };
    const clearPastSiteDateTime = (value) => {
      const siteNow = settings && settings.site_datetime ? String(settings.site_datetime) : '';
      return value !== '' && siteNow !== '' && value < siteNow ? '' : value;
    };

    const renderLocationOptions = (preferredSlug = '') => {
      $('location').innerHTML = '';
      Object.entries(settings.locations || {}).forEach(([slug, loc]) => {
        const option = document.createElement('option');
        option.value = slug;
        option.textContent = `${loc.name || slug} (${slug})`;
        $('location').appendChild(option);
      });
      const slugs = Object.keys(settings.locations || {});
      $('location').value = slugs.includes(preferredSlug) ? preferredSlug : (settings.default_location || slugs[0] || '');
      $('locationFields').hidden = slugs.length <= 1;
    };

    const renderPageOptions = () => {
      $('popupPages').innerHTML = '';
      pages.forEach((page) => {
        const option = document.createElement('option');
        option.value = String(page.id);
        option.textContent = page.title + (page.url ? ' - ' + page.url : '');
        $('popupPages').appendChild(option);
      });
    };

    const loadBlogOptions = async () => {
      const data = await request(blogOptionsUrl);
      $('blogCategories').innerHTML = '';
      let selectedAny = false;
      (data.categories || []).forEach((category) => {
        const option = document.createElement('option');
        option.value = String(category.id);
        option.textContent = category.name;
        option.selected = String(category.name || '').toLowerCase() === 'uncategorized';
        if (option.selected) selectedAny = true;
        $('blogCategories').appendChild(option);
      });
      if (!selectedAny && $('blogCategories').options.length) $('blogCategories').options[0].selected = true;
    };

    const cleanBlogEditorNode = (root) => {
      if (!root) return;
      root.querySelectorAll('font').forEach((node) => {
        const span = document.createElement('span');
        span.innerHTML = node.innerHTML;
        node.replaceWith(span);
      });
      root.querySelectorAll('[style]').forEach((node) => {
        node.removeAttribute('style');
      });
      root.querySelectorAll('[class]').forEach((node) => {
        node.removeAttribute('class');
      });
    };

    const saveBlogEditorSelection = (editor) => {
      const selection = window.getSelection();
      if (!editor || !selection || !selection.rangeCount) return null;
      const range = selection.getRangeAt(0);
      if (!editor.contains(range.commonAncestorContainer)) return null;
      return range.cloneRange();
    };

    const restoreBlogEditorSelection = (editor, range) => {
      if (!editor || !range) return false;
      editor.focus();
      const selection = window.getSelection();
      if (!selection) return false;
      selection.removeAllRanges();
      selection.addRange(range);
      return true;
    };

    const insertPlainTextAtSelection = (text) => {
      const safeText = String(text || '').replace(/\r\n/g, '\n');
      if (document.queryCommandSupported && document.queryCommandSupported('insertText')) {
        document.execCommand('insertText', false, safeText);
        return;
      }
      const selection = window.getSelection();
      if (!selection || !selection.rangeCount) return;
      const range = selection.getRangeAt(0);
      range.deleteContents();
      range.insertNode(document.createTextNode(safeText));
      range.collapse(false);
    };

    const setBlogEditorPlainTextMode = (editor) => {
      if (!editor) return;
      editor.focus();
      document.execCommand('removeFormat', false, null);
      if (document.queryCommandState('insertUnorderedList')) document.execCommand('insertUnorderedList', false, null);
      if (document.queryCommandState('insertOrderedList')) document.execCommand('insertOrderedList', false, null);
      document.execCommand('formatBlock', false, 'p');
      cleanBlogEditorNode(editor);
    };

    const wireBlogSection = (section) => {
      const editor = section.querySelector('[data-blog-body]');
      if (editor) {
        editor.addEventListener('focus', () => { activeBlogEditor = editor; });
        editor.addEventListener('click', () => { activeBlogEditor = editor; });
        editor.addEventListener('keyup', () => { activeBlogEditor = editor; });
        editor.addEventListener('paste', (event) => {
          const files = Array.from((event.clipboardData && event.clipboardData.files) || []);
          const html = event.clipboardData ? event.clipboardData.getData('text/html') : '';
          if (files.some((file) => String(file.type || '').startsWith('image/')) || /<img[\s>]/i.test(html)) {
            event.preventDefault();
            blogStatus('Images cannot be pasted into blog section content. If you want more complex blogs, please contact us.', false);
            return;
          }
          const text = event.clipboardData ? event.clipboardData.getData('text/plain') : '';
          if (text) {
            event.preventDefault();
            insertPlainTextAtSelection(text);
          }
        });
        editor.addEventListener('keydown', (event) => {
          if (event.key !== 'Enter') return;
          const selection = window.getSelection();
          if (!selection || !selection.anchorNode || !editor.contains(selection.anchorNode)) return;
          const listItem = selection.anchorNode.nodeType === 1
            ? selection.anchorNode.closest('li')
            : selection.anchorNode.parentElement && selection.anchorNode.parentElement.closest('li');
          if (!listItem || String(listItem.textContent || '').trim() !== '') return;
          event.preventDefault();
          if (document.queryCommandState('insertUnorderedList')) document.execCommand('insertUnorderedList', false, null);
          if (document.queryCommandState('insertOrderedList')) document.execCommand('insertOrderedList', false, null);
          document.execCommand('formatBlock', false, 'p');
        });
        editor.addEventListener('drop', (event) => {
          const files = Array.from((event.dataTransfer && event.dataTransfer.files) || []);
          if (files.some((file) => String(file.type || '').startsWith('image/'))) {
            event.preventDefault();
            blogStatus('Images cannot be dropped into blog section content. If you want more complex blogs, please contact us.', false);
          }
        });
        editor.addEventListener('input', () => {
          const images = editor.querySelectorAll('img');
          if (images.length) {
            images.forEach((image) => image.remove());
            blogStatus('Images cannot be added to blog section content. If you want more complex blogs, please contact us.', false);
          }
          cleanBlogEditorNode(editor);
        });
      }
      section.querySelectorAll('[data-blog-command]').forEach((button) => {
        button.addEventListener('click', () => {
          activeBlogEditor = editor;
          if (activeBlogEditor) activeBlogEditor.focus();
          document.execCommand(button.dataset.blogCommand, false, null);
          cleanBlogEditorNode(activeBlogEditor);
        });
      });
      section.querySelectorAll('[data-blog-plain-text]').forEach((button) => {
        button.addEventListener('click', () => {
          activeBlogEditor = editor;
          setBlogEditorPlainTextMode(activeBlogEditor);
        });
      });
      section.querySelectorAll('[data-blog-link]').forEach((button) => {
        button.addEventListener('click', async () => {
          activeBlogEditor = editor;
          pendingBlogLinkRange = saveBlogEditorSelection(activeBlogEditor);
          const url = await requestHttpsBlogLink();
          if (!url) {
            pendingBlogLinkRange = null;
            return;
          }
          restoreBlogEditorSelection(activeBlogEditor, pendingBlogLinkRange);
          document.execCommand('createLink', false, url);
          pendingBlogLinkRange = null;
        });
      });
    };

    const addBlogSection = () => {
      const first = document.querySelector('[data-blog-section]');
      const clone = first.cloneNode(true);
      clone.querySelectorAll('input').forEach((input) => { input.value = ''; });
      clone.querySelectorAll('[data-blog-body]').forEach((body) => { body.innerHTML = ''; });
      if (!clone.querySelector('[data-blog-heading]')) {
        const headingLabel = document.createElement('label');
        headingLabel.textContent = 'Section Heading';
        const headingInput = document.createElement('input');
        headingInput.type = 'text';
        headingInput.setAttribute('data-blog-heading', '');
        headingLabel.appendChild(headingInput);
        clone.querySelector('.blog-section-grid').prepend(headingLabel);
      }
      $('blogSections').appendChild(clone);
      wireBlogSection(clone);
      queueFrameHeight();
    };

    const resetBlogMaker = () => {
      $('blogTitle').value = '';
      $('blogSlug').value = '';
      $('blogExcerpt').value = '';
      $('blogImageUrl').value = '';
      $('blogImageThumb').removeAttribute('src');
      $('blogImageThumb').classList.remove('is-visible');
      $('blogImageHelp').hidden = false;
      $('blogScheduleAt').value = '';
      setBlogScheduleVisible(false);
      activeBlogEditor = null;

      const sections = Array.from(document.querySelectorAll('[data-blog-section]'));
      sections.slice(1).forEach((section) => section.remove());
      const first = document.querySelector('[data-blog-section]');
      if (first) {
        first.querySelectorAll('input').forEach((input) => { input.value = ''; });
        first.querySelectorAll('[data-blog-body]').forEach((body) => { body.innerHTML = ''; });
      }

      Array.from($('blogCategories').options).forEach((option) => {
        option.selected = String(option.textContent || '').toLowerCase() === 'uncategorized';
      });
      if (!$('blogCategories').selectedOptions.length && $('blogCategories').options.length) {
        $('blogCategories').options[0].selected = true;
      }
      queueFrameHeight();
    };

    const collectBlogPayload = (mode) => ({
      mode,
      title: $('blogTitle').value,
      slug: sanitizeBlogSlug($('blogSlug').value, true),
      excerpt: $('blogExcerpt').value,
      image_url: $('blogImageUrl').value,
      scheduled_at: mode === 'schedule' ? userInputToSiteDateTime($('blogScheduleAt').value) : '',
      category_ids: Array.from($('blogCategories').selectedOptions).map((option) => Number(option.value)),
      sections: Array.from(document.querySelectorAll('[data-blog-section]')).map((section) => ({
        heading: (section.querySelector('[data-blog-heading]') || {}).value || '',
        body: (section.querySelector('[data-blog-body]') || {}).innerHTML || ''
      }))
    });

    const saveBlog = async (mode) => {
      if (blogProcessing) return;
      showBlogProcessingOverlay(mode);
      $('blogSlug').value = sanitizeBlogSlug($('blogSlug').value, true);
      const scheduledAt = $('blogScheduleAt').value;
      try {
        const data = await request(blogPostsUrl, {
          method: 'POST',
          body: JSON.stringify(collectBlogPayload(mode))
        });
        if (mode === 'preview' && data.preview_url) {
          window.open(data.preview_url, '_blank', 'noopener');
          return;
        }
        const link = data.permalink || data.preview_url || '';
        const formattedSchedule = formatScheduleDateTime(scheduledAt);
        resetBlogMaker();
        requestParentScrollTop();
        window.setTimeout(() => {
          showBlogSuccessModal({
            mode,
            url: link,
            scheduledAt: formattedSchedule
          });
        }, mode === 'publish' ? 350 : 0);
      } finally {
        hideBlogProcessingOverlay();
      }
    };

    const setBlogScheduleVisible = (visible) => {
      blogScheduleVisible = !!visible;
      $('blogScheduleWrap').classList.toggle('is-visible', blogScheduleVisible);
      $('scheduleBlogBtn').classList.toggle('secondary', !blogScheduleVisible);
      $('publishBlogBtn').classList.toggle('secondary', blogScheduleVisible);
    };

    const switchSection = (section) => {
      const allowed = allowedSections();
      if (!allowed.includes(section)) section = firstAllowedSection();
      applyRemoteSectionVisibility();
      document.querySelectorAll('[data-section-tab]').forEach((button) => {
        const active = button.dataset.sectionTab === section;
        button.classList.toggle('is-active', active);
        button.setAttribute('aria-selected', active ? 'true' : 'false');
      });
      document.querySelectorAll('[data-section-panel]').forEach((panel) => {
        panel.hidden = panel.dataset.sectionPanel !== section;
      });
      updateSectionTabIndicator();
      queueFrameHeight();
    };

    const updateSectionTabIndicator = () => {
      const active = document.querySelector('[data-section-tab].is-active');
      const indicator = document.querySelector('.section-tab-indicator');
      const tabs = document.querySelector('.section-tabs');
      if (!active || !indicator || !tabs) return;
      const activeRect = active.getBoundingClientRect();
      const tabsRect = tabs.getBoundingClientRect();
      indicator.style.width = activeRect.width + 'px';
      indicator.style.transform = 'translateX(' + (activeRect.left - tabsRect.left) + 'px)';
    };

    const iframeViewportTop = () => {
      if (typeof parentViewportTop === 'number') return Math.max(18, parentViewportTop);
      try {
        if (window.frameElement) {
          return Math.max(18, 18 - window.frameElement.getBoundingClientRect().top);
        }
      } catch (e) {}
      return 18;
    };

    const syncFloatingControls = () => {
      if (window.matchMedia('(max-width:720px)').matches) {
        $('popupPreviewWrap').style.top = '';
        $('popupPreviewWrap').style.left = '';
        $('popupPreviewWrap').style.right = '';
        $('imageTools').style.top = '';
        return;
      }

      const top = iframeViewportTop();
      const docHeight = Math.max(document.documentElement.scrollHeight, document.body.scrollHeight);
      [$('popupPreviewWrap'), $('imageTools')].forEach((node) => {
        if (!node || node.classList.contains('is-hidden') || !node.classList.contains('is-visible') && node.id === 'imageTools') return;
        const height = node.offsetHeight || 0;
        const maxTop = Math.max(18, docHeight - height - 18);
        if (node.id === 'popupPreviewWrap') {
          if (!popupPreviewPositioned) {
            const width = node.offsetWidth || 420;
            node.style.left = Math.max(18, document.documentElement.clientWidth - width - 18) + 'px';
            node.style.right = 'auto';
            node.style.top = iframeViewportTop() + 'px';
            popupPreviewOffsetY = 0;
            popupPreviewPositioned = true;
          }
          node.style.top = Math.min(top + popupPreviewOffsetY, maxTop) + 'px';
        } else {
          node.style.top = Math.min(top, maxTop) + 'px';
        }
      });
    };

    const clampPopupPreview = () => {
      const node = $('popupPreviewWrap');
      if (!node || window.matchMedia('(max-width:720px)').matches) return;
      const width = node.offsetWidth || 0;
      const left = Number.parseFloat(node.style.left || '0');
      const maxLeft = Math.max(18, document.documentElement.clientWidth - width - 18);
      node.style.left = Math.min(Math.max(18, left), maxLeft) + 'px';
      const top = Number.parseFloat(node.style.top || '18');
      popupPreviewOffsetY = Math.max(0, top - iframeViewportTop());
    };

    const popupPreviewNaturalHeight = () => {
      const shell = $('popupPreviewShell');
      if (!shell) return 1;
      if (shell.offsetParent === null) return 1;
      return Math.max(1, shell.scrollHeight || shell.offsetHeight || 1);
    };

    const applyPopupPreviewScale = (force = false) => {
      const shell = $('popupPreviewShell');
      const stage = document.querySelector('.popup-preview-stage');
      const wrap = $('popupPreviewWrap');
      if (!shell || !stage || !wrap) return;

      const naturalHeight = popupPreviewNaturalHeight();
      if (naturalHeight < 40) return;
      const minScale = 0.02;
      const maxScale = Math.max(minScale, (document.documentElement.clientWidth - 36) / (popupPreviewBaseWidth + popupPreviewStagePaddingX));
      popupPreviewScale = Math.min(Math.max(popupPreviewScale, minScale), maxScale);

      shell.style.transform = 'scale(' + popupPreviewScale + ')';
      shell.style.left = (16 * popupPreviewScale) + 'px';
      shell.style.top = (24 * popupPreviewScale) + 'px';
      stage.style.width = ((popupPreviewBaseWidth + popupPreviewStagePaddingX) * popupPreviewScale) + 'px';
      stage.style.height = Math.max(popupPreviewMinHeight, (naturalHeight + popupPreviewStagePaddingY) * popupPreviewScale) + 'px';
      wrap.style.width = stage.style.width;
      clampPopupPreview();
      syncFloatingControls();
    };

    const refreshPopupPreviewLayout = () => {
      const wrap = $('popupPreviewWrap');
      if (!wrap || wrap.classList.contains('is-hidden')) return;
      window.requestAnimationFrame(() => {
        applyPopupPreviewScale(true);
        window.requestAnimationFrame(() => {
          applyPopupPreviewScale(true);
          queueFrameHeight();
        });
      });
    };

    const startFloatingControlTracker = () => {
      const tick = () => {
        syncFloatingControls();
        window.requestAnimationFrame(tick);
      };
      window.requestAnimationFrame(tick);
    };

    window.addEventListener('message', (event) => {
      const data = event.data || {};
      if (!data || data.type !== 'ioh-parent-viewport') return;
      const top = Number(data.top);
      parentViewportTop = Number.isFinite(top) ? top : null;
      syncFloatingControls();
    });

    const startPopupPreviewDrag = (event) => {
      if (event.target && event.target.closest('button')) return;
      if (window.matchMedia('(max-width:720px)').matches) return;
      const node = $('popupPreviewWrap');
      const rect = node.getBoundingClientRect();
      popupPreviewDrag = {
        pointerId: event.pointerId,
        startX: event.clientX,
        startY: event.clientY,
        left: rect.left,
        top: Number.parseFloat(node.style.top || '18')
      };
      node.style.left = rect.left + 'px';
      node.style.right = 'auto';
      popupPreviewPositioned = true;
      $('popupPreviewBar').setPointerCapture(event.pointerId);
      event.preventDefault();
    };

    const startPopupPreviewResize = (event) => {
      if (window.matchMedia('(max-width:720px)').matches) return;
      const node = $('popupPreviewWrap');
      popupPreviewResize = {
        pointerId: event.pointerId,
        startX: event.clientX,
        startY: event.clientY,
        scale: popupPreviewScale
      };
      $('popupPreviewResize').setPointerCapture(event.pointerId);
      event.preventDefault();
    };

    const movePopupPreviewPointer = (event) => {
      if (popupPreviewDrag && event.pointerId === popupPreviewDrag.pointerId) {
        const node = $('popupPreviewWrap');
        const width = node.offsetWidth || 0;
        const maxLeft = Math.max(18, document.documentElement.clientWidth - width - 18);
        const nextLeft = Math.min(Math.max(18, popupPreviewDrag.left + event.clientX - popupPreviewDrag.startX), maxLeft);
        const nextTop = Math.max(18, popupPreviewDrag.top + event.clientY - popupPreviewDrag.startY);
        node.style.left = nextLeft + 'px';
        node.style.top = nextTop + 'px';
        popupPreviewOffsetY = Math.max(0, nextTop - iframeViewportTop());
      }

      if (popupPreviewResize && event.pointerId === popupPreviewResize.pointerId) {
        const delta = Math.abs(event.clientX - popupPreviewResize.startX) > Math.abs(event.clientY - popupPreviewResize.startY)
          ? event.clientX - popupPreviewResize.startX
          : event.clientY - popupPreviewResize.startY;
        popupPreviewScale = popupPreviewResize.scale + (delta / popupPreviewBaseWidth);
        applyPopupPreviewScale();
      }
    };

    const endPopupPreviewPointer = (event) => {
      if (popupPreviewDrag && event.pointerId === popupPreviewDrag.pointerId) popupPreviewDrag = null;
      if (popupPreviewResize && event.pointerId === popupPreviewResize.pointerId) popupPreviewResize = null;
    };

    const setPopupPagesVisibility = () => {
      $('popupPagesWrap').style.display = $('popupScope').value === 'selected_pages' ? 'block' : 'none';
      $('popupScheduleWrap').style.display = $('popupScope').value === 'off' ? 'none' : 'block';
      $('popupHtmlWrap').style.display = $('popupScope').value === 'off' ? 'none' : 'block';
      updatePopupPreviewVisibility();
    };

    const remoteSectionConfig = () => {
      const config = settings && settings.remote_editor ? settings.remote_editor : {};
      return {
        popup: config.show_popup !== 0 && config.show_popup !== '0' && config.show_popup !== false,
        hours: config.show_hours !== 0 && config.show_hours !== '0' && config.show_hours !== false,
        blog: config.show_blog !== 0 && config.show_blog !== '0' && config.show_blog !== false
      };
    };

    const allowedSections = () => {
      const config = remoteSectionConfig();
      const allowed = sectionOrder.filter((section) => config[section]);
      return allowed.length ? allowed : sectionOrder.slice();
    };

    const isRemoteSectionAllowed = (section) => allowedSections().includes(section);

    const firstAllowedSection = () => allowedSections()[0] || 'popup';

    const applyRemoteSectionVisibility = () => {
      const allowed = new Set(allowedSections());
      document.querySelectorAll('[data-section-tab]').forEach((button) => {
        button.hidden = !allowed.has(button.dataset.sectionTab);
      });
      document.querySelectorAll('[data-section-panel]').forEach((panel) => {
        if (!allowed.has(panel.dataset.sectionPanel)) panel.hidden = true;
      });
      updatePopupPreviewVisibility();
      updateSectionTabIndicator();
      queueFrameHeight();
    };

    const updatePopupPreviewVisibility = () => {
      const wrap = $('popupPreviewWrap');
      const shouldHide = !isRemoteSectionAllowed('popup') || $('popupScope').value === 'off';
      const wasHidden = wrap.classList.contains('is-hidden');
      wrap.classList.toggle('is-hidden', shouldHide);
      syncFloatingControls();
      if (wasHidden && !shouldHide) refreshPopupPreviewLayout();
    };

    const syncHtmlFromEditor = () => {
      if ($('popupHtml').style.display === 'none') {
        const clone = $('popupEditor').cloneNode(true);
        clone.querySelectorAll('.is-selected').forEach((node) => node.classList.remove('is-selected'));
        $('popupHtml').value = clone.innerHTML;
      }
      updatePopupPreview();
    };

    const syncEditorFromHtml = () => {
      $('popupEditor').innerHTML = $('popupHtml').value || '';
      selectedImage = null;
      updateImageTools();
      updatePopupPreview();
    };

    const updatePopupPreview = () => {
      const title = $('popupTitle').value.trim();
      const bannerColor = $('popupBannerColor').value || defaultPopupBannerColor || '#19395f';
      const bannerTextColor = $('popupBannerTextColor').value || '#ffffff';
      $('popupBannerColorField').style.setProperty('--popup-swatch-color', bannerColor);
      $('popupBannerColor').style.borderColor = bannerColor;
      $('popupBannerColor').style.backgroundColor = bannerColor;
      $('popupBannerTextColorField').style.setProperty('--popup-swatch-color', bannerTextColor);
      $('popupBannerTextColor').style.borderColor = bannerTextColor;
      $('popupBannerTextColor').style.backgroundColor = bannerTextColor;
      updatePopupPreviewVisibility();
      $('popupPreviewShell').style.background = bannerColor;
      $('popupPreviewShell').style.padding = title ? '0 5px 5px' : '5px';
      $('popupPreviewBanner').style.background = bannerColor;
      $('popupPreviewBanner').style.color = bannerTextColor;
      $('popupPreviewBanner').textContent = title;
      $('popupPreviewBanner').style.display = title ? 'block' : 'none';
      $('popupPreviewContent').innerHTML = $('popupHtml').value || '<span style="color:#7a8794;">Popup content preview will appear here.</span>';
      applyPopupPreviewScale();
    };

    const focusEditor = () => {
      if ($('popupHtml').style.display === 'none') $('popupEditor').focus();
    };

    const selectImage = (image) => {
      if (selectedImage) selectedImage.classList.remove('is-selected');
      selectedImage = image;
      if (selectedImage) selectedImage.classList.add('is-selected');
      updateImageTools();
    };

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

    const updateImageTools = () => {
      const visible = !!selectedImage && $('popupHtml').style.display === 'none';
      $('imageTools').classList.toggle('is-visible', visible);
      if (!visible) return;
      const width = imageWidthPercent(selectedImage);
      $('imageWidth').value = String(width);
      $('imageWidthLabel').textContent = width + '%';
      syncFloatingControls();
    };

    const resizeSelectedImage = (width) => {
      if (!selectedImage) return;
      const safeWidth = Math.max(10, Math.min(100, Number(width) || 100));
      selectedImage.style.width = safeWidth + '%';
      selectedImage.style.maxWidth = '100%';
      selectedImage.style.height = 'auto';
      selectedImage.style.display = 'block';
      selectedImage.style.marginLeft = 'auto';
      selectedImage.style.marginRight = 'auto';
      updateImageTools();
      syncHtmlFromEditor();
    };

    const updateDayVisibility = (day) => {
      const closed = document.querySelector(`[data-day="${day}"][data-field="closed"]`);
      const useMessage = document.querySelector(`[data-day="${day}"][data-field="use_message"]`);
      const details = document.querySelector(`[data-day-details="${day}"]`);
      if (details && closed) details.classList.toggle('is-closed', closed.checked);
      if (details && useMessage) details.classList.toggle('is-message', useMessage.checked);
    };

    const fillEditor = () => {
      const loc = currentLocation();
      if (!loc) return;
      $('title').value = loc.office_hours_title || '';
      $('makeDefault').checked = currentSlug() === settings.default_location;
      days.forEach((day) => {
        const hours = (loc.hours && loc.hours[day]) || {};
        document.querySelectorAll(`[data-day="${day}"]`).forEach((input) => {
          const field = input.dataset.field;
          if (field === 'closed') input.checked = !!Number(hours.closed || 0);
          else if (field === 'use_message') input.checked = !!String(hours.message || '').trim();
          else input.value = hours[field] || '';
        });
        updateDayVisibility(day);
      });
      $('popupScope').value = popupHasExpired(loc.popup) ? 'off' : ((loc.popup && loc.popup.scope) || 'homepage');
      const selectedPageIds = new Set(((loc.popup && loc.popup.page_ids) || []).map((id) => String(id)));
      Array.from($('popupPages').options).forEach((option) => {
        option.selected = selectedPageIds.has(option.value);
      });
      setPopupPagesVisibility();
      $('popupScheduleStart').value = siteDateTimeToUserInput(clearPastSiteDateTime((loc.popup && loc.popup.schedule_start) || ''));
      $('popupScheduleEnd').value = siteDateTimeToUserInput(clearPastSiteDateTime((loc.popup && loc.popup.schedule_end) || ''));
      $('popupTitle').value = loc.popup && Object.prototype.hasOwnProperty.call(loc.popup, 'title') ? loc.popup.title : 'ATTENTION';
      $('popupBannerColor').value = (loc.popup && loc.popup.banner_color) || defaultPopupBannerColor || '#19395f';
      $('popupBannerTextColor').value = (loc.popup && loc.popup.banner_text_color) || '#ffffff';
      $('popupHtml').value = (loc.popup && loc.popup.html) || '';
      syncEditorFromHtml();
    };

    const loadSettings = async () => {
      if (!key()) {
        alert('Enter your API key first.');
        return;
      }
      if ($('rememberKey').checked) localStorage.setItem('ioh_api_key', key());
      else localStorage.removeItem('ioh_api_key');

      status('', true);
      const preferredSlug = settings && currentSlug() ? currentSlug() : '';
      settings = await request(settingsUrl);
      renderLocationOptions(preferredSlug);
      fillEditor();
      if (isRemoteSectionAllowed('blog')) loadBlogOptions().catch((e) => blogStatus(e.message, false));
      $('domainBanner').classList.add('is-visible');
      $('editor').hidden = false;
      switchSection(firstAllowedSection());
      updateTimezoneLabels();
      requestAnimationFrame(updateSectionTabIndicator);
      refreshPopupPreviewLayout();
      queueFrameHeight();
      status('', true);
    };

    const collectHours = () => {
      const hours = {};
      days.forEach((day) => {
        hours[day] = {};
        document.querySelectorAll(`[data-day="${day}"]`).forEach((input) => {
          const field = input.dataset.field;
          if (field === 'use_message') return;
          hours[day][field] = field === 'closed' ? (input.checked ? 1 : 0) : input.value;
        });
        if (hours[day].message && String(hours[day].message).trim() !== '') hours[day].closed = 0;
        if (hours[day].closed) hours[day].message = '';
      });
      return hours;
    };

    const saveLocation = async (section = 'hours') => {
      if (!settings || !currentSlug()) return;
      const saveButtons = [$('saveBtn'), $('savePopupBtn')].filter(Boolean);
      saveButtons.forEach((button) => {
        button.disabled = true;
        button.textContent = 'Saving...';
      });
      status('', true);
      try {
        if ($('popupScheduleStart').value && $('popupScheduleEnd').value && new Date($('popupScheduleEnd').value).getTime() < new Date($('popupScheduleStart').value).getTime()) {
          throw new Error('Popup end date/time must be after the start date/time.');
        }
        const payload = {
          office_hours_title: $('title').value,
          make_default: $('makeDefault').checked,
          hours: collectHours(),
          popup: {
            scope: $('popupScope').value,
            page_ids: Array.from($('popupPages').selectedOptions).map((option) => Number(option.value)),
            schedule_start: userInputToSiteDateTime($('popupScheduleStart').value),
            schedule_end: userInputToSiteDateTime($('popupScheduleEnd').value),
            title: $('popupTitle').value,
            banner_color: $('popupBannerColor').value,
            banner_text_color: $('popupBannerTextColor').value,
            html: $('popupHtml').value
          }
        };
        const data = await request(locationUrlBase + encodeURIComponent(currentSlug()), {
          method: 'POST',
          body: JSON.stringify(payload)
        });
        settings = data.settings;
        renderLocationOptions();
        $('location').value = data.location;
        fillEditor();
        status('', true);
        showSettingsSuccessModal(section);
        requestParentScrollTop();
      } finally {
        saveButtons.forEach((button) => {
          button.disabled = false;
          button.textContent = 'Save Changes';
        });
      }
    };

    $('loadBtn').addEventListener('click', () => loadSettings().catch((e) => status(e.message, false)));
    const saveLocationFromButton = (section) => {
      syncHtmlFromEditor();
      saveLocation(section).catch((e) => status(e.message, false));
    };
    $('saveBtn').addEventListener('click', () => saveLocationFromButton('hours'));
    $('savePopupBtn').addEventListener('click', () => saveLocationFromButton('popup'));
    $('location').addEventListener('change', fillEditor);
    document.querySelectorAll('[data-section-tab]').forEach((button) => {
      button.addEventListener('click', () => switchSection(button.dataset.sectionTab));
    });
    window.addEventListener('resize', updateSectionTabIndicator);
    $('popupScope').addEventListener('change', setPopupPagesVisibility);
    ['popupTitle', 'popupBannerColor', 'popupBannerTextColor'].forEach((id) => {
      $(id).addEventListener('input', updatePopupPreview);
    });
    $('popupPreviewBar').addEventListener('pointerdown', startPopupPreviewDrag);
    $('popupPreviewResize').addEventListener('pointerdown', startPopupPreviewResize);
    document.addEventListener('pointermove', movePopupPreviewPointer);
    document.addEventListener('pointerup', endPopupPreviewPointer);
    document.addEventListener('pointercancel', endPopupPreviewPointer);
    $('popupPreviewMinimize').addEventListener('click', () => {
      const minimized = !$('popupPreviewWrap').classList.contains('is-minimized');
      $('popupPreviewWrap').classList.toggle('is-minimized', minimized);
      $('popupPreviewMinimize').textContent = minimized ? '+' : '-';
      $('popupPreviewMinimize').setAttribute('aria-label', minimized ? 'Restore popup preview' : 'Minimize popup preview');
      applyPopupPreviewScale();
    });
    document.querySelectorAll('[data-command]').forEach((button) => {
      button.addEventListener('click', () => {
        focusEditor();
        document.execCommand(button.dataset.command, false, null);
        syncHtmlFromEditor();
      });
    });
    $('linkBtn').addEventListener('click', () => {
      focusEditor();
      const url = prompt('Enter the link URL', 'https://');
      if (!url) return;
      document.execCommand('createLink', false, url);
      syncHtmlFromEditor();
    });
    $('popupInlineTextSize').addEventListener('change', () => {
      const size = $('popupInlineTextSize').value;
      if (!size) return;
      focusEditor();
      document.execCommand('fontSize', false, '7');
      $('popupEditor').querySelectorAll('font[size="7"]').forEach((node) => {
        const span = document.createElement('span');
        span.style.fontSize = size;
        span.innerHTML = node.innerHTML;
        node.replaceWith(span);
      });
      $('popupInlineTextSize').value = '';
      syncHtmlFromEditor();
    });
    $('imageBtn').addEventListener('click', () => {
      $('imageUpload').click();
    });
    $('imageUpload').addEventListener('change', () => {
      const file = $('imageUpload').files && $('imageUpload').files[0];
      if (!file) return;
      status('Uploading photo...', true);
      uploadImage(file).then((data) => {
        focusEditor();
        const alt = file.name.replace(/\.[^.]+$/, '');
        document.execCommand('insertHTML', false, '<img src="' + data.url.replace(/"/g, '&quot;') + '" alt="' + alt.replace(/"/g, '&quot;') + '" style="width:100%;max-width:100%;height:auto;display:block;margin-left:auto;margin-right:auto;" />');
        syncHtmlFromEditor();
        status('Photo uploaded.', true);
      }).catch((e) => {
        status(e.message, false);
      }).finally(() => {
        $('imageUpload').value = '';
      });
    });
    $('htmlToggleBtn').addEventListener('click', () => {
      const htmlVisible = $('popupHtml').style.display !== 'none';
      if (htmlVisible) {
        syncEditorFromHtml();
        $('popupHtml').style.display = 'none';
        $('popupEditor').style.display = 'block';
        $('htmlToggleBtn').textContent = 'HTML';
      } else {
        syncHtmlFromEditor();
        selectImage(null);
        $('popupEditor').style.display = 'none';
        $('popupHtml').style.display = 'block';
        $('htmlToggleBtn').textContent = 'Visual';
      }
      updateImageTools();
    });
    $('popupEditor').addEventListener('input', syncHtmlFromEditor);
    $('popupEditor').addEventListener('click', (event) => {
      if (event.target && event.target.tagName === 'IMG') selectImage(event.target);
      else selectImage(null);
    });
    $('popupHtml').addEventListener('input', syncEditorFromHtml);
    $('imageWidth').addEventListener('input', () => resizeSelectedImage($('imageWidth').value));
    document.querySelectorAll('[data-image-size]').forEach((button) => {
      button.addEventListener('click', () => resizeSelectedImage(button.dataset.imageSize));
    });
    document.querySelectorAll('[data-field="closed"]').forEach((input) => {
      input.addEventListener('change', () => {
        if (input.checked) {
          const message = document.querySelector(`[data-day="${input.dataset.day}"][data-field="message"]`);
          if (message) message.value = '';
          const useMessage = document.querySelector(`[data-day="${input.dataset.day}"][data-field="use_message"]`);
          if (useMessage) useMessage.checked = false;
        }
        updateDayVisibility(input.dataset.day);
      });
    });
    document.querySelectorAll('[data-field="use_message"]').forEach((input) => {
      input.addEventListener('change', () => {
        const day = input.dataset.day;
        const closed = document.querySelector(`[data-day="${day}"][data-field="closed"]`);
        const message = document.querySelector(`[data-day="${day}"][data-field="message"]`);
        if (input.checked) {
          if (closed) closed.checked = false;
        } else if (message) {
          message.value = '';
        }
        updateDayVisibility(day);
      });
    });
    document.querySelectorAll('[data-field="message"]').forEach((input) => {
      input.addEventListener('input', () => {
        if (input.value.trim() !== '') {
          const closed = document.querySelector(`[data-day="${input.dataset.day}"][data-field="closed"]`);
          if (closed) closed.checked = false;
          const useMessage = document.querySelector(`[data-day="${input.dataset.day}"][data-field="use_message"]`);
          if (useMessage) useMessage.checked = true;
          updateDayVisibility(input.dataset.day);
        }
      });
    });
    document.querySelectorAll('[data-blog-section]').forEach(wireBlogSection);
    $('blogSlug').addEventListener('input', () => {
      const cleaned = sanitizeBlogSlug($('blogSlug').value);
      if ($('blogSlug').value !== cleaned) $('blogSlug').value = cleaned;
    });
    $('addBlogSectionBtn').addEventListener('click', addBlogSection);
    $('blogImageBtn').addEventListener('click', () => $('blogImageUpload').click());
    $('blogImageUpload').addEventListener('change', () => {
      const file = $('blogImageUpload').files && $('blogImageUpload').files[0];
      if (!file) return;
      uploadImage(file).then((data) => {
        $('blogImageUrl').value = data.url || '';
        if (data.url) {
          $('blogImageThumb').src = data.url;
          $('blogImageThumb').classList.add('is-visible');
          $('blogImageHelp').hidden = true;
        }
      }).catch((e) => blogStatus(e.message, false)).finally(() => {
        $('blogImageUpload').value = '';
      });
    });
    $('previewBlogBtn').addEventListener('click', () => saveBlog('preview').catch((e) => blogStatus(e.message, false)));
    $('scheduleBlogBtn').addEventListener('click', () => {
      if (!blogScheduleVisible) {
        setBlogScheduleVisible(true);
        $('blogScheduleAt').focus();
        blogStatus('Choose a date and time, then click Schedule Blog again.', true);
        return;
      }
      saveBlog('schedule').catch((e) => blogStatus(e.message, false));
    });
    $('publishBlogBtn').addEventListener('click', () => saveBlog('publish').catch((e) => blogStatus(e.message, false)));
    $('errorModalCloseBtn').addEventListener('click', hideErrorModal);
    $('errorModal').addEventListener('click', (event) => {
      if (event.target === $('errorModal')) hideErrorModal();
    });
    $('settingsSuccessCloseBtn').addEventListener('click', hideSettingsSuccessModal);
    $('settingsSuccessModal').addEventListener('click', (event) => {
      if (event.target === $('settingsSuccessModal')) hideSettingsSuccessModal();
    });
    $('blogLinkCancelBtn').addEventListener('click', () => hideBlogLinkModal(''));
    $('blogLinkApplyBtn').addEventListener('click', applyHttpsBlogLink);
    $('blogLinkPath').addEventListener('input', () => {
      const cleaned = cleanHttpsLinkPath($('blogLinkPath').value);
      if ($('blogLinkPath').value !== cleaned) $('blogLinkPath').value = cleaned;
    });
    $('blogLinkPath').addEventListener('keydown', (event) => {
      if (event.key === 'Enter') {
        event.preventDefault();
        applyHttpsBlogLink();
      }
    });
    $('blogLinkModal').addEventListener('click', (event) => {
      if (event.target === $('blogLinkModal')) hideBlogLinkModal('');
    });
    $('blogSuccessCloseBtn').addEventListener('click', hideBlogSuccessModal);
    $('blogSuccessModal').addEventListener('click', (event) => {
      if (event.target === $('blogSuccessModal')) hideBlogSuccessModal();
    });
    document.addEventListener('keydown', (event) => {
      if (event.key === 'Escape' && $('errorModal').classList.contains('is-visible')) hideErrorModal();
      if (event.key === 'Escape' && $('settingsSuccessModal').classList.contains('is-visible')) hideSettingsSuccessModal();
      if (event.key === 'Escape' && $('blogLinkModal').classList.contains('is-visible')) hideBlogLinkModal('');
      if (event.key === 'Escape' && $('blogSuccessModal').classList.contains('is-visible')) hideBlogSuccessModal();
    });
    renderPageOptions();
    setPopupPagesVisibility();
    setBlogScheduleVisible(false);
    updateTimezoneLabels();
    updatePopupPreview();
    switchSection(firstAllowedSection());
    requestAnimationFrame(updateSectionTabIndicator);
    refreshPopupPreviewLayout();
    startFloatingControlTracker();
    if ('ResizeObserver' in window) {
      const heightObserver = new ResizeObserver(queueFrameHeight);
      heightObserver.observe(document.body);
      heightObserver.observe($('editor'));
    }
    queueFrameHeight();

    const urlParams = new URLSearchParams(window.location.search);
    const urlKey = (urlParams.get('ioh_api_key') || urlParams.get('api_key') || '').trim();
    const storedKey = localStorage.getItem('ioh_api_key');
    if (urlKey) {
      $('apiKey').value = urlKey;
      $('rememberKey').checked = false;
      $('apiKeyBar').style.display = 'none';
      loadSettings().catch((e) => status(e.message, false));
    } else if (storedKey) {
      $('apiKey').value = storedKey;
      $('rememberKey').checked = true;
      loadSettings().catch((e) => status(e.message, false));
    }
  </script>
</body>
</html>
    <?php
    exit;
});
