<?php
/**
 * Admin: view/edit one configuration.
 * Usage: configuration_detail.php?id=123
 */
require __DIR__ . '/config.php';
require_once __DIR__ . '/admin_config_helpers-dp.php';

 header_remove('X-Frame-Options');
header('Content-Security-Policy: frame-ancestors https://admin.shopify.com https://*.myshopify.com');

function h($v) { return htmlspecialchars((string)$v, ENT_QUOTES, 'UTF-8'); }

$id = isset($_GET['id']) ? (int)$_GET['id'] : 0;
if (!$id) {
    header('Location: configurations.php?error=' . urlencode('Missing configuration ID'));
    exit;
}
$stmt = $pdo->prepare("SELECT * FROM door_configurations WHERE id = ?");
$stmt->execute([$id]);
$config = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$config) {
    header('Location: configurations.php?error=' . urlencode('Configuration not found'));
    exit;
}

$folder_id = isset($_GET['folder_id']) ? (int)$_GET['folder_id'] : 0;
if (!$folder_id && !empty($config['folder_id'])) {
    $folder_id = (int)$config['folder_id'];
}
$folder = null;
if ($folder_id) {
    $stmt = $pdo->prepare("SELECT * FROM door_folders WHERE id = ?");
    $stmt->execute([$folder_id]);
    $folder = $stmt->fetch(PDO::FETCH_ASSOC);
}

$admin_config_id = $id;
$admin_folder_id = $folder_id;

$options = json_decode($config['options_json'], true) ?: [];
$options = admin_enrich_options_product_context($options, $config);
// Capture explicit storefront casing before heuristic merge so the admin UI only
// shows the Casing section when the customer actually picked casing on the front.
$storefrontCasingSelections = admin_get_casing_selections($options);
$options = admin_merge_shopify_casing_into_options($options);
$options = admin_strip_casing_from_hardware_options($options);
// Enrich _selected_summary with stored millwork fields (Wood / Length / Thickness) so
// the edit page Selected options section and listing counts match saved values.
$options = admin_sync_listing_selected_summary($options);
if (function_exists('admin_hydrate_hardware_selections_from_summary')) {
    $options = admin_hydrate_hardware_selections_from_summary($options);
}

// Handle POST (save changes) – build options from _pricing_schema (metaobject-driven)
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
    if ($_POST['action'] === 'save') {
        $schema = $options['_pricing_schema'] ?? [];
        // Preserve storefront hardware picks (multi product + finish + qty).
        if (array_key_exists('opt_hardware_options_json', $_POST)) {
            $hwDecoded = json_decode((string) $_POST['opt_hardware_options_json'], true);
            $existingHw = admin_resolve_hardware_selections($options);
            $hwNormalized = admin_merge_hardware_admin_post(
                $existingHw,
                is_array($hwDecoded) ? $hwDecoded : []
            );
            if (!empty($hwNormalized)) {
                $options['_hardware_selections'] = $hwNormalized;
                $options['hardware_options'] = $hwNormalized;
            } else {
                unset($options['_hardware_selections'], $options['hardware_options']);
            }
        }
        // Preserve storefront casing picks (product image/title + length + qty).
        if (array_key_exists('opt_casing_options_json', $_POST)) {
            $casingDecoded = json_decode((string) $_POST['opt_casing_options_json'], true);
            $existingCasing = admin_resolve_casing_selections($options);
            $casingNormalized = admin_merge_casing_admin_post(
                $existingCasing,
                is_array($casingDecoded) ? $casingDecoded : []
            );
            if (!empty($casingNormalized)) {
                $options['_casing_selections'] = $casingNormalized;
                $options['casing_options'] = $casingNormalized;
                if (count($casingNormalized) === 1) {
                    $options['_casing_selection'] = $casingNormalized[0];
                } else {
                    unset($options['_casing_selection']);
                }
            } else {
                unset($options['_casing_selections'], $options['casing_options'], $options['_casing_selection']);
            }
        }
        foreach ($schema as $opt) {
            if (!is_array($opt) || empty($opt['id'])) continue;
            // These fraction dropdowns are removed from the admin UI; they are not posted,
            // so skip them here to preserve their existing saved value (avoid wiping to null).
            if (admin_is_hidden_admin_fraction_field($opt)) continue;
            $oid = $opt['id'];
            $optType = strtolower((string)($opt['type'] ?? $opt['input_type'] ?? ''));
            if ($optType === 'hardware_multi' || $optType === 'casing_multi') {
                continue;
            }
            if ((string)$oid === 'sidelight_design') {
                $options[$oid] = !empty($_POST['opt_sidelight_design']) ? ['1'] : [];
                continue;
            }
            if ((string)$oid === 'glass_bevel') {
                $options['glass_bevel'] = !empty($_POST['opt_glass_bevel']) ? ['true'] : [];
                continue;
            }
            if ($optType === 'checkbox') {
                $posted = null;
                foreach (['opt_' . $oid, 'opt_' . str_replace('-', '_', $oid)] as $postKey) {
                    if (isset($_POST[$postKey]) && is_array($_POST[$postKey])) {
                        $posted = $_POST[$postKey];
                        break;
                    }
                }
                $options[$oid] = is_array($posted)
                    ? array_values(array_filter($posted))
                    : [];
            } elseif ($optType === 'number') {
                $v = admin_read_post_option_value($oid);
                $options[$oid] = $v !== '' ? (float)$v : null;
            } else {
                $v = admin_read_post_option_value($oid);
                $options[$oid] = $v !== '' ? $v : null;
                if (admin_is_measurement_schema_option($opt)) {
                    $norm = admin_norm_option_id($oid);
                    if ($norm !== $oid) {
                        $options[$norm] = $options[$oid];
                    }
                    $hyphen = str_replace('_', '-', $norm);
                    if ($hyphen !== $oid && $hyphen !== $norm) {
                        $options[$hyphen] = $options[$oid];
                    }
                }
            }
        }
        $options = admin_sync_measurement_fields_in_summary($options, $schema);
        // Preserve admin edits to customer "Selected options" (millwork Length / Custom
        // Thickness / Wood Species, etc.) that aren't editable via the schema loop above.
        // Applied AFTER the loop so it isn't wiped when the typeless schema option is
        // skipped (no opt_<id> posted -> would otherwise be nulled).
        if (array_key_exists('opt_selected_options_json', $_POST)) {
            $selDecoded = json_decode((string) $_POST['opt_selected_options_json'], true);
            if (is_array($selDecoded)) {
                $options = admin_apply_selected_option_fields_post($options, $selDecoded);
            }
        }
        if (function_exists('admin_sync_landing_hardware_bidirectional')) {
            $options = admin_sync_landing_hardware_bidirectional($options);
        }
        $status    = $config['status'];
        $basePrice = isset($_POST['base_price']) ? (float)$_POST['base_price'] : (float)$config['base_price'];
        $notesSales = $_POST['notes_sales'] ?? '';
        $orderTotalOverrideRaw = trim((string)($_POST['admin_order_total_override'] ?? ''));
        $lineItemPropsOverride = trim((string)($_POST['admin_line_item_properties_override'] ?? ''));

        if ($orderTotalOverrideRaw !== '' && is_numeric($orderTotalOverrideRaw)) {
            $orderTotalOverride = round((float)$orderTotalOverrideRaw, 2);
            $options['_admin_order_total_override'] = $orderTotalOverride;
        } else {
            unset($options['_admin_order_total_override']);
        }
        if ($lineItemPropsOverride !== '') {
            $options['_admin_line_item_properties_override'] = $lineItemPropsOverride;
        } else {
            unset($options['_admin_line_item_properties_override']);
        }

        $customImageUrl = trim((string) ($_POST['custom_image_url'] ?? ''));
        if ($customImageUrl !== '') {
            $options['_custom_image_url'] = $customImageUrl;
        } else {
            unset($options['_custom_image_url']);
        }
        $internalImagesJson = trim((string) ($_POST['internal_images_json'] ?? ''));
        if ($internalImagesJson !== '') {
            $internalDecoded = json_decode($internalImagesJson, true);
            $internalUrls = admin_normalize_internal_image_urls(is_array($internalDecoded) ? $internalDecoded : []);
            if (!empty($internalUrls)) {
                $options['_internal_images'] = $internalUrls;
            } else {
                unset($options['_internal_images']);
            }
        } else {
            unset($options['_internal_images']);
        }

        $options = admin_save_draft_order_title_from_post($options, $_POST);
        $options = admin_merge_shopify_casing_into_options($options);
        $options = admin_sync_listing_selected_summary($options);

        // Unit price stored in computed_price; admin order-total override wins when set.
        $qty = max(1, (int)($options['_quantity'] ?? 1));
        if (isset($options['_admin_order_total_override'])) {
            $computedPrice = round((float)$options['_admin_order_total_override'] / $qty, 2);
        } else {
            $computedPrice = admin_get_applied_unit_price($options, $basePrice, isset($config['computed_price']) ? (float)$config['computed_price'] : null);
        }

        $up = $pdo->prepare("UPDATE door_configurations SET options_json=?, status=?, base_price=?, computed_price=?, notes_sales=? WHERE id=?");
        $up->execute([json_encode($options), $status, $basePrice, $computedPrice, $notesSales, $id]);

        // Mirror the edited options to the existing HubSpot deal (best-effort, non-blocking).
        // Reuses the storefront's update path: the deal is looked up by saved_project_name
        // + call_requested='--', then the [Config ID: <id>] door segment is replaced with the
        // rebuilt options summary (incl. bevel, hardware, active measurements, quantity).
        $savedProjectName = $folder['name'] ?? '';
        if ($savedProjectName !== '') {
            $hsLineProps = admin_get_merged_line_item_properties($options, (int)$id);
            $hsOrderTotal = admin_get_order_total_price($options, (float)$computedPrice);
            $hsPayload = [
              'product_id'         => (string)($options['_product_id'] ?? ($config['product_id'] ?? '')),
              'product_handle'     => (string)($options['_product_handle'] ?? ($config['product_handle'] ?? '')),
              'product_title'      => (string)($options['_product_title'] ?? ($config['product_title'] ?? 'Door Configuration')),
              'product_sku'        => (string)($options['_product_sku'] ?? ($config['product_sku'] ?? '')),
               'product_type'       => (string)($options['_product_type'] ?? ($config['product_type'] ?? '')),
              'options'            => $options,
              'options_summary'    => admin_build_options_values_only_text($options),
              'line_item_properties' => $hsLineProps,
              'quantity'           => max(1, (int)($options['_quantity'] ?? 1)),
              'base_price'         => (float)$basePrice,
              'applied_price'      => (float)$hsOrderTotal,
              'price'              => (float)$hsOrderTotal,
              'currency'           => 'USD',
              'customer_email'     => (string)($config['customer_email'] ?? ''),
              'call_requested'     => '--',
              'saved_project_name' => $savedProjectName,
              'config_id'          => (string)$id,
          ];
            // Endpoint: override via HUBSPOT_DEAL_ENDPOINT in config.php. Defaults to the
            // deployed location (admin app lives at /admin, deal endpoint at /hubspot/api).
            $hsEndpoint = defined('HUBSPOT_DEAL_ENDPOINT') ? HUBSPOT_DEAL_ENDPOINT : '';
            if ($hsEndpoint === '') {
                $scheme = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';
                $hsHost = $_SERVER['HTTP_HOST'] ?? '';
                if ($hsHost !== '') {
                    $hsEndpoint = $scheme . '://' . $hsHost . '/hubspot/api/hubspot-create-deal.php';
                }
            }
            if ($hsEndpoint !== '' && function_exists('curl_init')) {
                $ch = curl_init($hsEndpoint);
                curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
                curl_setopt($ch, CURLOPT_POST, true);
                curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
                curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($hsPayload));
                curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
                curl_setopt($ch, CURLOPT_TIMEOUT, 10);
                curl_exec($ch);
                curl_close($ch);
            }
        }

        $redirect = 'configuration_detail.php?id=' . $id . '&saved=1';
        if ($folder_id) {
            $redirect .= '&folder_id=' . $folder_id;
        }
        header('Location: ' . $redirect);
        exit;
    }
}
$statusLabels = [
    'draft' => 'Draft',
    'in_progress' => 'In progress',
    'awaiting_customer' => 'Awaiting customer',
    'finalized' => 'Finalized',
    'ordered' => 'Ordered',
    'archived' => 'Archived',
];
$admin_current_nav = 'filter';
$admin_app_title = 'Door Configurator';
$config_saved = isset($_GET['saved']) && $_GET['saved'] === '1';
$quote_preview_saved = isset($_GET['quote_preview_saved']) && $_GET['quote_preview_saved'] === '1';
$quote_preview_error = isset($_GET['quote_preview_error']) ? trim((string) $_GET['quote_preview_error']) : '';
$customImageUrl = trim((string) ($options['_custom_image_url'] ?? ''));
$internalImages = admin_normalize_internal_image_urls($options['_internal_images'] ?? null);
$defaultProductTitle = trim((string) ($options['_product_title'] ?? ($config['product_title'] ?? '')));
$adminUseCustomDraftTitle = !empty($options['_admin_use_custom_draft_title']);
$adminDraftOrderTitle = trim((string) ($options['_admin_quote_title'] ?? ''));
$scriptDir = rtrim(str_replace('\\', '/', dirname($_SERVER['SCRIPT_NAME'] ?? '')), '/');
$isAdminDeploy = ($scriptDir !== '' && $scriptDir !== '.' && preg_match('#(?:^|/)admin$#', $scriptDir));
if (defined('ADMIN_UPLOAD_IMAGE_API_URL') && ADMIN_UPLOAD_IMAGE_API_URL !== '') {
    $adminUploadImageApiUrl = ADMIN_UPLOAD_IMAGE_API_URL;
} elseif ($isAdminDeploy || $scriptDir === '' || $scriptDir === '.') {
    $adminUploadImageApiUrl = '/api/admin_upload_image.php';
} else {
    $adminUploadImageApiUrl = $scriptDir . '/api/admin_upload_image.php';
}
$adminImagePlaceholderSvg = '<svg xmlns="http://www.w3.org/2000/svg" width="96" height="72" viewBox="0 0 96 72" aria-hidden="true">'
    . '<rect width="96" height="72" fill="#f1f5f9"/>'
    . '<rect x="0.5" y="0.5" width="95" height="71" fill="none" stroke="#e2e8f0"/>'
    . '<path d="M24 50l12-14 9 11 7-9 18 22H24z" fill="#cbd5e1"/>'
    . '<circle cx="38" cy="26" r="6" fill="#cbd5e1"/>'
    . '</svg>';
$adminImagePlaceholder = 'data:image/svg+xml,' . rawurlencode($adminImagePlaceholderSvg);
?>
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Config #<?= h($config['id']) ?></title>
  <?php include __DIR__ . '/includes/admin_layout_styles.php'; ?>
  <style>
    .admin-casing-selections,
    .admin-hardware-selections,
    .admin-selected-options { display: flex; flex-direction: column; gap: 0.75rem; }
    .admin-selected-option-card .admin-casing-card__controls { width: 100%; }
    .admin-selected-option-field { min-width: 200px; flex: 1 1 200px; }
    .admin-selected-option-field .admin-selected-option-value { width: 100%; }
    .admin-casing-card {
      display: flex;
      gap: 0.75rem;
      align-items: flex-start;
      padding: 0.75rem;
      border: 1px solid #e2e8f0;
      border-radius: 8px;
      background: #fff;
    }
    .admin-casing-card__image {
      width: 72px;
      height: 72px;
      object-fit: cover;
      flex-shrink: 0;
      border-radius: 6px;
      background: #f8fafc;
    }
    .admin-casing-card__image--placeholder { border: 1px dashed #cbd5e1; }
    .admin-casing-card__body { flex: 1; min-width: 0; }
    .admin-casing-card__title { margin: 0 0 0.25rem; font-weight: 600; line-height: 1.35; }
    .admin-casing-card__price { margin: 0 0 0.5rem; color: #64748b; font-size: 0.875rem; }
    .admin-casing-card__controls { display: flex; flex-wrap: wrap; gap: 0.75rem; align-items: flex-end; }
    .admin-casing-field { display: flex; flex-direction: column; gap: 0.25rem; min-width: 120px; }
    .admin-casing-field--qty { width: 88px; }
    .admin-casing-field__label { font-size: 0.75rem; color: #64748b; text-transform: uppercase; letter-spacing: 0.03em; }
    .admin-save-overlay {
      position: fixed;
      inset: 0;
      z-index: 9999;
      display: flex;
      align-items: center;
      justify-content: center;
      background: rgba(15, 23, 42, 0.45);
      backdrop-filter: blur(2px);
    }
    .admin-save-overlay[hidden] { display: none; }
    .admin-save-overlay__box {
      display: flex;
      flex-direction: column;
      align-items: center;
      gap: 0.85rem;
      padding: 1.5rem 2rem;
      background: #fff;
      border-radius: 12px;
      box-shadow: 0 12px 40px rgba(15, 23, 42, 0.25);
    }
    .admin-save-overlay__spinner {
      width: 38px;
      height: 38px;
      border: 4px solid #e2e8f0;
      border-top-color: #2563eb;
      border-radius: 50%;
      animation: admin-save-spin 0.7s linear infinite;
    }
    .admin-save-overlay__text { margin: 0; font-weight: 600; color: #1e293b; }
    @keyframes admin-save-spin { to { transform: rotate(360deg); } }
    .admin-btn.is-saving { opacity: 0.7; cursor: progress; }
  </style>
</head>
<body class="admin-app">
  <?php
  $sidebar_file = __DIR__ . '/admin_sidebar.php';
  if (!is_file($sidebar_file)) {
      $sidebar_file = __DIR__ . '/includes/admin_sidebar.php';
  }
  include $sidebar_file;
  ?>
  <main class="admin-main">
  <div class="admin-wrap admin-wrap--narrow">
    <header class="admin-page-header">
      <nav class="admin-breadcrumb">
        <?php if ($folder): ?>
        <a href="folders.php">Projects</a>
        <span>›</span>
        <a href="folder_detail.php?id=<?= h($folder_id) ?>"><?= h($folder['name']) ?></a>
        <span>›</span>
        <span>#<?= h($config['id']) ?></span>
        <?php else: ?>
        <a href="configurations.php">Configurations</a>
        <span>›</span>
        <span>#<?= h($config['id']) ?></span>
        <?php endif; ?>
      </nav>
      <h1 class="admin-page-title">Configuration #<?= h($config['id']) ?></h1>
    </header>
    <?php if ($config_saved): ?>
    <div class="admin-alert admin-alert--success">
      <div>
        <strong>Configuration saved.</strong>
        Options, status, pricing, notes, and order overrides have been updated.
      </div>
    </div>
    <?php endif; ?>
    <?php if ($quote_preview_saved): ?>
    <div class="admin-alert admin-alert--success">
      <div>
        <strong>Quote preview saved.</strong>
        Staff edits to the title and description are stored for this configuration.
      </div>
    </div>
    <?php endif; ?>
    <?php if ($quote_preview_error !== ''): ?>
    <div class="admin-alert admin-alert--error">
      <div>
        <strong>Quote preview save failed</strong>
        <?= h($quote_preview_error) ?>
      </div>
    </div>
    <?php endif; ?>
    <?php
    $productTitle = $options['_product_title'] ?? '';
    $productImage = $options['_product_image_url'] ?? '';
    $selectedQty = (int)($options['_quantity'] ?? 1);
    if ($selectedQty < 1) $selectedQty = 1;
    $adminOrderTotalOverride = isset($options['_admin_order_total_override']) && $options['_admin_order_total_override'] !== ''
        ? (float)$options['_admin_order_total_override'] : null;
    $adminLineItemPropsOverride = (string)($options['_admin_line_item_properties_override'] ?? '');
    $appliedUnitPrice = admin_get_applied_unit_price($options, (float)$config['base_price'], (float)$config['computed_price']);
    $displayOrderTotal = $adminOrderTotalOverride !== null
        ? $adminOrderTotalOverride
        : admin_get_order_total_price($options, $appliedUnitPrice);
    if ($productImage || $productTitle):
    ?>
    <div class="admin-product-hero">
      <?php if ($productImage): ?>
        <img src="<?= h($productImage) ?>" alt="<?= h($productTitle) ?>">
      <?php endif; ?>
      <div>
        <p class="admin-product-title"><?= h($productTitle) ?: 'Product' ?></p>
        <p class="admin-product-meta">Customer <?= h($config['customer_email']) ?> &middot; $<?= h(number_format($displayOrderTotal, 2)) ?><?= $adminOrderTotalOverride !== null ? ' (override)' : '' ?> &middot; Qty <?= h($selectedQty) ?></p>
      </div>
    </div>
    <?php endif; ?>
    <p class="admin-status-bar">
      <span><strong>Customer</strong> <?= h($config['customer_email']) ?></span>
      <span><strong>Status</strong> <span class="admin-pill admin-pill--<?= h($config['status']) ?>"><?= h($statusLabels[$config['status']] ?? $config['status']) ?></span></span>
      <span><strong>Price</strong> $<?= h(number_format($displayOrderTotal, 2)) ?><?= $adminOrderTotalOverride !== null ? ' (override)' : '' ?></span>
      <span><strong>Qty</strong> <?= h($selectedQty) ?></span>
    </p>

    <div class="admin-card admin-card--form">
      <div class="admin-card-header">
        <p class="admin-card-title">Edit configuration</p>
      </div>
      <form method="post" class="admin-detail">
        <input type="hidden" name="action" value="save">
        <input type="hidden" name="id" value="<?= (int) $id ?>">
        <?php if ($folder_id): ?>
        <input type="hidden" name="folder_id" value="<?= (int) $folder_id ?>">
        <?php endif; ?>
        <div class="admin-form-group">
          <label class="admin-label">Base price</label>
          <input type="number" name="base_price" step="0.01" value="<?= h($config['base_price']) ?>" class="admin-input">
        </div>
        <?php
        $addonRows = admin_render_addon_breakdown_rows($options);
        $showAppliedPricing = $addonRows !== ''
          || $appliedUnitPrice > (float)$config['base_price'] + 0.01;
        if ($showAppliedPricing):
        ?>
        <div class="admin-form-group">
          <label class="admin-label">Applied unit price</label>
          <p class="admin-page-meta" style="margin:0 0 8px 0;">
            <strong>$<?= h(number_format($appliedUnitPrice, 2)) ?></strong>
            <?php if ($appliedUnitPrice > (float)$config['base_price'] + 0.01): ?>
              <span class="admin-meta-muted"> (base $<?= h(number_format((float)$config['base_price'], 2)) ?> + add-ons)</span>
            <?php endif; ?>
          </p>
          <div class="admin-table-wrap">
            <table class="admin-table admin-table--compact admin-table--hover">
              <thead>
                <tr><th>Add-on</th><th>Amount</th></tr>
              </thead>
              <tbody>
                <?= $addonRows ?>
              </tbody>
            </table>
          </div>
         
        </div>
        <?php endif; ?>
        <?php
        $schema = $options['_pricing_schema'] ?? [];
        if (!is_array($schema)) {
            $schema = [];
        }
        $schema = admin_ensure_casing_schema($schema, $options, $storefrontCasingSelections);
        $schema = admin_ensure_hardware_schema($schema, $options);
        // Reorder: place the sidelight section (toggle + style + location) right before transom_design.
        if (!empty($schema)) {
            $sidelightIds = ['sidelight_design', 'sidelight_location', 'sidelight_style'];
            $sidelightOpts = [];
            $restOpts = [];
            foreach ($schema as $sOpt) {
                $sOid = (is_array($sOpt) && isset($sOpt['id'])) ? (string)$sOpt['id'] : '';
                if (in_array($sOid, $sidelightIds, true)) { $sidelightOpts[$sOid] = $sOpt; }
                else { $restOpts[] = $sOpt; }
            }
            if (!empty($sidelightOpts)) {
                $orderedSide = [];
                foreach ($sidelightIds as $sid) { if (isset($sidelightOpts[$sid])) $orderedSide[] = $sidelightOpts[$sid]; }
                $newSchema = [];
                $insertedSide = false;
                foreach ($restOpts as $rOpt) {
                    $rOid = (is_array($rOpt) && isset($rOpt['id'])) ? (string)$rOpt['id'] : '';
                    if ($rOid === 'transom_design' && !$insertedSide) {
                        foreach ($orderedSide as $oSide) { $newSchema[] = $oSide; }
                        $insertedSide = true;
                    }
                    $newSchema[] = $rOpt;
                }
                if (!$insertedSide) { foreach ($orderedSide as $oSide) { $newSchema[] = $oSide; } }
                $schema = $newSchema;
            }
        }
        // Reorder editable options to their requested positions:
        //  - door_location_exposure  -> BEFORE wood_type
        //  - glass_bevel             -> after glass_type
        //  - all measurement dropdowns -> grouped after measurement_type ("Measurements")
        //  - hardware_options        -> near the end
        //  - casing_options          -> after hardware
        if (!empty($schema) && is_array($schema)) {
            $normId = function ($s) { return strtolower(str_replace('-', '_', (string)$s)); };
            // A measurement dropdown is tagged from the storefront OR its id matches a
            // dimension pattern (width/height/thickness/pre-hung/jamb).
            $isMeasurement = function ($o) use ($normId) {
                if (!is_array($o)) return false;
                if (($o['_adminGroup'] ?? '') === 'measurement') return true;
                $id = $normId($o['id'] ?? '');
                if ($id === 'measurement_type') return false;
                return (bool)preg_match('/(width|height|thick|pre_hung|jamb)/', $id);
            };
            // The door-setup option (Slab vs Pre-hung) is the one whose choices
            // include a "slab_only" value. Detected first so its pre-hung id does
            // not get mistaken for a measurement dropdown.
            $hasSlabChoice = function ($o) use ($normId) {
                if (!is_array($o) || empty($o['options']) || !is_array($o['options'])) return false;
                foreach ($o['options'] as $c) {
                    if (is_array($c) && isset($c['value']) && $normId($c['value']) === 'slab_only') return true;
                }
                return false;
            };
            $slabOpt = null; $exposure = null; $bevel = null; $hardware = null; $casing = null;
            $measurementBlock = [];
            $rest = [];
            foreach ($schema as $o) {
                if (!is_array($o)) { $rest[] = $o; continue; }
                $id = $normId($o['id'] ?? '');
                if ($slabOpt === null && $hasSlabChoice($o)) { $slabOpt = $o; continue; }
                if ($isMeasurement($o)) {
                    // Hidden per request: Exact Door Width / Sidelight Width / Transom Height (fraction).
                    if (admin_is_hidden_admin_fraction_field($o)) continue;
                    $measurementBlock[] = $o;
                    continue;
                }
                if ($id === 'door_location_exposure') { $exposure = $o; continue; }
                if ($id === 'glass_bevel') { $bevel = $o; continue; }
                if ($id === 'hardware_options') { $hardware = $o; continue; }
                if ($id === 'casing_options') { $casing = $o; continue; }
                $rest[] = $o;
            }
            // Arrange the measurement dropdowns into a consistent, storefront-matching
            // layout regardless of capture/DOM order or alias duplicates:
            //   Width, Width (fraction), Height, Height (fraction),
            //   Thickness, Thickness (fraction), then any remaining measurement fields.
            if (count($measurementBlock) > 1) {
                $measRank = function ($o) use ($normId) {
                    $id = $normId($o['id'] ?? '');
                    $label = strtolower((string)($o['label'] ?? ''));
                    $hay = $id . ' ' . $label;
                    $isFrac = (strpos($id, 'frac') !== false) || (strpos($label, 'fraction') !== false);
                    // Component group base: door first, then sidelight, transom, gate, panel.
                    $base = 0;
                    if (strpos($hay, 'sidelight') !== false || strpos($hay, 'side_light') !== false || strpos($hay, 'sidelite') !== false) { $base = 20; }
                    elseif (strpos($hay, 'transom') !== false) { $base = 30; }
                    elseif (strpos($hay, 'gate') !== false) { $base = 40; }
                    elseif (strpos($hay, 'panel') !== false && strpos($hay, 'door') === false) { $base = 50; }
                    // Dimension within the component: width, height, thickness.
                    $dim = null;
                    if (strpos($hay, 'width') !== false) { $dim = 0; }
                    elseif (strpos($hay, 'height') !== false) { $dim = 2; }
                    elseif (strpos($hay, 'thick') !== false) { $dim = 4; }
                    if ($dim === null) return $base + 100; // pre-hung / jamb / other -> after that component's core dims
                    return $base + $dim + ($isFrac ? 1 : 0);
                };
                $mi = 0;
                $tagged = array_map(function ($o) use (&$mi, $measRank) {
                    return ['rank' => $measRank($o), 'idx' => $mi++, 'o' => $o];
                }, $measurementBlock);
                usort($tagged, function ($a, $b) {
                    if ($a['rank'] !== $b['rank']) return $a['rank'] <=> $b['rank'];
                    return $a['idx'] <=> $b['idx']; // stable for equal ranks
                });
                $measurementBlock = array_map(function ($t) { return $t['o']; }, $tagged);
            }
            $ordered = [];
            $slabPlaced = false; $exposurePlaced = false; $bevelPlaced = false; $measPlaced = false;
            foreach ($rest as $o) {
                $id = is_array($o) ? $normId($o['id'] ?? '') : '';
                // Before wood_type: slab option, then door_location_exposure.
                if ($id === 'wood_type') {
                    if ($slabOpt !== null && !$slabPlaced) { $ordered[] = $slabOpt; $slabPlaced = true; }
                    if ($exposure !== null && !$exposurePlaced) { $ordered[] = $exposure; $exposurePlaced = true; }
                }
                $ordered[] = $o;
                if ($id === 'glass_type' && $bevel !== null && !$bevelPlaced) { $ordered[] = $bevel; $bevelPlaced = true; }
                if ($id === 'measurement_type' && !$measPlaced && !empty($measurementBlock)) {
                    foreach ($measurementBlock as $mb) { $ordered[] = $mb; }
                    $measPlaced = true;
                }
            }
            // Fallbacks when an anchor was not found (keep slab before exposure).
            if ($exposure !== null && !$exposurePlaced) { array_unshift($ordered, $exposure); $exposurePlaced = true; }
            if ($slabOpt !== null && !$slabPlaced) { array_unshift($ordered, $slabOpt); $slabPlaced = true; }
            if ($bevel !== null && !$bevelPlaced) { $ordered[] = $bevel; }
            if (!$measPlaced && !empty($measurementBlock)) { foreach ($measurementBlock as $mb) { $ordered[] = $mb; } }
            if ($hardware !== null) { $ordered[] = $hardware; }
            if ($casing !== null) { $ordered[] = $casing; }
            $schema = $ordered;
        }
        if (!empty($schema) && is_array($schema)) {
            $adminOptionBasePrice = (float)($config['base_price'] ?? 0);
            $optionBuckets = admin_bucket_schema_by_accordion($schema);
            $optionGroupLabels = admin_accordion_group_labels();
            $isFirstOptionAccordion = true;
            $renderedCasingOptionsUi = false;
            $renderedHardwareOptionsUi = false;
            foreach (array_keys($optionGroupLabels) as $optionGroupKey) {
                if (empty($optionBuckets[$optionGroupKey])) continue;
            ?>
            <details class="admin-option-accordion"<?= $isFirstOptionAccordion ? ' open' : '' ?>>
              <summary class="admin-option-accordion-summary"><?= h($optionGroupLabels[$optionGroupKey]) ?></summary>
              <div class="admin-option-accordion-body">
            <?php
                foreach ($optionBuckets[$optionGroupKey] as $opt) {
                if (!is_array($opt) || empty($opt['id'])) continue;
                // Sidelight master toggle: always render sidelight_design as a single
                // "Add sidelight" checkbox (regardless of its schema type), used to
                // gate the style/location selections in the admin.
                if ((string)$opt['id'] === 'sidelight_design') {
                    $sideLabel = $opt['label'] ?? 'Sidelight';
                    $sideActive = admin_config_key_marked_enabled($options, 'sidelight_design');
        ?>
        <div class="admin-option-row" data-option-id="sidelight_design">
          <label class="admin-label"><?= h($sideLabel) ?></label>
          <label class="admin-checkbox-label">
            <input type="checkbox" name="opt_sidelight_design" value="1"<?= $sideActive ? ' checked' : '' ?>>
            Add sidelight
          </label>
        </div>
        <?php
                    continue;
                }
                if ((string)$opt['id'] === 'glass_bevel') {
                    $bevelActive = admin_glass_bevel_is_enabled($options);
        ?>
        <div class="admin-option-row" data-option-id="glass_bevel">
          <label class="admin-label"><?= h($opt['label'] ?? 'Bevel Glass') ?></label>
          <label class="admin-checkbox-label">
            <input type="checkbox" name="opt_glass_bevel[]" value="true"<?= $bevelActive ? ' checked' : '' ?>>
            Add Bevel Glass
          </label>
        </div>
        <?php
                    continue;
                }
                $type = '';
                if (!empty($opt['type']) && is_string($opt['type'])) {
                    $type = strtolower($opt['type']);
                } elseif (!empty($opt['input_type']) && is_string($opt['input_type'])) {
                    $type = strtolower($opt['input_type']);
                }
                if ($type === '') continue;
                $oid = $opt['id'];
                $label = $opt['label'] ?? $oid;
                $current = admin_is_measurement_schema_option($opt)
                    ? admin_config_get_measurement_value($options, $oid)
                    : admin_config_get_value($options, $oid);
                $choices = isset($opt['options']) && is_array($opt['options']) ? $opt['options'] : [];
                if (admin_norm_option_id($oid) === 'measurement_type') {
                    $resolvedMeas = admin_resolve_measurement_type_value($options);
                    if ($resolvedMeas !== '' && ($current === null || $current === '' || $current === [])) {
                        $matchVal = $resolvedMeas;
                        foreach ($choices as $cMatch) {
                            if (!is_array($cMatch)) {
                                continue;
                            }
                            $cv = $cMatch['value'] ?? '';
                            if (admin_select_value_matches($resolvedMeas, $cv)) {
                                $matchVal = $cv;
                                break;
                            }
                        }
                        $current = ($type === 'checkbox') ? [$matchVal] : (string) $matchVal;
                    }
                }
                $hideWhen = isset($opt['hideWhen']) && is_array($opt['hideWhen']) ? $opt['hideWhen'] : [];
                $showWhen = isset($opt['showWhen']) && is_array($opt['showWhen']) ? $opt['showWhen'] : [];
                if (empty($showWhen) && !empty($opt['show_when_key']) && (string)$opt['show_when_key'] !== '' && isset($opt['show_when_value'])) {
                    $showWhen = [ (string)$opt['show_when_key'] => (string)$opt['show_when_value'] ];
                }
                $refKey = '';
                $refVal = '';
                $isShowWhen = false;
                if (!empty($hideWhen)) {
                    $hKeys = array_keys($hideWhen);
                    $refKey = isset($hKeys[0]) ? (string)$hKeys[0] : '';
                    $refVal = $refKey !== '' ? (string)($hideWhen[$refKey] ?? '') : '';
                } elseif (!empty($showWhen)) {
                    $sKeys = array_keys($showWhen);
                    $refKey = isset($sKeys[0]) ? (string)$sKeys[0] : '';
                    $refVal = $refKey !== '' ? (string)($showWhen[$refKey] ?? '') : '';
                    $isShowWhen = true;
                }
                $selectedPriceLabel = '';
                if (in_array($type, ['select', 'radio', 'checkbox'], true)) {
                    $hasOptionSelection = ($type === 'checkbox')
                        ? count(admin_normalize_checkbox_selected_values($current, $choices)) > 0
                        : admin_option_has_selection($type, $current);
                    $selectedPriceLabel = admin_format_option_price_display(
                        admin_get_option_display_price_delta($opt, $options, $adminOptionBasePrice),
                        $hasOptionSelection
                    );
                }
        ?>
        <div class="admin-option-row" data-option-id="<?= h($oid) ?>"
          <?= ($refKey !== '' && $refVal !== '') ? ($isShowWhen ? ' data-show-when-ref="' . h($refKey) . '" data-show-when-val="' . h($refVal) . '"' : ' data-hide-when-ref="' . h($refKey) . '" data-hide-when-val="' . h($refVal) . '"') : '' ?>>
        <div class="admin-option-label-row">
          <label class="admin-label"><?= h($label) ?></label>
          <span class="admin-option-selected-price<?= $selectedPriceLabel === '' ? ' admin-option-selected-price--empty' : '' ?>" data-option-id="<?= h($oid) ?>"><?= h($selectedPriceLabel) ?></span>
        </div>
        <?php if ($type === 'select'): ?>
        <select name="opt_<?= h($oid) ?>" class="admin-select">
          <option value="">(none)</option>
          <?php foreach ($choices as $c) {
              $v = $c['value'] ?? '';
              $l = $c['label'] ?? $v;
              $sel = admin_select_value_matches($current, $v) ? ' selected' : '';
              $cShowWhen = isset($c['showWhen']) && is_array($c['showWhen']) ? $c['showWhen'] : [];
              if (empty($cShowWhen) && !empty($c['show_when_key']) && (string)$c['show_when_key'] !== '' && isset($c['show_when_value'])) {
                  $cShowWhen = [ (string)$c['show_when_key'] => (string)$c['show_when_value'] ];
              }
              $cRefKey = '';
              $cRefVal = '';
              $cIsShow = false;
              if (!empty($cShowWhen)) {
                  $cKeys = array_keys($cShowWhen);
                  $cRefKey = isset($cKeys[0]) ? (string)$cKeys[0] : '';
                  $cRefVal = $cRefKey !== '' ? (string)($cShowWhen[$cRefKey] ?? '') : '';
                  $cIsShow = true;
              }
              $optAttrs = '';
              if ($cRefKey !== '' && $cRefVal !== '') {
                  $optAttrs = $cIsShow ? ' data-show-when-ref="' . h($cRefKey) . '" data-show-when-val="' . h($cRefVal) . '"' : ' data-hide-when-ref="' . h($cRefKey) . '" data-hide-when-val="' . h($cRefVal) . '"';
              }
              $choicePrice = admin_resolve_choice_price_amount(is_array($c) ? $c : [], $opt, $options, $adminOptionBasePrice);
          ?><option value="<?= h($v) ?>" data-choice-price="<?= h((string)$choicePrice) ?>"<?= $optAttrs ?><?= $sel ?>><?= h($l) ?></option>
          <?php } ?>
        </select>
        <?php elseif ($type === 'number'):
            $min = isset($opt['min']) ? (int)$opt['min'] : null;
            $max = isset($opt['max']) ? (int)$opt['max'] : null;
            $val = $current !== null && $current !== '' ? (float)$current : '';
        ?>
        <input type="number" name="opt_<?= h($oid) ?>" class="admin-input" value="<?= h($val) ?>"<?= $min !== null ? ' min="' . (int)$min . '"' : '' ?><?= $max !== null ? ' max="' . (int)$max . '"' : '' ?>>
        <?php elseif ($type === 'radio'):
            $selVal = $current !== null && $current !== '' ? (string)$current : '';
            $hasAnyImage = false;
            foreach ($choices as $c0) {
                $img0 = $c0['image'] ?? '';
                if (is_array($img0) && !empty($img0['url'])) $img0 = $img0['url'];
                if (is_string($img0) && trim($img0) !== '') { $hasAnyImage = true; break; }
            }
        ?>
        <?php if ($hasAnyImage): ?>
        <div class="admin-choice-cards<?= $oid === 'sidelight_style' ? ' admin-choice-cards--full' : '' ?>">
          <?php foreach ($choices as $c) {
              $v = $c['value'] ?? '';
              $l = $c['label'] ?? $v;
              $img = $c['image'] ?? '';
              if (is_array($img) && !empty($img['url'])) $img = $img['url'];
              $checked = admin_select_value_matches($current, $v) ? ' checked' : '';
              $selectedClass = $checked ? ' admin-choice-card--selected' : '';
              $choicePrice = admin_resolve_choice_price_amount(is_array($c) ? $c : [], $opt, $options, $adminOptionBasePrice);
          ?>
            <label class="admin-choice-card<?= h($selectedClass) ?>">
              <input type="radio" name="opt_<?= h($oid) ?>" value="<?= h($v) ?>" data-choice-price="<?= h((string)$choicePrice) ?>"<?= $checked ?>>
              <span class="admin-choice-indicator">✓</span>
              <?php if ($img): ?><img src="<?= h($img) ?>" alt="" class="admin-choice-thumb"><?php endif; ?>
              <span class="admin-choice-text"><?= h($l) ?></span>
            </label>
          <?php } ?>
        </div>
        <?php else: ?>
        <div class="admin-checkbox-group">
          <?php foreach ($choices as $c) {
              $v = $c['value'] ?? '';
              $l = $c['label'] ?? $v;
              $checked = admin_select_value_matches($current, $v) ? ' checked' : '';
              $choicePrice = admin_resolve_choice_price_amount(is_array($c) ? $c : [], $opt, $options, $adminOptionBasePrice);
          ?><label class="admin-checkbox-label admin-radio-label"><input type="radio" name="opt_<?= h($oid) ?>" value="<?= h($v) ?>" data-choice-price="<?= h((string)$choicePrice) ?>"<?= $checked ?>> <?= h($l) ?></label>
          <?php } ?>
        </div>
        <?php endif; ?>
        <?php elseif ($type === 'checkbox'):
            $arr = admin_normalize_checkbox_selected_values($current, $choices);
            $hasAnyImage = false;
            foreach ($choices as $c0) {
                $img0 = $c0['image'] ?? '';
                if (is_array($img0) && !empty($img0['url'])) $img0 = $img0['url'];
                if (is_string($img0) && trim($img0) !== '') { $hasAnyImage = true; break; }
            }
        ?>
        <?php if ($hasAnyImage): ?>
        <div class="admin-choice-cards<?= $oid === 'sidelight_style' ? ' admin-choice-cards--full' : '' ?>">
          <?php foreach ($choices as $c) {
              $v = $c['value'] ?? '';
              $l = $c['label'] ?? $v;
              $img = $c['image'] ?? '';
              if (is_array($img) && !empty($img['url'])) $img = $img['url'];
              $checked = false;
              foreach ($arr as $selItem) {
                  if (admin_select_value_matches($selItem, $v)) {
                      $checked = true;
                      break;
                  }
              }
              $checked = $checked ? ' checked' : '';
              $selectedClass = $checked ? ' admin-choice-card--selected' : '';
              $choicePrice = admin_resolve_choice_price_amount(is_array($c) ? $c : [], $opt, $options, $adminOptionBasePrice);
          ?>
            <label class="admin-choice-card<?= h($selectedClass) ?>">
              <input type="checkbox" name="opt_<?= h($oid) ?>[]" value="<?= h($v) ?>" data-choice-price="<?= h((string)$choicePrice) ?>"<?= $checked ?>>
              <span class="admin-choice-indicator">✓</span>
              <?php if ($img): ?><img src="<?= h($img) ?>" alt="" class="admin-choice-thumb"><?php endif; ?>
              <span class="admin-choice-text"><?= h($l) ?></span>
            </label>
          <?php } ?>
        </div>
        <?php else: ?>
        <div class="admin-checkbox-group">
          <?php foreach ($choices as $c) {
              $v = $c['value'] ?? '';
              $l = $c['label'] ?? $v;
              $checked = false;
              foreach ($arr as $selItem) {
                  if (admin_select_value_matches($selItem, $v)) {
                      $checked = true;
                      break;
                  }
              }
              $checked = $checked ? ' checked' : '';
              $choicePrice = admin_resolve_choice_price_amount(is_array($c) ? $c : [], $opt, $options, $adminOptionBasePrice);
          ?><label class="admin-checkbox-label"><input type="checkbox" name="opt_<?= h($oid) ?>[]" value="<?= h($v) ?>" data-choice-price="<?= h((string)$choicePrice) ?>"<?= $checked ?>> <?= h($l) ?></label>
          <?php } ?>
        </div>
        <?php endif; ?>
        <?php elseif ($type === 'hardware_multi'):
            if ($renderedHardwareOptionsUi) {
                continue;
            }
            $renderedHardwareOptionsUi = true;
            $hwItems = admin_resolve_hardware_selections($options);
            if (empty($hwItems) && is_array($current) && isset($current[0]) && is_array($current[0])) {
                $hwItems = admin_filter_hardware_selections(admin_normalize_hardware_selections($current));
            }
            // Drop saved values for fields the storefront product does not expose (e.g. track
            // length on a knob), so they neither render nor get re-saved.
            if (function_exists('admin_strip_unavailable_hardware_fields')) {
                foreach ($hwItems as $hwSanIdx => $hwSanItem) {
                    if (is_array($hwSanItem)) {
                        $hwItems[$hwSanIdx] = admin_strip_unavailable_hardware_fields($hwSanItem, $options);
                    }
                }
            }
        ?>
        <div class="admin-hardware-selections" data-admin-hardware-root="1">
          <?php if (!$hwItems): ?>
            <p class="admin-form-hint">No hardware added on the storefront.</p>
          <?php else: ?>
            <?php foreach ($hwItems as $hi => $item):
                if (!is_array($item)) continue;
                $hwTitle = trim((string)($item['title'] ?? $item['product_id'] ?? ''));
                if ($hwTitle === '') continue;
                $hwImage = trim((string)($item['image'] ?? ''));
                $hwQty = max(1, (int)($item['qty'] ?? 1));
                $hwPrice = trim((string)($item['price_formatted'] ?? ''));
                $hwOpts = admin_options_with_hardware_product_context($options, $item);
                $finishChoices = admin_hardware_finish_choices_for_item($item, $hwOpts);
                $functionChoices = admin_hardware_function_choices_for_item($item, $hwOpts);
                $thicknessChoices = admin_hardware_thickness_choices_for_item($item, $hwOpts);
                $hwExtraFields = [];
                foreach (admin_hardware_landing_field_defs() as $hwDef) {
                    if (!is_array($hwDef)) continue;
                    $vk = (string)($hwDef['value_key'] ?? '');
                    if (in_array($vk, ['finish_value', 'function_value', 'thickness_value'], true)) continue;
                    // Only render fields the storefront product actually exposes.
                    if (function_exists('admin_hardware_field_available_for_product')
                        && !admin_hardware_field_available_for_product($hwDef, $hwOpts)) {
                        continue;
                    }
                    $hwExtraFields[] = [
                        'def' => $hwDef,
                        'choices' => admin_hardware_extra_field_choices_for_item($item, $hwDef, $hwOpts),
                        'selected' => trim((string)($item[$vk] ?? $item[(string)($hwDef['label_key'] ?? '')] ?? '')),
                    ];
                }
                $selectedFinish = trim((string)($item['finish_value'] ?? $item['finish_label'] ?? ''));
                $selectedFunction = trim((string)($item['function_value'] ?? $item['function_label'] ?? ''));
                $selectedThickness = trim((string)($item['thickness_value'] ?? $item['thickness_label'] ?? ''));
                // Availability for the core fields (only show what the storefront product exposes).
                $finishAvailable = true;
                $functionAvailable = true;
                $thicknessAvailable = true;
                if (function_exists('admin_hardware_field_available_for_product')) {
                    foreach (admin_hardware_landing_field_defs() as $coreDef) {
                        if (!is_array($coreDef)) continue;
                        $coreVk = (string)($coreDef['value_key'] ?? '');
                        if ($coreVk === 'finish_value') {
                            $finishAvailable = admin_hardware_field_available_for_product($coreDef, $hwOpts);
                        } elseif ($coreVk === 'function_value') {
                            $functionAvailable = admin_hardware_field_available_for_product($coreDef, $hwOpts);
                        } elseif ($coreVk === 'thickness_value') {
                            $thicknessAvailable = admin_hardware_field_available_for_product($coreDef, $hwOpts);
                        }
                    }
                }
            ?>
            <div class="admin-casing-card admin-hardware-card" data-hardware-index="<?= (int)$hi ?>">
              <?php if ($hwImage !== ''): ?>
                <img src="<?= h($hwImage) ?>" alt="" class="admin-choice-thumb admin-casing-card__image">
              <?php else: ?>
                <div class="admin-choice-thumb admin-casing-card__image admin-casing-card__image--placeholder" aria-hidden="true"></div>
              <?php endif; ?>
              <div class="admin-casing-card__body">
                <p class="admin-casing-card__title"><?= h($hwTitle) ?></p>
                <?php if ($hwPrice !== ''): ?>
                  <p class="admin-casing-card__price"><?= h($hwPrice) ?> as configured</p>
                <?php endif; ?>
                <div class="admin-casing-card__controls">
                  <?php if ($finishAvailable && (!empty($finishChoices) || $selectedFinish !== '')): ?>
                  <label class="admin-casing-field">
                    <span class="admin-casing-field__label">Finish</span>
                    <?php if (!empty($finishChoices)): ?>
                    <select class="admin-select admin-hardware-finish">
                      <?php $finishHasCurrent = false; foreach ($finishChoices as $fc):
                          $fv = (string)($fc['value'] ?? '');
                          $fl = (string)($fc['label'] ?? $fv);
                          $finSel = ($selectedFinish !== '' && (admin_select_value_matches($selectedFinish, $fv) || admin_select_value_matches($selectedFinish, $fl))) ? ' selected' : '';
                          if ($finSel !== '') { $finishHasCurrent = true; }
                      ?>
                      <option value="<?= h($fv) ?>" data-finish-label="<?= h($fl) ?>"<?= $finSel ?>><?= h($fl !== '' ? $fl : $fv) ?></option>
                      <?php endforeach; ?>
                      <?php if (!$finishHasCurrent && $selectedFinish !== ''): ?>
                      <option value="<?= h($selectedFinish) ?>" data-finish-label="<?= h($selectedFinish) ?>" selected><?= h($selectedFinish) ?></option>
                      <?php endif; ?>
                    </select>
                    <?php else: ?>
                    <input type="text" class="admin-input admin-hardware-finish-text" value="<?= h($selectedFinish) ?>" readonly>
                    <?php endif; ?>
                  </label>
                  <?php endif; ?>
                  <?php if ($functionAvailable && (!empty($functionChoices) || $selectedFunction !== '')): ?>
                  <label class="admin-casing-field">
                    <span class="admin-casing-field__label">Hardware Function</span>
                    <?php if (!empty($functionChoices)): ?>
                    <select class="admin-select admin-hardware-function">
                      <?php foreach ($functionChoices as $fnc):
                          $fnv = (string)($fnc['value'] ?? '');
                          $fnl = (string)($fnc['label'] ?? $fnv);
                          $fnSel = ($selectedFunction !== '' && ($fnv === $selectedFunction || $fnl === $selectedFunction)) ? ' selected' : '';
                      ?>
                      <option value="<?= h($fnv) ?>" data-function-label="<?= h($fnl) ?>"<?= $fnSel ?>><?= h($fnl) ?></option>
                      <?php endforeach; ?>
                    </select>
                    <?php else: ?>
                    <input type="text" class="admin-input" value="<?= h($selectedFunction) ?>" readonly>
                    <?php endif; ?>
                  </label>
                  <?php endif; ?>
                  <?php if ($thicknessAvailable && (!empty($thicknessChoices) || $selectedThickness !== '')): ?>
                  <label class="admin-casing-field">
                    <span class="admin-casing-field__label">Door Thickness</span>
                    <?php if (!empty($thicknessChoices)): ?>
                    <select class="admin-select admin-hardware-thickness">
                      <?php foreach ($thicknessChoices as $tc):
                          $tv = (string)($tc['value'] ?? '');
                          $tl = (string)($tc['label'] ?? $tv);
                          $tSel = ($selectedThickness !== '' && ($tv === $selectedThickness || $tl === $selectedThickness)) ? ' selected' : '';
                      ?>
                      <option value="<?= h($tv) ?>" data-thickness-label="<?= h($tl) ?>"<?= $tSel ?>><?= h($tl) ?></option>
                      <?php endforeach; ?>
                    </select>
                    <?php else: ?>
                    <input type="text" class="admin-input" value="<?= h($selectedThickness) ?>" readonly>
                    <?php endif; ?>
                  </label>
                  <?php endif; ?>
                  <?php foreach ($hwExtraFields as $hwExtra):
                      if (!is_array($hwExtra['def'])) continue;
                      $hwDef = $hwExtra['def'];
                      $hwUiLabel = (string)($hwDef['prop_label'] ?? '');
                      $hwDataKey = (string)($hwDef['label_key'] ?? '');
                      $hwSelected = (string)($hwExtra['selected'] ?? '');
                      $hwChoices = (isset($hwExtra['choices']) && is_array($hwExtra['choices'])) ? $hwExtra['choices'] : [];
                      if (empty($hwChoices) && $hwSelected === '') continue;
                  ?>
                  <label class="admin-casing-field">
                    <span class="admin-casing-field__label"><?= h($hwUiLabel) ?></span>
                    <?php if (!empty($hwChoices)): ?>
                    <select class="admin-select admin-hardware-extra" data-hw-field="<?= h($hwDataKey) ?>">
                      <?php $hwExtraHasCurrent = false; foreach ($hwChoices as $hc):
                          $hv = (string)($hc['value'] ?? '');
                          $hl = (string)($hc['label'] ?? $hv);
                          $hSel = ($hwSelected !== '' && (admin_select_value_matches($hwSelected, $hv) || admin_select_value_matches($hwSelected, $hl))) ? ' selected' : '';
                          if ($hSel !== '') { $hwExtraHasCurrent = true; }
                      ?>
                      <option value="<?= h($hv) ?>" data-hw-extra-label="<?= h($hl) ?>"<?= $hSel ?>><?= h($hl !== '' ? $hl : $hv) ?></option>
                      <?php endforeach; ?>
                      <?php if (!$hwExtraHasCurrent && $hwSelected !== ''): ?>
                      <option value="<?= h($hwSelected) ?>" data-hw-extra-label="<?= h($hwSelected) ?>" selected><?= h($hwSelected) ?></option>
                      <?php endif; ?>
                    </select>
                    <?php else: ?>
                    <input type="text" class="admin-input" value="<?= h($hwSelected) ?>" readonly>
                    <?php endif; ?>
                  </label>
                  <?php endforeach; ?>
                  <label class="admin-casing-field admin-casing-field--qty">
                    <span class="admin-casing-field__label">QTY</span>
                    <input type="number" class="admin-input admin-hardware-qty" min="1" step="1" value="<?= (int)$hwQty ?>">
                  </label>
                </div>
              </div>
            </div>
            <?php endforeach; ?>
          <?php endif; ?>
        </div>
        <input type="hidden" name="opt_hardware_options_json" id="opt-hardware-options-json" value="<?= h(json_encode($hwItems, JSON_UNESCAPED_UNICODE)) ?>">
        <?php elseif ($type === 'casing_multi'):
            if ($renderedCasingOptionsUi || empty($storefrontCasingSelections)) {
                continue;
            }
            $renderedCasingOptionsUi = true;
            $casingItems = admin_deduplicate_casing_selections(admin_resolve_casing_selections($options));
            if (empty($casingItems) && is_array($current) && isset($current[0]) && is_array($current[0])) {
                $casingItems = admin_normalize_casing_selections($current);
            }
        ?>
        <div class="admin-casing-selections" data-admin-casing-root="1">
          <?php if (!$casingItems): ?>
            <p class="admin-form-hint">No casing added on the storefront.</p>
          <?php else: ?>
            <?php foreach ($casingItems as $ci => $item):
                if (!is_array($item)) continue;
                $casingTitle = trim((string)($item['title'] ?? $item['product_id'] ?? ''));
                if ($casingTitle === '') continue;
                $casingSku = trim((string)($item['sku'] ?? ''));
                if ($casingSku !== '' && stripos($casingTitle, $casingSku) === false) {
                    $casingTitle .= ' / ' . $casingSku;
                }
                $casingImage = trim((string)($item['image'] ?? ''));
                $casingQty = max(1, (int)($item['qty'] ?? 1));
                $casingPrice = trim((string)($item['price_formatted'] ?? ''));
                $lengthChoices = admin_casing_length_choices_for_item($item);
                $selectedLength = trim((string)($item['length_value'] ?? $item['length_label'] ?? ''));
            ?>
            <div class="admin-casing-card" data-casing-index="<?= (int)$ci ?>">
              <?php if ($casingImage !== ''): ?>
                <img src="<?= h($casingImage) ?>" alt="" class="admin-choice-thumb admin-casing-card__image">
              <?php else: ?>
                <div class="admin-choice-thumb admin-casing-card__image admin-casing-card__image--placeholder" aria-hidden="true"></div>
              <?php endif; ?>
              <div class="admin-casing-card__body">
                <p class="admin-casing-card__title"><?= h($casingTitle) ?></p>
                <?php if ($casingPrice !== ''): ?>
                  <p class="admin-casing-card__price"><?= h($casingPrice) ?> as configured</p>
                <?php endif; ?>
                <div class="admin-casing-card__controls">
                  <label class="admin-casing-field">
                    <span class="admin-casing-field__label">Length</span>
                    <select class="admin-select admin-casing-length">
                      <?php foreach ($lengthChoices as $lc):
                          $lv = (string)($lc['value'] ?? '');
                          $ll = (string)($lc['label'] ?? $lv);
                          $lenSel = ($selectedLength !== '' && ($lv === $selectedLength || $ll === $selectedLength)) ? ' selected' : '';
                      ?>
                      <option value="<?= h($lv) ?>" data-length-label="<?= h($ll) ?>"<?= $lenSel ?>><?= h($ll) ?></option>
                      <?php endforeach; ?>
                    </select>
                  </label>
                  <label class="admin-casing-field admin-casing-field--qty">
                    <span class="admin-casing-field__label">QTY</span>
                    <input type="number" class="admin-input admin-casing-qty" min="1" step="1" value="<?= (int)$casingQty ?>">
                  </label>
                </div>
              </div>
            </div>
            <?php endforeach; ?>
          <?php endif; ?>
        </div>
        <input type="hidden" name="opt_casing_options_json" id="opt-casing-options-json" value="<?= h(json_encode($casingItems, JSON_UNESCAPED_UNICODE)) ?>">
        <?php endif; ?>
        </div>
        <?php
                }
            ?>
              </div>
            </details>
            <?php
                $isFirstOptionAccordion = false;
            }
            // Customer "Selected options" that aren't editable via the schema loop above
            // (e.g. millwork Length / Custom Thickness / Wood Species). Rendered as editable
            // dropdowns when choices are known, otherwise editable text — mirrors casing/hardware.
            $selectedOptionFields = admin_resolve_selected_option_fields($options);
        ?>
            <?php if (!empty($selectedOptionFields)): ?>
            <details class="admin-option-accordion">
              <summary class="admin-option-accordion-summary">Selected options</summary>
              <div class="admin-option-accordion-body">
                <div class="admin-option-row" data-option-id="selected_options">
                  <div class="admin-selected-options" data-admin-selected-options-root="1">
                    <div class="admin-casing-card admin-selected-option-card">
                      <div class="admin-casing-card__body">
                        <div class="admin-casing-card__controls">
                          <?php foreach ($selectedOptionFields as $si => $field):
                              if (!is_array($field)) continue;
                              $field = admin_enrich_selected_option_field_values($field);
                              $fLabel = (string)($field['label'] ?? '');
                              $fValue = (string)($field['value'] ?? '');
                              $fStorage = (string)($field['storage_value'] ?? '');
                              $fSource = (string)($field['source'] ?? '');
                              $fId = (string)($field['id'] ?? '');
                              $fChoices = admin_normalize_choice_list(
                                  (isset($field['choices']) && is_array($field['choices'])) ? $field['choices'] : []
                              );
                              $fUseSelect = admin_count_renderable_selected_option_choices($fChoices) > 0;
                          ?>
                          <label class="admin-casing-field admin-selected-option-field"
                                 data-selected-index="<?= (int)$si ?>"
                                 data-selected-label="<?= h($fLabel) ?>"
                                 data-selected-source="<?= h($fSource) ?>"
                                 data-selected-id="<?= h($fId) ?>">
                            <span class="admin-casing-field__label"><?= h($fLabel) ?></span>
                            <?php if ($fUseSelect):
                                $hasCurrent = false;
                            ?>
                            <select class="admin-select admin-selected-option-value">
                              <?php foreach ($fChoices as $c):
                                  $cv = (string)($c['value'] ?? '');
                                  $cl = (string)($c['label'] ?? $cv);
                                  if ($cv === '' && $cl === '') continue;
                                  $sel = admin_selected_option_field_is_selected($field, $cv, $cl) ? ' selected' : '';
                                  if ($sel !== '') $hasCurrent = true;
                              ?>
                              <option value="<?= h($cv) ?>" data-choice-label="<?= h($cl) ?>"<?= $sel ?>><?= h($cl !== '' ? $cl : $cv) ?></option>
                              <?php endforeach; ?>
                              <?php if (!$hasCurrent && ($fValue !== '' || $fStorage !== '')):
                                  $fbVal = $fStorage !== '' ? $fStorage : $fValue;
                                  $fbLab = $fValue !== '' ? $fValue : $fStorage;
                              ?>
                              <option value="<?= h($fbVal) ?>" data-choice-label="<?= h($fbLab) ?>" selected><?= h($fbLab) ?></option>
                              <?php endif; ?>
                            </select>
                            <?php else: ?>
                            <input type="text" class="admin-input admin-selected-option-value" value="<?= h($fValue !== '' ? $fValue : $fStorage) ?>">
                            <?php endif; ?>
                          </label>
                          <?php endforeach; ?>
                        </div>
                      </div>
                    </div>
                  </div>
                  <input type="hidden" name="opt_selected_options_json" id="opt-selected-options-json" value="<?= h(json_encode($selectedOptionFields, JSON_UNESCAPED_UNICODE)) ?>">
                </div>
              </div>
            </details>
            <?php endif; ?>
        <?php
        } else {
          $fallbackHardware = admin_resolve_hardware_selections($options);
          $fallbackCasing = !empty($storefrontCasingSelections)
              ? admin_deduplicate_casing_selections(admin_resolve_casing_selections($options))
              : [];
          $selectedOptionFields = admin_resolve_selected_option_fields($options);
        ?>
        <p class="admin-form-hint">This configuration was saved without `_pricing_schema`, so interactive option controls cannot be rebuilt. Showing saved selected options below.</p>
        <?php if (!empty($fallbackHardware)): ?>
          <div class="admin-option-row" data-option-id="hardware_options">
            <label class="admin-label">Hardware</label>
            <div class="admin-hardware-selections admin-hardware-selections--readonly">
              <?php foreach ($fallbackHardware as $item):
                  if (!is_array($item)) continue;
                  $t = trim((string)($item['title'] ?? $item['product_id'] ?? ''));
                  if ($t === '') continue;
                  $img = trim((string)($item['image'] ?? ''));
                  $fin = trim((string)($item['finish_label'] ?? ''));
                  $fn = trim((string)($item['function_label'] ?? ''));
                  $thick = trim((string)($item['thickness_label'] ?? ''));
                  if ($thick === '' && !empty($item['thickness_value'])) {
                      $thick = humanize_token($item['thickness_value']);
                  }
                  $q = max(1, (int)($item['qty'] ?? 1));
              ?>
              <div class="admin-casing-card admin-hardware-card">
                <?php if ($img !== ''): ?>
                  <img src="<?= h($img) ?>" alt="" class="admin-choice-thumb admin-casing-card__image">
                <?php endif; ?>
                <div class="admin-casing-card__body">
                  <p class="admin-casing-card__title"><?= h($t) ?></p>
                  <?php if ($fin !== ''): ?><p class="admin-form-hint">Finish: <?= h($fin) ?></p><?php endif; ?>
                  <?php if ($fn !== ''): ?><p class="admin-form-hint">Function: <?= h($fn) ?></p><?php endif; ?>
                  <?php if ($thick !== ''): ?><p class="admin-form-hint">Door Thickness: <?= h($thick) ?></p><?php endif; ?>
                  <?php if ($q > 1): ?><p class="admin-form-hint">QTY: <?= (int)$q ?></p><?php endif; ?>
                </div>
              </div>
              <?php endforeach; ?>
            </div>
          </div>
        <?php endif; ?>
        <?php if (!empty($fallbackCasing)): ?>
          <div class="admin-option-row" data-option-id="casing_options">
            <label class="admin-label">Casing</label>
            <div class="admin-casing-selections admin-casing-selections--readonly">
              <?php foreach ($fallbackCasing as $item):
                  if (!is_array($item)) continue;
                  $t = trim((string)($item['title'] ?? $item['product_id'] ?? ''));
                  if ($t === '') continue;
                  $sku = trim((string)($item['sku'] ?? ''));
                  if ($sku !== '' && stripos($t, $sku) === false) {
                      $t .= ' / ' . $sku;
                  }
                  $img = trim((string)($item['image'] ?? ''));
                  $len = trim((string)($item['length_label'] ?? $item['length_value'] ?? ''));
                  $q = max(1, (int)($item['qty'] ?? 1));
              ?>
              <div class="admin-casing-card">
                <?php if ($img !== ''): ?>
                  <img src="<?= h($img) ?>" alt="" class="admin-choice-thumb admin-casing-card__image">
                <?php endif; ?>
                <div class="admin-casing-card__body">
                  <p class="admin-casing-card__title"><?= h($t) ?></p>
                  <?php if ($len !== ''): ?><p class="admin-form-hint">Length: <?= h($len) ?></p><?php endif; ?>
                  <?php if ($q > 1): ?><p class="admin-form-hint">QTY: <?= (int)$q ?></p><?php endif; ?>
                </div>
              </div>
              <?php endforeach; ?>
            </div>
          </div>
        <?php endif; ?>
        <?php if (!empty($selectedOptionFields)): ?>
            <details class="admin-option-accordion" open>
              <summary class="admin-option-accordion-summary">Selected options</summary>
              <div class="admin-option-accordion-body">
                <div class="admin-option-row" data-option-id="selected_options">
                  <div class="admin-selected-options" data-admin-selected-options-root="1">
                    <div class="admin-casing-card admin-selected-option-card">
                      <div class="admin-casing-card__body">
                        <div class="admin-casing-card__controls">
                          <?php foreach ($selectedOptionFields as $si => $field):
                              if (!is_array($field)) continue;
                              $field = admin_enrich_selected_option_field_values($field);
                              $fLabel = (string)($field['label'] ?? '');
                              $fValue = (string)($field['value'] ?? '');
                              $fStorage = (string)($field['storage_value'] ?? '');
                              $fSource = (string)($field['source'] ?? '');
                              $fId = (string)($field['id'] ?? '');
                              $fChoices = admin_normalize_choice_list(
                                  (isset($field['choices']) && is_array($field['choices'])) ? $field['choices'] : []
                              );
                              $fUseSelect = admin_count_renderable_selected_option_choices($fChoices) > 0;
                          ?>
                          <label class="admin-casing-field admin-selected-option-field"
                                 data-selected-index="<?= (int)$si ?>"
                                 data-selected-label="<?= h($fLabel) ?>"
                                 data-selected-source="<?= h($fSource) ?>"
                                 data-selected-id="<?= h($fId) ?>">
                            <span class="admin-casing-field__label"><?= h($fLabel) ?></span>
                            <?php if ($fUseSelect):
                                $hasCurrent = false;
                            ?>
                            <select class="admin-select admin-selected-option-value">
                              <?php foreach ($fChoices as $c):
                                  $cv = (string)($c['value'] ?? '');
                                  $cl = (string)($c['label'] ?? $cv);
                                  if ($cv === '' && $cl === '') continue;
                                  $sel = admin_selected_option_field_is_selected($field, $cv, $cl) ? ' selected' : '';
                                  if ($sel !== '') $hasCurrent = true;
                              ?>
                              <option value="<?= h($cv) ?>" data-choice-label="<?= h($cl) ?>"<?= $sel ?>><?= h($cl !== '' ? $cl : $cv) ?></option>
                              <?php endforeach; ?>
                              <?php if (!$hasCurrent && ($fValue !== '' || $fStorage !== '')):
                                  $fbVal = $fStorage !== '' ? $fStorage : $fValue;
                                  $fbLab = $fValue !== '' ? $fValue : $fStorage;
                              ?>
                              <option value="<?= h($fbVal) ?>" data-choice-label="<?= h($fbLab) ?>" selected><?= h($fbLab) ?></option>
                              <?php endif; ?>
                            </select>
                            <?php else: ?>
                            <input type="text" class="admin-input admin-selected-option-value" value="<?= h($fValue !== '' ? $fValue : $fStorage) ?>">
                            <?php endif; ?>
                          </label>
                          <?php endforeach; ?>
                        </div>
                      </div>
                    </div>
                  </div>
                  <input type="hidden" name="opt_selected_options_json" id="opt-selected-options-json" value="<?= h(json_encode($selectedOptionFields, JSON_UNESCAPED_UNICODE)) ?>">
                </div>
              </div>
            </details>
        <?php elseif (empty($fallbackHardware) && empty($fallbackCasing)): ?>
          <p class="admin-form-hint">No selected options found in saved payload.</p>
        <?php endif; ?>
        <?php } ?>
        <div class="admin-form-group">
          <label class="admin-label">Notes from sales</label>
          <textarea name="notes_sales" class="admin-textarea" rows="3" placeholder="Internal notes..."><?= h($config['notes_sales'] ?? '') ?></textarea>
        </div>
        <div class="admin-form-group">
          <label class="admin-label">Draft order line item title</label>
          <label class="admin-checkbox-label" style="margin-bottom:0.75rem;">
            <input type="checkbox" name="admin_use_custom_draft_title" value="1" id="admin-use-custom-draft-title"<?= $adminUseCustomDraftTitle ? ' checked' : '' ?>>
            Use custom product title on draft order
          </label>
          <input
            type="text"
            name="admin_draft_order_title"
            id="admin-draft-order-title"
            class="admin-input"
            placeholder="<?= h($defaultProductTitle !== '' ? $defaultProductTitle : 'Custom door title') ?>"
            value="<?= h($adminDraftOrderTitle) ?>"
            <?= $adminUseCustomDraftTitle ? '' : ' disabled' ?>
          >
          <p class="admin-form-hint">
            When unchecked, draft orders use <strong>Custom <?= h($defaultProductTitle !== '' ? $defaultProductTitle : 'product name') ?></strong>.
            When checked, the text above is used exactly as the Shopify line item title. Click <strong>Save</strong> before creating a draft order.
          </p>
        </div>
        <div class="admin-form-group">
          <label class="admin-label">Order total price override</label>
          <input
            type="number"
            name="admin_order_total_override"
            step="0.01"
            min="0"
            class="admin-input"
            placeholder="Total order price (excl. tax &amp; shipping)"
            value="<?= $adminOrderTotalOverride !== null ? h(number_format($adminOrderTotalOverride, 2, '.', '')) : '' ?>"
          >
          <p class="admin-form-hint">Optional. Total order price for this configuration (quantity <?= h($selectedQty) ?> included). Excludes tax and shipping. Used when creating a Shopify draft order; you can also adjust price in Shopify Admin after the order is created.</p>
        </div>
        <div class="admin-form-group">
          <label class="admin-label">Line item properties override</label>
          <textarea
            name="admin_line_item_properties_override"
            class="admin-textarea"
            rows="6"
            placeholder="Wood Type: White Oak&#10;Door Height: 80 in"
          ><?= h($adminLineItemPropsOverride) ?></textarea>
          <p class="admin-form-hint">Optional. Appended to Shopify line item properties on draft order. One per line: <code>Label: Value</code> (e.g. <code>SDL Profile: Bell Ogee</code>) or JSON. Click <strong>Save</strong> before creating the draft order.</p>
        </div>

        <div class="admin-form-group admin-image-upload-block">
          <label class="admin-label">Product Custom image</label>
          <input type="hidden" name="custom_image_url" id="custom-image-url" value="<?= h($customImageUrl) ?>">
          <p class="admin-form-hint">Uploaded to Shopify. Click <strong>Save</strong> to store the URL. Draft order line item property: <code>custom_image_url</code>.</p>
          <div class="admin-image-preview-wrap" id="custom-image-preview-wrap">
            <div class="admin-image-preview-item<?= $customImageUrl === '' ? ' admin-image-preview-item--placeholder' : '' ?>" id="custom-image-preview-item">
              <button type="button" id="custom-image-remove" aria-label="Remove custom image"<?= $customImageUrl === '' ? ' hidden' : '' ?>>&times;</button>
              <img
                src="<?= $customImageUrl !== '' ? h($customImageUrl) : h($adminImagePlaceholder) ?>"
                alt="<?= $customImageUrl !== '' ? 'Custom image preview' : 'No image uploaded yet' ?>"
                id="custom-image-preview-img"
                class="<?= $customImageUrl === '' ? 'admin-image-preview-img--placeholder' : '' ?>"
              >
              <p class="admin-image-preview-caption<?= $customImageUrl !== '' ? ' is-done' : '' ?>" id="custom-image-preview-caption"><?= $customImageUrl !== '' ? 'Upload done' : 'No image uploaded yet' ?></p>
            </div>
          </div>
          <div class="admin-image-upload-actions">
            <input type="file" id="custom-image-file" accept="image/*"<?= $customImageUrl !== '' ? ' hidden' : '' ?>>
            <button type="button" class="admin-btn" id="custom-image-upload-btn"<?= $customImageUrl !== '' ? ' hidden' : '' ?>>Upload to Shopify</button>
            <button type="button" class="admin-btn" id="custom-image-clear-btn"<?= $customImageUrl === '' ? ' hidden' : '' ?>>Remove</button>
          </div>
          <p class="admin-image-upload-status" id="custom-image-status" hidden></p>
        </div>

        <div class="admin-form-group admin-image-upload-block">
          <label class="admin-label">Internal images</label>
          <input type="hidden" name="internal_images_json" id="internal-images-json" value="<?= h(json_encode($internalImages, JSON_UNESCAPED_SLASHES)) ?>">
          <p class="admin-form-hint">For internal reference only — not included on draft orders or PandaDoc documents.</p>
          <div class="admin-image-preview-wrap" id="internal-images-preview-wrap"></div>
          <div class="admin-image-upload-actions">
            <input type="file" id="internal-images-file" accept="image/*" multiple>
            <button type="button" class="admin-btn" id="internal-images-upload-btn">Upload selected</button>
          </div>
          <p class="admin-image-upload-status" id="internal-images-status" hidden></p>
        </div>

        <div class="admin-form-actions">
        <button type="submit" class="admin-btn admin-btn--primary" id="admin-save-btn" data-save-trigger="1">Save</button>
        <button type="submit" class="admin-btn admin-btn--secondary1" name="action" value="preview_quote"
          formaction="configuration_quote_preview.php"
          formtarget="_blank" formnovalidate>Preview quote email</button>
        </div>
      </form>
    </div>

  </div>
  </main>

  <?php if (!empty($schema) && is_array($schema)):
        $adminPricingBootSavedOptions = [];
        foreach ($options as $bootKey => $bootVal) {
            if (!is_string($bootKey) || $bootKey === '' || $bootKey[0] === '_') {
                continue;
            }
            $adminPricingBootSavedOptions[$bootKey] = $bootVal;
        }
  ?>
  <script type="application/json" id="admin-pricing-boot"><?=
    json_encode(
        [
            'basePrice' => (float)($config['base_price'] ?? 0),
            'schema' => $schema,
            'savedOptions' => $adminPricingBootSavedOptions,
            'addonBreakdown' => (isset($options['_addon_breakdown']) && is_array($options['_addon_breakdown']))
                ? $options['_addon_breakdown'] : [],
            'optionAddonBreakdownKeys' => admin_option_addon_breakdown_key_map(),
            'measurementAddonBreakdownKeys' => admin_measurement_addon_breakdown_keys_catalog(),
            'allMeasurementAddonBreakdownKeys' => admin_all_measurement_addon_breakdown_keys(),
            'inferredMeasurementType' => admin_resolve_measurement_type_value($options),
        ],
        JSON_UNESCAPED_UNICODE | JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS
    )
  ?></script>
  <?php endif; ?>

  <script>
    (function () {
      var ADMIN_UPLOAD_IMAGE_URL = <?= json_encode($adminUploadImageApiUrl) ?>;
      var ADMIN_IMAGE_PLACEHOLDER = <?= json_encode($adminImagePlaceholder) ?>;

      var customDraftTitleCheckbox = document.getElementById('admin-use-custom-draft-title');
      var customDraftTitleInput = document.getElementById('admin-draft-order-title');
      if (customDraftTitleCheckbox && customDraftTitleInput) {
        function syncCustomDraftTitleInput() {
          customDraftTitleInput.disabled = !customDraftTitleCheckbox.checked;
        }
        customDraftTitleCheckbox.addEventListener('change', syncCustomDraftTitleInput);
        syncCustomDraftTitleInput();
      }

      function uploadImageToShopify(file, statusEl) {
        var fd = new FormData();
        fd.append('file', file);
        if (statusEl) {
          statusEl.hidden = false;
          statusEl.classList.remove('is-error');
          statusEl.textContent = 'Uploading ' + (file.name || 'image') + '…';
        }
        return fetch(ADMIN_UPLOAD_IMAGE_URL, {
          method: 'POST',
          body: fd,
          credentials: 'same-origin'
        })
          .then(function (res) {
            return res.json().then(function (data) {
              return { ok: res.ok, data: data };
            });
          })
          .then(function (result) {
            if (!result.ok || !result.data || !result.data.success || !result.data.url) {
              throw new Error((result.data && result.data.error) || 'Upload failed');
            }
            if (statusEl) {
              statusEl.textContent = 'Uploaded to Shopify.';
            }
            return result.data.url;
          })
          .catch(function (err) {
            if (statusEl) {
              statusEl.hidden = false;
              statusEl.classList.add('is-error');
              statusEl.textContent = err.message || 'Upload failed';
            }
            throw err;
          });
      }

      function initConfigImageUploads() {
        var customUrlInput = document.getElementById('custom-image-url');
        var customFileInput = document.getElementById('custom-image-file');
        var customUploadBtn = document.getElementById('custom-image-upload-btn');
        var customClearBtn = document.getElementById('custom-image-clear-btn');
        var customPreviewWrap = document.getElementById('custom-image-preview-wrap');
        var customPreviewImg = document.getElementById('custom-image-preview-img');
        var customPreviewCaption = document.getElementById('custom-image-preview-caption');
        var customPreviewItem = document.getElementById('custom-image-preview-item');
        var customRemoveBtn = document.getElementById('custom-image-remove');
        var customStatus = document.getElementById('custom-image-status');
        var internalJsonInput = document.getElementById('internal-images-json');
        var internalPreviewWrap = document.getElementById('internal-images-preview-wrap');
        var internalFileInput = document.getElementById('internal-images-file');
        var internalUploadBtn = document.getElementById('internal-images-upload-btn');
        var internalStatus = document.getElementById('internal-images-status');
        var customPendingObjectUrl = null;
        var internalPendingPreviews = [];

        function revokeObjectUrl(url) {
          if (url) {
            try { URL.revokeObjectURL(url); } catch (e) {}
          }
        }

        function revokeCustomPendingUrl() {
          revokeObjectUrl(customPendingObjectUrl);
          customPendingObjectUrl = null;
        }

        function revokeInternalPendingUrls() {
          internalPendingPreviews.forEach(function (entry) {
            revokeObjectUrl(entry.objectUrl);
          });
          internalPendingPreviews = [];
        }

        function setInternalFileInputFiles(files) {
          if (!internalFileInput || typeof DataTransfer === 'undefined') return;
          var dt = new DataTransfer();
          files.forEach(function (file) { dt.items.add(file); });
          internalFileInput.files = dt.files;
        }

        function openFullImagePreview(src) {
          var url = String(src || '').trim();
          if (!url || url === ADMIN_IMAGE_PLACEHOLDER) return;
          window.open(url, '_blank', 'noopener,noreferrer');
        }

        function syncCustomPreviewClickable() {
          if (!customPreviewImg) return;
          var clickable = !customPreviewImg.classList.contains('admin-image-preview-img--placeholder')
            && String(customPreviewImg.src || '').trim() !== ''
            && customPreviewImg.src !== ADMIN_IMAGE_PLACEHOLDER;
          customPreviewImg.classList.toggle('admin-image-preview-img--clickable', clickable);
          customPreviewImg.title = clickable ? 'Click to view full image' : '';
        }

        function readInternalImages() {
          if (!internalJsonInput) return [];
          try {
            var parsed = JSON.parse(internalJsonInput.value || '[]');
            return Array.isArray(parsed) ? parsed.filter(function (url) { return String(url || '').trim() !== ''; }) : [];
          } catch (e) {
            return [];
          }
        }

        function writeInternalImages(urls) {
          if (!internalJsonInput) return;
          internalJsonInput.value = JSON.stringify(urls);
        }

        function appendInternalPreviewItem(container, opts) {
          var item = document.createElement('div');
          item.className = 'admin-image-preview-item'
            + (opts.placeholderItem ? ' admin-image-preview-item--placeholder' : '')
            + (opts.pending ? ' admin-image-preview-item--pending' : '');
          if (opts.removeHandler) {
            var removeBtn = document.createElement('button');
            removeBtn.type = 'button';
            removeBtn.setAttribute('aria-label', 'Remove image');
            removeBtn.textContent = '×';
            removeBtn.addEventListener('click', opts.removeHandler);
            item.appendChild(removeBtn);
          }
          var img = document.createElement('img');
          img.src = opts.src;
          img.alt = opts.alt || 'Image preview';
          if (opts.placeholder) {
            img.className = 'admin-image-preview-img--placeholder';
          } else {
            img.className = 'admin-image-preview-img--clickable';
            img.title = 'Click to view full image';
            img.addEventListener('click', function () {
              openFullImagePreview(opts.src);
            });
          }
          item.appendChild(img);
          if (opts.caption) {
            var cap = document.createElement('p');
            cap.className = 'admin-image-preview-caption'
              + (opts.pending ? ' admin-image-preview-caption--pending' : '')
              + (opts.caption === 'Upload done' ? ' is-done' : '');
            cap.textContent = opts.caption;
            item.appendChild(cap);
          }
          if (opts.filename) {
            var fname = document.createElement('p');
            fname.className = 'admin-image-preview-filename';
            fname.textContent = opts.filename;
            item.appendChild(fname);
          }
          container.appendChild(item);
        }

        function syncCustomUploadUi(mode) {
          var uploaded = mode === 'uploaded';
          var pending = mode === 'pending';
          if (customUploadBtn) customUploadBtn.hidden = uploaded;
          if (customFileInput) customFileInput.hidden = uploaded;
          if (customClearBtn) customClearBtn.hidden = !uploaded && !pending;
        }

        function renderInternalImages() {
          if (!internalPreviewWrap) return;
          var urls = readInternalImages();
          var pending = internalPendingPreviews.slice();
          internalPreviewWrap.innerHTML = '';
          internalPreviewWrap.hidden = false;
          if (!urls.length && !pending.length) {
            appendInternalPreviewItem(internalPreviewWrap, {
              src: ADMIN_IMAGE_PLACEHOLDER,
              alt: 'No internal images yet',
              placeholder: true,
              placeholderItem: true,
              caption: 'No images yet'
            });
            return;
          }
          urls.forEach(function (url, index) {
            appendInternalPreviewItem(internalPreviewWrap, {
              src: url,
              alt: 'Internal image ' + (index + 1),
              caption: 'Upload done',
              removeHandler: function () {
                var next = readInternalImages().filter(function (_, i) { return i !== index; });
                writeInternalImages(next);
                renderInternalImages();
              }
            });
          });
          pending.forEach(function (entry, index) {
            appendInternalPreviewItem(internalPreviewWrap, {
              src: entry.objectUrl,
              alt: 'Pending internal image ' + (index + 1),
              pending: true,
              filename: entry.file && entry.file.name ? entry.file.name : '',
              removeHandler: function () {
                revokeObjectUrl(entry.objectUrl);
                internalPendingPreviews = internalPendingPreviews.filter(function (_, i) { return i !== index; });
                setInternalFileInputFiles(internalPendingPreviews.map(function (p) { return p.file; }));
                renderInternalImages();
              }
            });
          });
        }

        function syncInternalPendingFromInput() {
          revokeInternalPendingUrls();
          var files = internalFileInput && internalFileInput.files
            ? Array.prototype.slice.call(internalFileInput.files)
            : [];
          internalPendingPreviews = files.map(function (file, index) {
            return {
              id: 'pending-' + index + '-' + Date.now(),
              file: file,
              objectUrl: URL.createObjectURL(file)
            };
          });
          renderInternalImages();
        }

        function setCustomImage(url) {
          if (!customUrlInput) return;
          var hasUrl = String(url || '').trim() !== '';
          customUrlInput.value = hasUrl ? url : '';
          if (customPreviewWrap) customPreviewWrap.hidden = false;
          if (customPreviewItem) {
            customPreviewItem.classList.remove('admin-image-preview-item--pending');
            customPreviewItem.classList.toggle('admin-image-preview-item--placeholder', !hasUrl);
          }
          if (customPreviewImg) {
            customPreviewImg.src = hasUrl ? url : ADMIN_IMAGE_PLACEHOLDER;
            customPreviewImg.classList.toggle('admin-image-preview-img--placeholder', !hasUrl);
            customPreviewImg.alt = hasUrl ? 'Custom image preview' : 'No image uploaded yet';
          }
          if (customPreviewCaption) {
            customPreviewCaption.hidden = false;
            customPreviewCaption.classList.remove('admin-image-preview-caption--pending');
            customPreviewCaption.textContent = hasUrl ? 'Upload done' : 'No image uploaded yet';
            customPreviewCaption.classList.toggle('is-done', hasUrl);
          }
          if (customRemoveBtn) customRemoveBtn.hidden = !hasUrl;
          syncCustomUploadUi(hasUrl ? 'uploaded' : 'empty');
          syncCustomPreviewClickable();
        }

        function previewCustomLocalFile(file) {
          if (!file || !customPreviewImg) return;
          revokeCustomPendingUrl();
          customPendingObjectUrl = URL.createObjectURL(file);
          if (customPreviewWrap) customPreviewWrap.hidden = false;
          if (customPreviewItem) {
            customPreviewItem.classList.add('admin-image-preview-item--pending');
            customPreviewItem.classList.remove('admin-image-preview-item--placeholder');
          }
          customPreviewImg.src = customPendingObjectUrl;
          customPreviewImg.classList.remove('admin-image-preview-img--placeholder');
          customPreviewImg.alt = 'Selected image preview — click to view full size';
          if (customPreviewCaption) {
            customPreviewCaption.hidden = true;
            customPreviewCaption.classList.remove('admin-image-preview-caption--pending');
          }
          if (customRemoveBtn) customRemoveBtn.hidden = false;
          syncCustomUploadUi('pending');
          syncCustomPreviewClickable();
        }

        if (customPreviewImg) {
          customPreviewImg.addEventListener('click', function () {
            if (!customPreviewImg.classList.contains('admin-image-preview-img--clickable')) return;
            openFullImagePreview(customPreviewImg.src);
          });
        }

        function clearCustomImage() {
          revokeCustomPendingUrl();
          if (customFileInput) {
            customFileInput.value = '';
            customFileInput.hidden = false;
          }
          setCustomImage('');
          syncCustomUploadUi('empty');
          if (customStatus) {
            customStatus.hidden = true;
            customStatus.textContent = '';
            customStatus.classList.remove('is-error');
          }
        }

        if (customFileInput) {
          customFileInput.addEventListener('change', function () {
            var file = customFileInput.files && customFileInput.files[0];
            if (file) {
              previewCustomLocalFile(file);
              return;
            }
            revokeCustomPendingUrl();
            setCustomImage(customUrlInput ? customUrlInput.value : '');
          });
        }

        if (customUploadBtn && customFileInput) {
          customUploadBtn.addEventListener('click', function () {
            var file = customFileInput.files && customFileInput.files[0];
            if (!file) {
              if (customStatus) {
                customStatus.hidden = false;
                customStatus.classList.add('is-error');
                customStatus.textContent = 'Choose an image first.';
              }
              return;
            }
            customUploadBtn.disabled = true;
            uploadImageToShopify(file, customStatus)
              .then(function (url) {
                revokeCustomPendingUrl();
                setCustomImage(url);
                customFileInput.value = '';
              })
              .catch(function () {})
              .then(function () {
                customUploadBtn.disabled = false;
              });
          });
        }
        if (customClearBtn) customClearBtn.addEventListener('click', clearCustomImage);
        if (customRemoveBtn) customRemoveBtn.addEventListener('click', clearCustomImage);
        setCustomImage(customUrlInput ? customUrlInput.value : '');

        if (internalFileInput) {
          internalFileInput.addEventListener('change', syncInternalPendingFromInput);
        }

        if (internalUploadBtn && internalFileInput) {
          internalUploadBtn.addEventListener('click', function () {
            var files = internalFileInput.files ? Array.prototype.slice.call(internalFileInput.files) : [];
            if (!files.length) {
              if (internalStatus) {
                internalStatus.hidden = false;
                internalStatus.classList.add('is-error');
                internalStatus.textContent = 'Choose one or more images first.';
              }
              return;
            }
            internalUploadBtn.disabled = true;
            var urls = readInternalImages();
            var chain = Promise.resolve();
            files.forEach(function (file) {
              chain = chain.then(function () {
                return uploadImageToShopify(file, internalStatus).then(function (url) {
                  urls.push(url);
                });
              });
            });
            chain
              .then(function () {
                writeInternalImages(urls);
                revokeInternalPendingUrls();
                internalFileInput.value = '';
                renderInternalImages();
              })
              .catch(function () {})
              .then(function () {
                internalUploadBtn.disabled = false;
              });
          });
        }

        renderInternalImages();
      }

      function run() {
        initConfigImageUploads();
        var form = document.querySelector('form.admin-detail');
        if (!form) return;
        function getRefValue(ref) {
          var sel = form.querySelector('select[name="opt_' + ref + '"]');
          if (sel) return (sel.value || '').trim();
          var radio = form.querySelector('input[type="radio"][name="opt_' + ref + '"]:checked');
          if (radio) return (radio.value || '').trim();
          var checkboxes = form.querySelectorAll('input[type="checkbox"][name="opt_' + ref + '[]"]:checked');
          if (checkboxes && checkboxes.length) {
            var arr = [];
            for (var i = 0; i < checkboxes.length; i++) arr.push((checkboxes[i].value || '').trim());
            return arr;
          }
          return '';
        }
        function refMatchesVal(refVal, val) {
          val = String(val || '').trim();
          if (Array.isArray(refVal)) return refVal.indexOf(val) !== -1 || refVal.some(function (v) { return String(v) === val; });
          return String(refVal || '') === val;
        }
        var hideRows = form.querySelectorAll('.admin-option-row[data-hide-when-ref][data-hide-when-val]');
        var showRows = form.querySelectorAll('.admin-option-row[data-show-when-ref][data-show-when-val]');
        function toggleHideWhen(row) {
          var ref = row.getAttribute('data-hide-when-ref');
          var val = row.getAttribute('data-hide-when-val');
          if (!ref) return;
          var refVal = getRefValue(ref);
          row.classList.toggle('admin-hidden', refMatchesVal(refVal, val));
        }
        function toggleShowWhen(row) {
          var ref = row.getAttribute('data-show-when-ref');
          var val = row.getAttribute('data-show-when-val');
          if (!ref) return;
          var refVal = getRefValue(ref);
          row.classList.toggle('admin-hidden', !refMatchesVal(refVal, val));
        }
        var showOpts = form.querySelectorAll('select option[data-show-when-ref][data-show-when-val]');
        var hideOpts = form.querySelectorAll('select option[data-hide-when-ref][data-hide-when-val]');
        function updateOptionVisibility(opt) {
          var ref = opt.getAttribute('data-show-when-ref') || opt.getAttribute('data-hide-when-ref');
          var val = opt.getAttribute('data-show-when-val') || opt.getAttribute('data-hide-when-val');
          var isShow = opt.hasAttribute('data-show-when-ref');
          if (!ref) return;
          var refVal = getRefValue(ref);
          var match = refMatchesVal(refVal, val);
          opt.disabled = isShow ? !match : match;
        }
        function updateAll() {
          hideRows.forEach(toggleHideWhen);
          showRows.forEach(toggleShowWhen);
          showOpts.forEach(updateOptionVisibility);
          hideOpts.forEach(updateOptionVisibility);
          updateOptionSelectedPrices();
        }
        function formatOptionPrice(n, hasSelection) {
          n = parseFloat(n);
          if (isNaN(n)) n = 0;
          if (!hasSelection && Math.abs(n) < 0.005) return '';
          var abs = Math.abs(n);
          var s = abs.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
          return (n >= 0 ? '+$' : '-$') + s;
        }
        var pricingBoot = null;
        try {
          var bootEl = document.getElementById('admin-pricing-boot');
          if (bootEl) pricingBoot = JSON.parse(bootEl.textContent || '{}');
        } catch (ePricingBoot) {}
        function adminNormOptionValue(s) {
          return String(s == null ? '' : s).trim().toLowerCase();
        }
        function adminNormOptionId(s) {
          return adminNormOptionValue(String(s || '').replace(/-/g, '_'));
        }
        function adminConfigGetValue(options, key) {
          if (!options) return null;
          if (Object.prototype.hasOwnProperty.call(options, key)) return options[key];
          var target = adminNormOptionId(key);
          for (var k in options) {
            if (!Object.prototype.hasOwnProperty.call(options, k) || !k || k.charAt(0) === '_') continue;
            if (adminNormOptionId(k) === target) return options[k];
          }
          return null;
        }
        function adminOptionHasSelection(type, selected) {
          type = String(type || '').toLowerCase();
          if (type === 'checkbox') return Array.isArray(selected) && selected.length > 0;
          if (type === 'select' || type === 'radio') return selected != null && selected !== '';
          return false;
        }
        function adminOptionValueMatches(options, key, val) {
          var other = adminConfigGetValue(options, key);
          var target = adminNormOptionValue(val);
          if (Array.isArray(other)) {
            for (var i = 0; i < other.length; i++) {
              if (adminNormOptionValue(other[i]) === target) return true;
            }
            return false;
          }
          return adminNormOptionValue(other || '') === target;
        }
        function adminFindSchemaChoice(choices, selected) {
          if (!Array.isArray(choices)) return null;
          var selStr = String(selected == null ? '' : selected);
          for (var i = 0; i < choices.length; i++) {
            var c = choices[i];
            if (!c) continue;
            if (String(c.value == null ? '' : c.value) === selStr) return c;
          }
          var selNorm = adminNormOptionId(selStr);
          for (var j = 0; j < choices.length; j++) {
            var c2 = choices[j];
            if (!c2) continue;
            if (adminNormOptionId(c2.value == null ? '' : c2.value) === selNorm) return c2;
          }
          return null;
        }
        function adminNormalizePriceOverrides(choice) {
          if (!choice) return [];
          var overrides = choice.priceOverrides;
          if (Array.isArray(overrides) && overrides.length) return overrides;
          var raw = choice.priceOverridesRaw;
          for (var i = 0; i < 3; i++) {
            if (Array.isArray(raw)) return raw;
            if (typeof raw !== 'string' || !raw.trim()) break;
            try {
              var decoded = JSON.parse(raw);
              if (decoded === raw) break;
              raw = decoded;
            } catch (eDecode) { break; }
          }
          return Array.isArray(raw) ? raw : [];
        }
        function adminChoiceFieldTruthy(choice, key) {
          if (!choice || !key) return false;
          var v = choice[key];
          if (v == null) {
            var alt = key.indexOf('_') !== -1 ? key.replace(/_/g, '-') : key.replace(/-/g, '_');
            v = choice[alt];
          }
          if (v === true) return true;
          if (v === false || v == null) return false;
          if (typeof v === 'number') return v !== 0;
          var s = adminNormOptionValue(v);
          if (!s || s === 'false' || s === '0' || s === 'no' || s === 'off') return false;
          return true;
        }
        function adminPanelProfileGateOpen(options) {
          function enabled(key) {
            var v = adminConfigGetValue(options, key);
            if (v == null || v === '' || v === false) return false;
            if (Array.isArray(v)) {
              for (var i = 0; i < v.length; i++) {
                var s = adminNormOptionValue(v[i]);
                if (s && s !== 'false' && s !== '0') return true;
              }
              return false;
            }
            var s2 = adminNormOptionValue(v);
            return s2 !== '' && s2 !== 'false' && s2 !== '0';
          }
          return enabled('panel_int_ext') || enabled('panel_storm_panel');
        }
        function adminResolveChoicePriceAmount(choice, opt, options, basePrice) {
          if (!choice) return 0;
          var optId = adminNormOptionId(opt && opt.id);
          if (optId === 'panel_profile') {
            var byChoice = adminChoiceFieldTruthy(choice, 'panel_int_ext') || adminChoiceFieldTruthy(choice, 'panel_storm_panel');
            if (!byChoice && !adminPanelProfileGateOpen(options)) return 0;
          }
          var t = choice.priceType || choice.price_type;
          var v = parseFloat(choice.priceValue != null ? choice.priceValue : choice.price_value);
          if (isNaN(v)) v = 0;
          var overrides = adminNormalizePriceOverrides(choice);
          if (optId !== 'stile_and_rail_profile') {
            if (overrides.length) {
              for (var oi = 0; oi < overrides.length; oi++) {
                var o = overrides[oi];
                if (!o) continue;
                var matched = false;
                var whenArr = o.price_when || o.priceWhen;
                if (Array.isArray(whenArr) && whenArr.length) {
                  matched = true;
                  for (var wi = 0; wi < whenArr.length; wi++) {
                    var cond = whenArr[wi];
                    var ck = cond && (cond.key || cond.price_when_key);
                    var cv = cond && (cond.value != null ? cond.value : cond.price_when_value);
                    if (!ck || cv == null || !adminOptionValueMatches(options, ck, cv)) { matched = false; break; }
                  }
                } else {
                  var whenKey = o.priceWhenKey || o.price_when_key;
                  var whenVal = o.priceWhenValue != null ? o.priceWhenValue : o.price_when_value;
                  if (whenKey && whenVal != null && whenVal !== '') {
                    matched = adminOptionValueMatches(options, whenKey, whenVal);
                  }
                }
                if (matched) {
                  t = o.priceWhenType || o.price_when_type || 'fixed';
                  v = parseFloat(o.priceWhenValueNumber != null ? o.priceWhenValueNumber : o.price_when_value_number);
                  if (isNaN(v)) v = 0;
                  break;
                }
              }
            } else {
              var whenKey2 = choice.priceWhenKey || choice.price_when_key;
              var whenVal2 = choice.priceWhenValue != null ? choice.priceWhenValue : choice.price_when_value;
              if (whenKey2 && whenVal2 != null && whenVal2 !== '' && adminOptionValueMatches(options, whenKey2, whenVal2)) {
                t = choice.priceWhenType || choice.price_when_type || 'fixed';
                v = parseFloat(choice.priceWhenValueNumber != null ? choice.priceWhenValueNumber : choice.price_when_value_number);
                if (isNaN(v)) v = 0;
              }
            }
          }
          if (!t) t = 'fixed';
          if (t === 'fixed') return isNaN(v) ? 0 : Math.round(v * 100) / 100;
          if (t === 'percent') return isNaN(v) ? 0 : Math.round(basePrice * v * 100) / 100;
          return 0;
        }
        function adminGetOptionSelectedPriceDelta(opt, options, basePrice) {
          if (!opt || !opt.id) return null;
          var type = String(opt.type || opt.input_type || '').toLowerCase();
          if (['select', 'radio', 'checkbox'].indexOf(type) === -1) return null;
          var oid = String(opt.id);
          var choices = Array.isArray(opt.options) ? opt.options : [];
          var selected = adminConfigGetValue(options, oid);
          var hasSelection = type === 'checkbox'
            ? (Array.isArray(selected) && selected.length > 0)
            : adminOptionHasSelection(type, selected);
          if (!hasSelection) return null;
          var addonDelta = adminGetMeasurementAddonDelta(oid, options, hasSelection);
          if (addonDelta !== null && addonDelta > 0.005) return addonDelta;
          var breakdownKeyMap = pricingBoot && pricingBoot.optionAddonBreakdownKeys ? pricingBoot.optionAddonBreakdownKeys : {};
          var breakdownKey = breakdownKeyMap[oid] || breakdownKeyMap[adminNormOptionId(oid)];
          var addonBreakdown = pricingBoot && pricingBoot.addonBreakdown ? pricingBoot.addonBreakdown : {};
          if (breakdownKey && Object.prototype.hasOwnProperty.call(addonBreakdown, breakdownKey)) {
            var bdAmt = parseFloat(addonBreakdown[breakdownKey]);
            if (!isNaN(bdAmt)) return Math.round(bdAmt * 100) / 100;
          }
          if (type === 'select' || type === 'radio') {
            var ch = adminFindSchemaChoice(choices, selected);
            return ch ? adminResolveChoicePriceAmount(ch, opt, options, basePrice) : 0;
          }
          if (type === 'checkbox') {
            var arr = Array.isArray(selected) ? selected : [];
            var delta = 0;
            for (var ci = 0; ci < arr.length; ci++) {
              var ch2 = adminFindSchemaChoice(choices, arr[ci]);
              if (ch2) delta += adminResolveChoicePriceAmount(ch2, opt, options, basePrice);
            }
            return Math.round(delta * 100) / 100;
          }
          return null;
        }
        function adminSumBreakdownKeys(bd, keys) {
          var sum = 0;
          (keys || []).forEach(function (k) {
            if (!bd || !Object.prototype.hasOwnProperty.call(bd, k)) return;
            var n = parseFloat(bd[k]);
            if (!isNaN(n)) sum += n;
          });
          return Math.round(sum * 100) / 100;
        }
        function adminOptionsForPricing(liveOptions) {
          var merged = {};
          var saved = pricingBoot && pricingBoot.savedOptions ? pricingBoot.savedOptions : {};
          Object.keys(saved).forEach(function (k) { merged[k] = saved[k]; });
          if (liveOptions) {
            Object.keys(liveOptions).forEach(function (k) {
              var val = liveOptions[k];
              if (val === null || val === undefined || val === '') return;
              if (Array.isArray(val) && !val.length) return;
              merged[k] = val;
            });
          }
          return merged;
        }
        function adminConfigOptionHasValue(options, key) {
          if (!options || !Object.prototype.hasOwnProperty.call(options, key)) return false;
          var val = options[key];
          if (Array.isArray(val)) return val.length > 0;
          return val !== null && val !== undefined && String(val) !== '';
        }
        function adminBreakdownSidelightTransomSplitMode(bd) {
          if (!bd) return false;
          var pair1 = parseFloat(bd.sidelight_transom_oversized_pair1 || 0) || 0;
          var pair2 = parseFloat(bd.sidelight_transom_oversized_pair2 || 0) || 0;
          return Math.abs(pair1) > 0.005 || Math.abs(pair2) > 0.005;
        }
        function adminIsSidelightMeasurementOptionId(oid) {
          return /(sidelight.*width|sidelight_width)/.test(adminNormOptionId(oid));
        }
        function adminIsTransomMeasurementOptionId(oid) {
          return /(transom.*height|panel_transom|panel_door_width)/.test(adminNormOptionId(oid));
        }
        function adminSumSidelightTransomRowAddon(oid, options, bd) {
          var split = adminBreakdownSidelightTransomSplitMode(bd);
          var pair1 = parseFloat(bd.sidelight_transom_oversized_pair1 || 0) || 0;
          var pair2 = parseFloat(bd.sidelight_transom_oversized_pair2 || 0) || 0;
          var legacy = parseFloat(bd.sidelight_transom_oversized || 0) || 0;
          var hasSl = adminConfigOptionHasValue(options, 'sidelight_style');
          var hasTr = adminConfigOptionHasValue(options, 'transom_style');
          var ssSl = parseFloat(bd.screen_storm_sidelight_transom || 0) || 0;
          var ssTc = parseFloat(bd.screen_storm_transom_combo || 0) || 0;
          if (adminIsSidelightMeasurementOptionId(oid)) {
            if (!split && Math.abs(legacy) > 0.005 && hasTr && !hasSl) return null;
            var slAmt = Math.round(((split ? pair2 : legacy) + ssSl) * 100) / 100;
            return Math.abs(slAmt) > 0.005 ? slAmt : null;
          }
          if (adminIsTransomMeasurementOptionId(oid)) {
            if (!split && Math.abs(legacy) > 0.005 && hasSl && !hasTr) return null;
            var trAmt = Math.round(((split ? pair1 : legacy) + ssSl + ssTc) * 100) / 100;
            return Math.abs(trAmt) > 0.005 ? trAmt : null;
          }
          return null;
        }
        function adminMeasurementOptionGroup(oid) {
          var norm = adminNormOptionId(oid);
          if (norm === 'measurement_type') return 'all';
          if (/(sidelight.*width|sidelight_width|transom.*height|panel_transom|panel_door_width)/.test(norm)) return 'sidelight_transom';
          if (/thick/.test(norm)) return 'door_thickness';
          if (/(width|height|pre_hung|jamb)/.test(norm)) return 'door_oversized';
          return null;
        }
        function adminIsMeasurementOptionId(oid) {
          var norm = adminNormOptionId(oid);
          if (norm === 'measurement_type') return true;
          return /(width|height|thick|pre_hung|jamb|sidelight|transom)/.test(norm);
        }
        function adminMeasurementFieldHasValue(oid) {
          var sel = form.querySelector('select[name="opt_' + oid + '"]');
          if (sel && String(sel.value || '') !== '') return true;
          var radios = form.querySelectorAll('input[type="radio"][name="opt_' + oid + '"]:checked');
          return radios && radios.length > 0;
        }
        function adminGetMeasurementAddonDelta(oid, options, hasSelection) {
          if (!pricingBoot || !adminIsMeasurementOptionId(oid)) return null;
          if (adminNormOptionId(oid) !== 'measurement_type') return null;
          var group = adminMeasurementOptionGroup(oid);
          if (!group) return null;
          if (!adminResolveMeasurementType(adminOptionsForPricing(options))) return null;
          var addonBreakdown = pricingBoot.addonBreakdown || {};
          var allKeys = pricingBoot.allMeasurementAddonBreakdownKeys || [];
          var total = adminSumBreakdownKeys(addonBreakdown, allKeys);
          return total > 0.005 ? total : null;
        }
        function adminCollectOptionsFromForm() {
          var out = {};
          if (!pricingBoot || !Array.isArray(pricingBoot.schema)) return out;
          pricingBoot.schema.forEach(function (opt) {
            if (!opt || !opt.id) return;
            var oid = String(opt.id);
            var type = String(opt.type || opt.input_type || '').toLowerCase();
            if (type === 'checkbox') {
              var boxes = form.querySelectorAll('input[type="checkbox"][name="opt_' + oid + '[]"]:checked');
              var arr = [];
              boxes.forEach(function (b) { if (b.value) arr.push(b.value); });
              out[oid] = arr;
            } else if (type === 'number') {
              var num = form.querySelector('[name="opt_' + oid + '"]');
              out[oid] = num && num.value !== '' ? parseFloat(num.value) : null;
            } else {
              var v = getRefValue(oid);
              out[oid] = (v === '' || v == null) ? null : v;
            }
          });
          return out;
        }
        function updateOptionSelectedPrices() {
          if (!pricingBoot || !Array.isArray(pricingBoot.schema)) {
            form.querySelectorAll('.admin-option-row[data-option-id]').forEach(function (row) {
              var oid = row.getAttribute('data-option-id') || '';
              var priceEl = row.querySelector('.admin-option-selected-price');
              if (!priceEl || !oid) return;
              var sel = row.querySelector('select[name="opt_' + oid + '"]');
              var delta = 0;
              var found = false;
              if (sel) {
                var opt = sel.options[sel.selectedIndex];
                if (opt && opt.value !== '') {
                  delta = parseFloat(opt.getAttribute('data-choice-price') || '0');
                  found = true;
                }
              } else {
                var radios = row.querySelectorAll('input[type="radio"][name="opt_' + oid + '"]:checked');
                if (radios.length) {
                  delta = parseFloat(radios[0].getAttribute('data-choice-price') || '0');
                  found = true;
                }
                var checks = row.querySelectorAll('input[type="checkbox"][name="opt_' + oid + '[]"]:checked');
                if (checks.length) {
                  delta = 0;
                  checks.forEach(function (c) { delta += parseFloat(c.getAttribute('data-choice-price') || '0'); });
                  found = true;
                }
              }
              var text = found ? formatOptionPrice(delta, true) : '';
              priceEl.textContent = text;
              priceEl.classList.toggle('admin-option-selected-price--empty', text === '');
            });
            return;
          }
          var basePrice = parseFloat(pricingBoot.basePrice) || 0;
          var liveOptions = adminCollectOptionsFromForm();
          var pricingOptions = adminOptionsForPricing(liveOptions);
          pricingBoot.schema.forEach(function (opt) {
            if (!opt || !opt.id) return;
            var oid = String(opt.id);
            var type = String(opt.type || opt.input_type || '').toLowerCase();
            if (['select', 'radio', 'checkbox'].indexOf(type) === -1) return;
            var row = form.querySelector('.admin-option-row[data-option-id="' + oid + '"]');
            if (!row) return;
            var priceEl = row.querySelector('.admin-option-selected-price');
            if (!priceEl) return;
            var selected = adminConfigGetValue(liveOptions, oid);
            var hasSelection = adminOptionHasSelection(type, selected);
            if (adminNormOptionId(oid) === 'measurement_type') {
              hasSelection = !!adminResolveMeasurementType(pricingOptions);
            }
            var delta = null;
            var breakdownKeyMap = pricingBoot.optionAddonBreakdownKeys || {};
            var breakdownKey = breakdownKeyMap[oid] || breakdownKeyMap[adminNormOptionId(oid)];
            var addonBreakdown = pricingBoot.addonBreakdown || {};
            var measDelta = adminGetMeasurementAddonDelta(oid, liveOptions, hasSelection);
            if (adminIsMeasurementOptionId(oid) && adminNormOptionId(oid) !== 'measurement_type') {
              priceEl.textContent = '';
              priceEl.classList.add('admin-option-selected-price--empty');
              return;
            }
            if (measDelta !== null && measDelta > 0.005) {
              delta = measDelta;
            } else if (breakdownKey && Object.prototype.hasOwnProperty.call(addonBreakdown, breakdownKey) && hasSelection) {
              delta = parseFloat(addonBreakdown[breakdownKey]);
              if (isNaN(delta)) delta = 0;
            } else {
              delta = adminGetOptionSelectedPriceDelta(opt, pricingOptions, basePrice);
            }
            var text = '';
            if (measDelta !== null && measDelta > 0.005) {
              text = formatOptionPrice(measDelta, true);
            } else if (!adminIsMeasurementOptionId(oid) && hasSelection) {
              text = formatOptionPrice(delta == null ? 0 : delta, true);
            }
            priceEl.textContent = text;
            priceEl.classList.toggle('admin-option-selected-price--empty', text === '');
            var choices = Array.isArray(opt.options) ? opt.options : [];
            choices.forEach(function (c) {
              if (!c || c.value == null) return;
              var val = String(c.value);
              var amount = adminResolveChoicePriceAmount(c, opt, liveOptions, basePrice);
              row.querySelectorAll('option[data-choice-price], input[data-choice-price]').forEach(function (el) {
                if (String(el.value) === val) el.setAttribute('data-choice-price', String(amount));
              });
            });
          });
        }
        function updateCardSelectionState() {
          var cardInputs = form.querySelectorAll('.admin-choice-card input[type="radio"], .admin-choice-card input[type="checkbox"]');
          cardInputs.forEach(function (inp) {
            var card = inp.closest('.admin-choice-card');
            if (!card) return;
            card.classList.toggle('admin-choice-card--selected', !!inp.checked);
          });
        }
        function addListenersForRef(ref) {
          if (!ref) return;
          var sel = form.querySelector('select[name="opt_' + ref + '"]');
          if (sel) sel.addEventListener('change', updateAll);
          form.querySelectorAll('input[type="radio"][name="opt_' + ref + '"]').forEach(function (r) { r.addEventListener('change', updateAll); });
          form.querySelectorAll('input[type="checkbox"][name="opt_' + ref + '[]"]').forEach(function (r) { r.addEventListener('change', updateAll); });
        }
        hideRows.forEach(function (row) {
          addListenersForRef(row.getAttribute('data-hide-when-ref'));
        });
        showRows.forEach(function (row) {
          addListenersForRef(row.getAttribute('data-show-when-ref'));
        });
        showOpts.forEach(function (opt) { addListenersForRef(opt.getAttribute('data-show-when-ref')); });
        hideOpts.forEach(function (opt) { addListenersForRef(opt.getAttribute('data-hide-when-ref')); });
        // ---- Sidelight master-toggle linkage ----
        function sidelightDesignCheckbox() {
          return form.querySelector('input[type="checkbox"][name="opt_sidelight_design"]');
        }
        function hasSidelightStyleSelected() {
          var v = getRefValue('sidelight_style');
          if (Array.isArray(v)) return v.length > 0;
          return String(v || '') !== '';
        }
        function hasSidelightLocationSelected() {
          var v = getRefValue('sidelight_location');
          if (Array.isArray(v)) return v.length > 0;
          return String(v || '') !== '';
        }
        function resetSidelightStyleAndLocation() {
          ['sidelight_style', 'sidelight_location'].forEach(function (oid) {
            form.querySelectorAll('input[type="radio"][name="opt_' + oid + '"]').forEach(function (r) { r.checked = false; });
            form.querySelectorAll('input[type="checkbox"][name="opt_' + oid + '[]"]').forEach(function (c) { c.checked = false; });
            var sel = form.querySelector('select[name="opt_' + oid + '"]');
            if (sel) sel.value = '';
          });
        }
        function isSidelightStyleInput(t) {
          return t && (t.name === 'opt_sidelight_style' || t.name === 'opt_sidelight_style[]');
        }
        function isSidelightDesignInput(t) {
          return t && t.name === 'opt_sidelight_design';
        }
        // Show sidelight_location + sidelight_style when toggle is on or values already saved.
        function syncSidelightSubRows() {
          var box = sidelightDesignCheckbox();
          var visible = !!(box && box.checked) || hasSidelightStyleSelected() || hasSidelightLocationSelected();
          ['sidelight_location', 'sidelight_style'].forEach(function (oid) {
            var row = form.querySelector('.admin-option-row[data-option-id="' + oid + '"]');
            if (row) row.classList.toggle('admin-hidden', !visible);
          });
        }

        // ---- Transom toggle linkage ----
        function transomDesignAnyChecked() {
          return form.querySelectorAll('input[type="checkbox"][name="opt_transom_design[]"]:checked').length > 0;
        }
        function isTransomDesignInput(t) {
          return t && t.name === 'opt_transom_design[]';
        }
        function isTransomStyleInput(t) {
          return t && (t.name === 'opt_transom_style' || t.name === 'opt_transom_style[]');
        }
        function hasTransomStyleSelected() {
          var v = getRefValue('transom_style');
          if (Array.isArray(v)) { if (v.length > 0) return true; }
          else if (String(v || '') !== '') return true;
          // Also honor the saved configuration so the toggle opens on initial load
          // even before the user touches the form.
          var saved = pricingBoot ? pricingBoot.savedOptions : null;
          var sv = saved ? adminConfigGetValue(saved, 'transom_style') : null;
          if (Array.isArray(sv)) return sv.some(function (x) { return String(x == null ? '' : x).trim() !== ''; });
          return String(sv == null ? '' : sv).trim() !== '';
        }
        function checkTransomDesign() {
          var box = form.querySelector('input[type="checkbox"][name="opt_transom_design[]"][value="transom_designs"]')
            || form.querySelector('input[type="checkbox"][name="opt_transom_design[]"]');
          if (box) box.checked = true;
        }
        function resetTransomStyle() {
          ['transom_style'].forEach(function (oid) {
            form.querySelectorAll('input[type="radio"][name="opt_' + oid + '"]').forEach(function (r) { r.checked = false; });
            form.querySelectorAll('input[type="checkbox"][name="opt_' + oid + '[]"]').forEach(function (c) { c.checked = false; });
            var sel = form.querySelector('select[name="opt_' + oid + '"]');
            if (sel) sel.value = '';
          });
        }
        // Keep the transom design toggle checked whenever a style is selected, and
        // keep the style row visible (mirrors the storefront's derived "added" state).
        function syncTransomSubRows() {
          if (hasTransomStyleSelected()) {
            checkTransomDesign();
          }
          var visible = transomDesignAnyChecked() || hasTransomStyleSelected();
          var row = form.querySelector('.admin-option-row[data-option-id="transom_style"]');
          if (row) row.classList.toggle('admin-hidden', !visible);
        }

        // ---- Measurement field visibility (label-driven) ----
        // The selected measurement TYPE is identified by its label text (e.g. "Exact Door",
        // "Pre-Hung Unit", "Exact Panel"), and each dimension row is shown/hidden by matching
        // its OWN label against that type's keyword(s). "Door Thickness" is common to every
        // type and is always shown. Unknown type / nothing selected -> all rows shown.
        var DOOR_THICKNESS_IDS = {
          'door_thickness': 1, 'exact_door_thickness': 1, 'exact_door_thickness_frac': 1
        };
        function isDoorThicknessId(oid) {
          return Object.prototype.hasOwnProperty.call(DOOR_THICKNESS_IDS, measNorm(oid));
        }
        function adminNormalizeMeasurementTypeValue(v) {
          var t = adminNormOptionId(v);
          if (t === 'finished_opening') return 'finished_opening_size';
          if (t === 'jamb_unit_size') return 'pre_hung_unit_size';
          return t;
        }
        function adminResolveMeasurementType(options) {
          var raw = adminConfigGetValue(options || {}, 'measurement_type');
          if (Array.isArray(raw)) {
            for (var ri = 0; ri < raw.length; ri++) {
              if (raw[ri] != null && String(raw[ri]).trim() !== '') {
                return adminNormalizeMeasurementTypeValue(raw[ri]);
              }
            }
          } else if (raw != null && String(raw).trim() !== '') {
            return adminNormalizeMeasurementTypeValue(raw);
          }
          if (pricingBoot && pricingBoot.inferredMeasurementType) {
            return adminNormalizeMeasurementTypeValue(pricingBoot.inferredMeasurementType);
          }
          return '';
        }
        function restoreMeasurementTypeFromSaved() {
          var want = adminResolveMeasurementType(pricingBoot ? pricingBoot.savedOptions : {});
          if (!want) return;
          form.querySelectorAll('input[name="opt_measurement_type"], input[name="opt_measurement_type[]"]').forEach(function (inp) {
            if (adminNormOptionId(inp.value) === want) inp.checked = true;
          });
        }
        function measNorm(v) { return String(v == null ? '' : v).toLowerCase().replace(/-/g, '_').trim(); }
        function isMeasurementOptionId(oid) {
          var n = measNorm(oid);
          if (n === 'measurement_type') return false;
          return /(width|height|thick|pre_hung|jamb)/.test(n);
        }
        // The Door Setup option (slab / pre-hung) has a pre_hung-style id that matches the
        // measurement pattern; never treat/hide it as a measurement row.
        function rowIsDoorSetup(row) {
          var found = false;
          row.querySelectorAll('input, option').forEach(function (el) {
            var v = measNorm(el.value);
            if (v === 'slab_only' || v === 'pre_hung_on_jamb' || v === 'pre_hung_on_brick_molding') found = true;
          });
          return found;
        }
        function rowLabelText(row) {
          var el = row.querySelector('.admin-label');
          return el ? String(el.textContent || '').toLowerCase().trim() : '';
        }
        // Visible label of the currently selected measurement type (select option text or
        // checked radio/checkbox label). Falls back to the saved/normalized value so it still
        // resolves on first load before the user changes anything.
        function selectedMeasurementTypeLabel() {
          var row = null;
          form.querySelectorAll('.admin-option-row[data-option-id]').forEach(function (r) {
            if (measNorm(r.getAttribute('data-option-id')) === 'measurement_type') row = r;
          });
          if (row) {
            var sel = row.querySelector('select');
            if (sel && sel.options && sel.selectedIndex >= 0) {
              var op = sel.options[sel.selectedIndex];
              if (op && op.value !== '') return String(op.textContent || '').toLowerCase().trim();
            }
            var inp = row.querySelector('input[type="radio"]:checked, input[type="checkbox"]:checked');
            if (inp) {
              var card = inp.closest('.admin-choice-card');
              if (card) {
                var txt = card.querySelector('.admin-choice-text');
                if (txt) return String(txt.textContent || '').toLowerCase().trim();
              }
              var lab = inp.closest('label');
              if (lab) return String(lab.textContent || '').toLowerCase().trim();
            }
          }
          // Fallback: saved/inferred value with underscores turned to spaces so the same
          // keyword checks work (e.g. "pre_hung_unit_size" -> "pre hung unit size").
          return String(adminResolveMeasurementType(pricingBoot ? pricingBoot.savedOptions : {}) || '')
            .toLowerCase().replace(/_/g, ' ').trim();
        }
        // Map a measurement-type label/value string to the field-label keyword(s) whose rows
        // should stay visible. Returns null for an unrecognized type (-> show all). Order
        // matters: more specific words are tested before the generic "door".
        function measurementFieldKeywords(typeStr) {
          var s = String(typeStr || '');
          if (!s) return null;
          if (s.indexOf('sidelight') !== -1) return ['sidelight'];
          if (s.indexOf('transom') !== -1) return ['transom'];
          if (s.indexOf('pre-hung') !== -1 || s.indexOf('prehung') !== -1 || s.indexOf('pre hung') !== -1 || s.indexOf('jamb') !== -1) {
            return ['pre-hung', 'prehung', 'pre hung', 'jamb'];
          }
          if (s.indexOf('finished') !== -1) return ['finished'];
          if (s.indexOf('rough') !== -1) return ['rough'];
          if (s.indexOf('panel') !== -1) return ['panel'];   // Exact Panel -> Porch Panel
          if (s.indexOf('gate') !== -1) return ['gate'];
          if (s.indexOf('door') !== -1) return ['door'];     // Exact Door -> Door W / H / Thickness
          return null;
        }
        function syncMeasurementVisibility() {
          var keywords = measurementFieldKeywords(selectedMeasurementTypeLabel());
          form.querySelectorAll('.admin-option-row[data-option-id]').forEach(function (row) {
            var oid = row.getAttribute('data-option-id') || '';
            if (!isMeasurementOptionId(oid) || rowIsDoorSetup(row)) return;
            var lbl = rowLabelText(row);
            var show;
            if (isDoorThicknessId(oid) || lbl.indexOf('door thickness') !== -1) {
              // Door Thickness is common to every measurement type -> always visible.
              show = true;
            } else if (!keywords) {
              // Unknown type / nothing selected -> show all measurement rows (safe default).
              show = true;
            } else {
              show = keywords.some(function (k) { return lbl.indexOf(k) !== -1; });
            }
            row.classList.toggle('admin-hidden', !show);
          });
        }

        function initAdminCasingSelections() {
          var root = form.querySelector('[data-admin-casing-root="1"]');
          var hidden = document.getElementById('opt-casing-options-json');
          if (!root || !hidden) return;
          var baseItems = [];
          try {
            baseItems = JSON.parse(hidden.value || '[]');
            if (!Array.isArray(baseItems)) baseItems = [];
          } catch (eCasingBase) {
            baseItems = [];
          }
          function syncCasingHiddenJson() {
            var cards = root.querySelectorAll('.admin-casing-card[data-casing-index]');
            var out = [];
            cards.forEach(function (card) {
              var idx = parseInt(card.getAttribute('data-casing-index'), 10);
              if (isNaN(idx) || !baseItems[idx] || typeof baseItems[idx] !== 'object') return;
              var item = Object.assign({}, baseItems[idx]);
              var lenSel = card.querySelector('.admin-casing-length');
              var qtyInp = card.querySelector('.admin-casing-qty');
              if (lenSel) {
                var opt = lenSel.options[lenSel.selectedIndex];
                item.length_value = String(lenSel.value || '');
                item.length_label = opt ? String(opt.getAttribute('data-length-label') || opt.textContent || item.length_value) : item.length_value;
              }
              if (qtyInp) {
                var q = parseInt(qtyInp.value, 10);
                item.qty = (isNaN(q) || q < 1) ? 1 : q;
              }
              out.push(item);
            });
            try {
              hidden.value = JSON.stringify(out);
            } catch (eCasingJson) {}
          }
          root.querySelectorAll('.admin-casing-length, .admin-casing-qty').forEach(function (el) {
            el.addEventListener('change', syncCasingHiddenJson);
            el.addEventListener('input', syncCasingHiddenJson);
          });
          syncCasingHiddenJson();
        }

        function initAdminHardwareSelections() {
          var root = form.querySelector('[data-admin-hardware-root="1"]');
          var hidden = document.getElementById('opt-hardware-options-json');
          if (!root || !hidden) return;
          var baseItems = [];
          try {
            baseItems = JSON.parse(hidden.value || '[]');
            if (!Array.isArray(baseItems)) baseItems = [];
          } catch (eHwBase) {
            baseItems = [];
          }
          function stripBlankHardwareFields(item) {
            if (!item || typeof item !== 'object') return item;
            [
              ['finish_value', 'finish_label', 'finish_options'],
              ['function_value', 'function_label', 'function_options'],
              ['thickness_value', 'thickness_label', 'thickness_options'],
              ['closer_color_value', 'closer_color_label', 'closer_color_options'],
              ['swing_direction_value', 'swing_direction_label', 'swing_direction_options'],
              ['backset_value', 'backset_label', 'backset_options'],
              ['track_length_value', 'track_length_label', 'track_length_options'],
              ['connected_doors_value', 'connected_doors_label', 'connected_doors_options'],
              ['upper_track_length_value', 'upper_track_length_label', 'upper_track_length_options'],
              ['max_door_size_value', 'max_door_size_label', 'max_door_size_options'],
              ['carriage_pack_type_value', 'carriage_pack_type_label', 'carriage_pack_type_options'],
              ['strap_hinge_length_value', 'strap_hinge_length_label', 'strap_hinge_length_options']
            ].forEach(function (keys) {
              var val = String(item[keys[0]] || '').trim();
              var lbl = String(item[keys[1]] || '').trim();
              if (!val && !lbl) {
                delete item[keys[0]];
                delete item[keys[1]];
                if (keys[2]) delete item[keys[2]];
              }
            });
            return item;
          }
          function syncHardwareHiddenJson() {
            var cards = root.querySelectorAll('.admin-hardware-card[data-hardware-index]');
            var out = [];
            cards.forEach(function (card) {
              var idx = parseInt(card.getAttribute('data-hardware-index'), 10);
              if (isNaN(idx) || !baseItems[idx] || typeof baseItems[idx] !== 'object') return;
              var item = Object.assign({}, baseItems[idx]);
              var finishSel = card.querySelector('.admin-hardware-finish');
              if (finishSel && finishSel.options && finishSel.selectedIndex >= 0) {
                var finOpt = finishSel.options[finishSel.selectedIndex];
                item.finish_value = String(finishSel.value || '');
                item.finish_label = String(
                  (finOpt && finOpt.getAttribute('data-finish-label')) || (finOpt && finOpt.textContent) || item.finish_value || ''
                ).trim();
              }
              var functionSel = card.querySelector('.admin-hardware-function');
              if (functionSel && functionSel.options && functionSel.selectedIndex >= 0) {
                var fnOpt = functionSel.options[functionSel.selectedIndex];
                item.function_value = String(functionSel.value || '');
                item.function_label = String(
                  (fnOpt && fnOpt.getAttribute('data-function-label')) || (fnOpt && fnOpt.textContent) || item.function_value || ''
                ).trim();
              }
              var thicknessSel = card.querySelector('.admin-hardware-thickness');
              if (thicknessSel && thicknessSel.options && thicknessSel.selectedIndex >= 0) {
                var thOpt = thicknessSel.options[thicknessSel.selectedIndex];
                item.thickness_value = String(thicknessSel.value || '');
                item.thickness_label = String(
                  (thOpt && thOpt.getAttribute('data-thickness-label')) || (thOpt && thOpt.textContent) || item.thickness_value || ''
                ).trim();
              }
              card.querySelectorAll('.admin-hardware-extra[data-hw-field]').forEach(function (extraSel) {
                if (!extraSel.options || extraSel.selectedIndex < 0) return;
                var fieldKey = String(extraSel.getAttribute('data-hw-field') || '');
                if (!fieldKey) return;
                var valueKey = fieldKey.replace(/_label$/, '_value');
                if (valueKey === fieldKey) valueKey = fieldKey.replace(/label$/, 'value');
                var exOpt = extraSel.options[extraSel.selectedIndex];
                item[valueKey] = String(extraSel.value || '');
                item[fieldKey] = String(
                  (exOpt && exOpt.getAttribute('data-hw-extra-label')) || (exOpt && exOpt.textContent) || item[valueKey] || ''
                ).trim();
              });
              var qtyInp = card.querySelector('.admin-hardware-qty');
              if (qtyInp) {
                var q = parseInt(qtyInp.value, 10);
                item.qty = (isNaN(q) || q < 1) ? 1 : q;
              }
              out.push(stripBlankHardwareFields(item));
            });
            try {
              hidden.value = JSON.stringify(out);
            } catch (eHwJson) {}
          }
          root.querySelectorAll('.admin-hardware-finish, .admin-hardware-function, .admin-hardware-thickness, .admin-hardware-extra, .admin-hardware-qty').forEach(function (el) {
            el.addEventListener('change', syncHardwareHiddenJson);
            el.addEventListener('input', syncHardwareHiddenJson);
          });
          syncHardwareHiddenJson();
        }

        function initAdminSelectedOptions() {
          var root = form.querySelector('[data-admin-selected-options-root="1"]');
          var hidden = document.getElementById('opt-selected-options-json');
          if (!root || !hidden) return;
          var baseItems = [];
          try {
            baseItems = JSON.parse(hidden.value || '[]');
            if (!Array.isArray(baseItems)) baseItems = [];
          } catch (eSelBase) {
            baseItems = [];
          }
          function syncSelectedOptionsHiddenJson() {
            var fields = root.querySelectorAll('.admin-selected-option-field[data-selected-index]');
            var out = [];
            fields.forEach(function (field) {
              var idx = parseInt(field.getAttribute('data-selected-index'), 10);
              var base = (!isNaN(idx) && baseItems[idx] && typeof baseItems[idx] === 'object') ? baseItems[idx] : {};
              var item = Object.assign({}, base);
              item.label = field.getAttribute('data-selected-label') || item.label || '';
              item.source = field.getAttribute('data-selected-source') || item.source || '';
              item.id = field.getAttribute('data-selected-id') || item.id || '';
              var ctrl = field.querySelector('.admin-selected-option-value');
              if (ctrl) {
                if (ctrl.tagName === 'SELECT' && ctrl.options && ctrl.selectedIndex >= 0) {
                  var selOpt = ctrl.options[ctrl.selectedIndex];
                  item.storage_value = String(ctrl.value || '').trim();
                  item.value = String(
                    (selOpt && selOpt.getAttribute('data-choice-label')) || (selOpt && selOpt.textContent) || item.storage_value || ''
                  ).trim();
                } else {
                  item.value = String(ctrl.value || '');
                  if (item.storage_value == null) {
                    item.storage_value = item.value;
                  }
                }
              }
              out.push(item);
            });
            try {
              hidden.value = JSON.stringify(out);
            } catch (eSelJson) {}
          }
          root.querySelectorAll('.admin-selected-option-value').forEach(function (el) {
            el.addEventListener('change', syncSelectedOptionsHiddenJson);
            el.addEventListener('input', syncSelectedOptionsHiddenJson);
          });
          syncSelectedOptionsHiddenJson();
        }

        form.addEventListener('change', function (e) {
          var t = e.target;
          // unchecking the sidelight toggle resets style + location.
          if (isSidelightDesignInput(t) && !t.checked) {
            resetSidelightStyleAndLocation();
          }
          // Keep the transom toggle checked while a style is selected; only clear the
          // style when the toggle is turned off with no style chosen.
          if (isTransomDesignInput(t) && !transomDesignAnyChecked()) {
            if (hasTransomStyleSelected()) {
              checkTransomDesign();
            } else {
              resetTransomStyle();
            }
          }
          // Run own visibility sync LAST so it overrides show/hide-when rules.
          updateAll();
          updateCardSelectionState();
          syncSidelightSubRows();
          syncTransomSubRows();
          syncMeasurementVisibility();
        });
        restoreMeasurementTypeFromSaved();
        initAdminCasingSelections();
        initAdminHardwareSelections();
        initAdminSelectedOptions();
        updateAll();
        updateCardSelectionState();
        syncSidelightSubRows();
        syncTransomSubRows();
        syncMeasurementVisibility();
        updateOptionSelectedPrices();
      }
      if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', run);
      } else {
        run();
      }
    })();
  </script>

  <div class="admin-save-overlay" id="admin-save-overlay" role="alert" aria-live="assertive" aria-busy="true" hidden>
    <div class="admin-save-overlay__box">
      <div class="admin-save-overlay__spinner" aria-hidden="true"></div>
      <p class="admin-save-overlay__text">Saving configuration…</p>
    </div>
  </div>

  <script>
    (function () {
      var form = document.querySelector('form.admin-detail');
      var overlay = document.getElementById('admin-save-overlay');
      if (!form || !overlay) {
        return;
      }

      function isSaveSubmitter(btn) {
        // Only the primary "Save" button should trigger the saving loader.
        return !!btn && btn.getAttribute && btn.getAttribute('data-save-trigger') === '1';
      }

      function showOverlay(submitter) {
        overlay.hidden = false;
        if (submitter && submitter.classList) {
          submitter.classList.add('is-saving');
          submitter.setAttribute('aria-busy', 'true');
        }
      }

      function hideOverlay() {
        overlay.hidden = true;
      }

      form.addEventListener('submit', function (e) {
        var submitter = e.submitter || document.activeElement;
        // Show the loader ONLY when the Save button performed the submit.
        if (!isSaveSubmitter(submitter)) {
          return;
        }
        // No preventDefault — the browser still submits the form normally (default not broken).
        showOverlay(submitter);
      });

      // Hide the loader if the user returns via back/forward (bfcache) navigation.
      window.addEventListener('pageshow', function (event) {
        if (event.persisted) {
          hideOverlay();
        }
      });
    })();
  </script>
</body>
</html>
