{
  "version": 3,
  "sources": ["/cdn/shop/t/131/assets/quick-config.js?cb=1784126039629"],
  "sourcesContent": ["/**\n * Quick Config \u2014 APO Takeover\n * Three-step simplified UX above Add to Cart:\n *   Step 1: Finish Color  (wires Wood Type + conditional Finish group)\n *   Step 2: Door Width    (wires Door Width select)\n *   Step 3: Swing & Hinge (wires Swing Direction + Hinges On)\n *\n * All other required APO options are pre-selected with valid defaults on load,\n * so Add to Cart succeeds without the Advanced panel ever being opened.\n * The full APO form lives inside the Advanced slide-out panel.\n *\n * Activated only when window.__qcProductId matches the current APO product.\n */\n(function () {\n  'use strict';\n\n  var PRODUCT_ID = window.__qcProductId;\n  if (!PRODUCT_ID) return;\n\n  // \u2500\u2500\u2500 APO value IDs \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n  // Sourced from live mwApoInit.response on 2026-06-17.\n\n  var APO = {\n    // Option group IDs\n    OPT: {\n      woodType: 'o_2314954',\n      finishPG: 'o_2314959',\n      finishMaple: 'o_2314955',\n      finishOak: 'o_2314956', // Red Oak\n      finishWOak: 'o_2314957', // White Oak\n      finishAlder: 'o_2314958', // Knotty Alder\n      finishWalnut: 'o_2314960',\n      doorWidth: 'o_2314961', // select\n      doorHeight: 'o_2314963', // Door Height select\n      doorDepth: 'o_2314965', // Door Depth select \u2014 drives which Swing group is shown\n      // Swing Direction is NOT one group \u2014 APO shows a DIFFERENT swing group per\n      // depth (5\u00BC\u2033\u2192o_2314966 out-only, 6\u00BD\u2033\u2192o_2314967, 8\u00BC\u2033\u2192o_2314968, 10\u2033\u2192o_2314969,\n      // 12\u2033\u2192o_2314970). swingDir8 is kept only as the default-depth fallback; the\n      // ACTIVE group is resolved at runtime by getActiveSwingGroupId(). Never assume\n      // swingDir8 is the live group \u2014 that was the depth-desync bug (fixed 2026-07-09).\n      swingDir8: 'o_2314968', // Swing Direction for 8\u00BC\u2033 depth (default-depth fallback only)\n      hingesIn: 'o_2314972', // Hinges On \u2014 In-Swing\n      hingesOut: 'o_2314971', // Hinges On \u2014 Out-Swing\n      jambIn: 'o_2314974', // Jamb Depth \u2014 In-Swing\n      jambOut: 'o_2314973', // Jamb Depth \u2014 Out-Swing\n    },\n    // Value IDs \u2014 Wood Type (o_2314954)\n    woodType: { paintGrade: 'v_19862809', redOak: 'v_19862810' },\n    // Value IDs \u2014 Finish groups\n    finishPG: {\n      unfinished: 'v_19862835',\n      primer: 'v_19862836',\n      black: 'v_19862837',\n      white: 'v_19862838',\n    },\n    // Value IDs \u2014 Door Width (o_2314961, type=select)\n    doorWidth: {\n      name: 'mw_opts[o_2314961]',\n      w24: 'v_19862847',\n      w26: 'v_19862849',\n      w28: 'v_19862851',\n      w30: 'v_19862853',\n      w32: 'v_19862855',\n      w34: 'v_19862857',\n      w36: 'v_19862859',\n    },\n    // Value IDs \u2014 Swing Direction (o_2314968)\n    swingDir: { inSwing: 'v_19862921', outSwing: 'v_19862922' },\n    // Value IDs \u2014 Hinges On\n    hingesIn: { left: 'v_19862929', right: 'v_19862930' },\n    hingesOut: { left: 'v_19862927', right: 'v_19862928' },\n    // Value IDs \u2014 Jamb Depth defaults\n    jambInDefault: 'v_19862934', // 4 9/16\u2033 in-swing\n    jambOutDefault: 'v_19862931', // 4 9/16\u2033 out-swing\n  };\n\n  // \u2500\u2500\u2500 Config data \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n  // APO swatch image URLs (100\u00D7100 wood grain textures from apo-admin.mageworx.com).\n  // Confirmed live on 2026-06-17 via computed-style extraction from APO DOM labels.\n  // Only Walnut (v_19862814) is used today \u2014 it's the dominant stain wood per 90-day\n  // order data and powers all 3 stain tiles in FINISH_TILES below.\n  var APO_IMG =\n    'https://apo-admin.mageworx.com/front/img/murphydoor.myshopify.com/';\n  var APO_SWATCH_URLS = {\n    v_19862814:\n      APO_IMG +\n      '1c142365d44865192c14c038183a3a0a447f24fe0a2bde022896a062b537890f?width=100&height=100',\n  };\n\n  // Stain finish value IDs for the wood species we expose as stain tiles.\n  var STAIN_VALS = {\n    walnut: {\n      clear: 'v_19862842',\n      medium: 'v_19862843',\n      cherry: 'v_19862844',\n      burntCoal: 'v_19862846',\n    },\n  };\n\n  // Mapping based on 90-day order data (879 orders analyzed 2026-06-17):\n  // - 79% Paint Grade (Primer 31% / Unfinished 28% / White 16% / Black 2.6%)\n  // - 21% stained hardwoods\n  // - Walnut dominates Medium (67%) and Dark (56%); Knotty Alder ties Walnut for Light (9 each)\n  // - Picking Walnut for all 3 stain tiles for consistency + best hit rate\n  var FINISH_TILES = [\n    // Paint-grade finishes: solid color circles\n    {\n      id: 'primed',\n      label: 'Primed',\n      bg: '#c0bfbc',\n      woodOpt: APO.OPT.woodType,\n      wood: APO.woodType.paintGrade,\n      finishOpt: APO.OPT.finishPG,\n      finishVal: APO.finishPG.primer,\n    },\n    {\n      id: 'unfinished',\n      label: 'Unfinished',\n      bg: '#c9a96e',\n      woodOpt: APO.OPT.woodType,\n      wood: APO.woodType.paintGrade,\n      finishOpt: APO.OPT.finishPG,\n      finishVal: APO.finishPG.unfinished,\n    },\n    {\n      id: 'white',\n      label: 'White',\n      bg: '#f0eeea',\n      border: '#ccc',\n      woodOpt: APO.OPT.woodType,\n      wood: APO.woodType.paintGrade,\n      finishOpt: APO.OPT.finishPG,\n      finishVal: APO.finishPG.white,\n    },\n    {\n      id: 'black',\n      label: 'Black',\n      bg: '#1e1e1e',\n      woodOpt: APO.OPT.woodType,\n      wood: APO.woodType.paintGrade,\n      finishOpt: APO.OPT.finishPG,\n      finishVal: APO.finishPG.black,\n    },\n    // Stain tiles: Walnut (top stain wood \u2014 41/170 stain orders, dominates Med + Dark)\n    {\n      id: 'light-stain',\n      label: 'Light Stain',\n      bg: '#b8914e',\n      img: APO_SWATCH_URLS['v_19862814'],\n      woodOpt: APO.OPT.woodType,\n      wood: 'v_19862814', // Walnut\n      finishOpt: APO.OPT.finishWalnut,\n      finishVal: STAIN_VALS.walnut.clear,\n      note: 'Walnut \u2013 Clear',\n    },\n    {\n      id: 'medium-stain',\n      label: 'Medium Stain',\n      bg: '#7a5230',\n      img: APO_SWATCH_URLS['v_19862814'],\n      woodOpt: APO.OPT.woodType,\n      wood: 'v_19862814',\n      finishOpt: APO.OPT.finishWalnut,\n      finishVal: STAIN_VALS.walnut.medium,\n      note: 'Walnut \u2013 Medium',\n    },\n    {\n      id: 'dark-stain',\n      label: 'Dark Stain',\n      bg: '#3e2318',\n      img: APO_SWATCH_URLS['v_19862814'],\n      woodOpt: APO.OPT.woodType,\n      wood: 'v_19862814',\n      finishOpt: APO.OPT.finishWalnut,\n      finishVal: STAIN_VALS.walnut.burntCoal,\n      note: 'Walnut \u2013 Burnt Coal',\n    },\n  ];\n\n  // Width auto-defaults to 32\" per CEO direction 2026-06-17 (2nd-most popular at\n  // 18.1% of orders, behind 36\" at 22.3%). Steps 1 (color) and 3 (swing) do NOT\n  // auto-default \u2014 customer must actively select those.\n  var WIDTH_OPTIONS = [\n    { val: APO.doorWidth.w24, door: 24, ro: 26 },\n    { val: APO.doorWidth.w26, door: 26, ro: 28 },\n    { val: APO.doorWidth.w28, door: 28, ro: 30 },\n    { val: APO.doorWidth.w30, door: 30, ro: 32 },\n    { val: APO.doorWidth.w32, door: 32, ro: 34, isDefault: true },\n    { val: APO.doorWidth.w34, door: 34, ro: 36 },\n    { val: APO.doorWidth.w36, door: 36, ro: 38 },\n  ];\n\n  // Door handing thumbnail images \u2014 sourced from Shopify Files originally\n  // uploaded under product 8097093419053 (Flush Mount Bookcase Door 2.0).\n  // These are referenced cross-product because shop.url/files/\u2026 is store-level,\n  // not product-scoped \u2014 QC renders for product 2090217013307 (Hidden Bookcase\n  // Door) but can freely use any file in the store's media library.\n  // Order confirmed by user: in-left is file gid://shopify/MediaImage/44099298361389.\n  // Remaining 3 images assumed by product media order \u2014 verify with Ryan if needed.\n  var QC_CDN = 'https://cdn.shopify.com/s/files/1/0109/8488/2235/files/';\n  var SWING_IMGS = {\n    'in-left':\n      QC_CDN +\n      'murphy-door-hidden-bookcase-light-wood-shelves_51986920-3990-402a-a229-06ff191508db.png',\n    'in-right': QC_CDN + 'murphy-door-hidden-bookcase-light-wood-shelves.webp',\n    'out-left': QC_CDN + 'murphy-door-hidden-door-bookcase-natural-wood.webp',\n    'out-right': QC_CDN + 'murphy-door-natural-wood-hidden-bookcase.webp',\n  };\n\n  // Each tile carries a swing DIRECTION ('in'/'out') and a hinge hand, NOT a fixed\n  // swing value ID. The concrete swing value is resolved against the ACTIVE swing\n  // group (per current depth) at click/sync time via swingValueByDir(). Hinge groups\n  // (o_2314971/o_2314972) are NOT depth-dependent, so their value IDs stay fixed.\n  var SWING_OPTIONS = [\n    {\n      id: 'in-right',\n      label: 'In-Swing',\n      sub: 'Hinge Right',\n      dir: 'in',\n      hingeOpt: APO.OPT.hingesIn,\n      hinge: APO.hingesIn.right,\n    },\n    {\n      id: 'in-left',\n      label: 'In-Swing',\n      sub: 'Hinge Left',\n      dir: 'in',\n      hingeOpt: APO.OPT.hingesIn,\n      hinge: APO.hingesIn.left,\n    },\n    {\n      id: 'out-right',\n      label: 'Out-Swing',\n      sub: 'Hinge Right',\n      dir: 'out',\n      hingeOpt: APO.OPT.hingesOut,\n      hinge: APO.hingesOut.right,\n    },\n    {\n      id: 'out-left',\n      label: 'Out-Swing',\n      sub: 'Hinge Left',\n      dir: 'out',\n      hingeOpt: APO.OPT.hingesOut,\n      hinge: APO.hingesOut.left,\n    },\n  ];\n\n  // \u2500\u2500\u2500 SVG door diagrams \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n  // Minimal inline SVGs showing door panel, hinge pins, knob, and swing arc.\n\n  function swingSvg(dir, hinge) {\n    var hx = hinge === 'right' ? 55 : 5;\n    var kx = hinge === 'right' ? 10 : 50;\n    var arcD;\n    if (dir === 'in') {\n      arcD =\n        hinge === 'right'\n          ? 'M 5,62 A 50,50 0 0,1 55,12'\n          : 'M 55,62 A 50,50 0 0,0 5,12';\n    } else {\n      arcD =\n        hinge === 'right'\n          ? 'M 5,62 A 50,50 0 0,0 55,12'\n          : 'M 55,62 A 50,50 0 0,1 5,12';\n    }\n    return (\n      '<svg viewBox=\"0 0 60 68\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\">' +\n      '<rect x=\"2\" y=\"2\" width=\"56\" height=\"64\" rx=\"2\" fill=\"#f5f2ed\" stroke=\"#c0b8ac\" stroke-width=\"1.5\"/>' +\n      '<rect x=\"' +\n      (hx - 2) +\n      '\" y=\"10\" width=\"4\" height=\"7\" rx=\"1\" fill=\"#999\"/>' +\n      '<rect x=\"' +\n      (hx - 2) +\n      '\" y=\"50\" width=\"4\" height=\"7\" rx=\"1\" fill=\"#999\"/>' +\n      '<circle cx=\"' +\n      kx +\n      '\" cy=\"34\" r=\"3\" fill=\"#aaa\"/>' +\n      '<path d=\"' +\n      arcD +\n      '\" fill=\"none\" stroke=\"#4a8fd4\" stroke-width=\"1.2\" stroke-dasharray=\"3 2\" opacity=\"0.75\"/>' +\n      '</svg>'\n    );\n  }\n\n  // \u2500\u2500\u2500 APO interaction helpers \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n  // APO uses its own internal state object (mwApoInit.response[key].values[vid].enabled)\n  // as the source of truth for cart submission \u2014 the DOM radio inputs are secondary.\n  // Direct state modification + mwApo::applyAttributeStateToHtml sync is the only\n  // reliable way to change APO's selection programmatically (label.click() has\n  // race conditions and toggle behavior that make it unreliable after init).\n\n  function getApoRespKey() {\n    var resp = window.mwApoInit && window.mwApoInit.response;\n    if (!resp) return null;\n    var keys = Object.keys(resp);\n    return keys.length ? keys[0] : null;\n  }\n\n  // Set a single APO option group to a given value (or null to clear all).\n  // Deselects all other values in the group, enables the target.\n  function setApoOption(optionId, valueId) {\n    var key = getApoRespKey();\n    if (!key) return false;\n    var resp = window.mwApoInit.response[key];\n    var option = resp.options[optionId];\n    if (!option) return false;\n    option.values.forEach(function (vid) {\n      if (resp.values[vid]) resp.values[vid].enabled = false;\n    });\n    if (valueId && resp.values[valueId]) {\n      resp.values[valueId].enabled = true;\n    }\n    return true;\n  }\n\n  // Sync APO's HTML state from its internal state object, then rehome the ATC button.\n  // APO may re-inject its ATC button during state sync \u2014 we move it back immediately after.\n  function syncApoUi() {\n    if (window.mwApoInit && window.mwApoInit.fireEvent) {\n      window.mwApoInit.fireEvent('mwApo::applyAttributeStateToHtml', {});\n    }\n    setTimeout(rehomeApoAtcBtn, 50);\n  }\n\n  // After syncApoUi, APO may re-position its ATC button. Keep it in the product form.\n  function rehomeApoAtcBtn() {\n    var b = document.querySelector('.mw-apo-add-to-cart-custom');\n    if (!b) return;\n    var buyBtns = document.querySelector('.product-form__buttons');\n    if (buyBtns && b.parentElement !== buyBtns)\n      buyBtns.insertBefore(b, buyBtns.firstChild);\n  }\n\n  function setApoSelect(name, valueId) {\n    var sel = document.querySelector('select[name=\"' + name + '\"]');\n    if (!sel) return false;\n    sel.value = valueId;\n    sel.dispatchEvent(new Event('change', { bubbles: true }));\n    sel.dispatchEvent(new Event('input', { bubbles: true }));\n    return true;\n  }\n\n  // All finish option group IDs \u2014 cleared when switching wood type\n  var ALL_FINISH_OPTS = [\n    APO.OPT.finishPG,\n    APO.OPT.finishMaple,\n    APO.OPT.finishOak,\n    APO.OPT.finishWOak,\n    APO.OPT.finishAlder,\n    APO.OPT.finishWalnut,\n  ];\n\n  // \u2500\u2500 Helpers to read current APO enabled state \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n  function currentEnabledVal(optionId) {\n    var key = getApoRespKey();\n    var resp =\n      window.mwApoInit &&\n      window.mwApoInit.response &&\n      window.mwApoInit.response[key];\n    if (!resp || !resp.options[optionId]) return null;\n    var found = null;\n    resp.options[optionId].values.forEach(function (vid) {\n      if (resp.values[vid] && resp.values[vid].enabled) found = vid;\n    });\n    return found;\n  }\n\n  function getResp() {\n    var key = getApoRespKey();\n    return (\n      (window.mwApoInit &&\n        window.mwApoInit.response &&\n        window.mwApoInit.response[key]) ||\n      null\n    );\n  }\n\n  // \u2500\u2500 Depth-aware Swing resolution (data-driven \u2014 no hardcoded swing group) \u2500\u2500\u2500\u2500\u2500\n  // APO renders a SEPARATE \"Swing Direction\" option group for each Door Depth and\n  // hides all but the active one with the `mw-hidden` class on its .mw-option\n  // container. Reading/writing swing MUST target the currently-active group, or the\n  // QC display desyncs and ATC blocks when depth \u2260 8\u00BC\u2033. See apo-geometry-model.\n\n  // All option group IDs titled \"Swing Direction\" (5 today, one per depth).\n  function getSwingGroupIds() {\n    var resp = getResp();\n    if (!resp || !resp.options) return [];\n    return Object.keys(resp.options).filter(function (oid) {\n      return resp.options[oid].title === 'Swing Direction';\n    });\n  }\n\n  // The currently-shown swing group = the one whose .mw-option container does NOT\n  // carry `mw-hidden`. Falls back to whichever group already has an enabled value,\n  // then to the default-depth group (swingDir8) so callers always get something.\n  function getActiveSwingGroupId() {\n    var ids = getSwingGroupIds();\n    var i;\n    for (i = 0; i < ids.length; i++) {\n      var cont = document.querySelector(\n        '.mw-option[data-option-id=\"' + ids[i] + '\"]'\n      );\n      if (cont && !cont.classList.contains('mw-hidden')) return ids[i];\n    }\n    for (i = 0; i < ids.length; i++) {\n      if (getEnabledInGroup(ids[i])) return ids[i];\n    }\n    return ids.indexOf(APO.OPT.swingDir8) >= 0\n      ? APO.OPT.swingDir8\n      : ids[0] || null;\n  }\n\n  // The value ID within `groupId` whose title is \"In-Swing\" / \"Out-Swing\".\n  // Returns null when that direction doesn't exist in the group (e.g. the 5\u00BC\u2033\n  // group is Out-Swing only), which is exactly how we detect out-only depths.\n  function swingValueByDir(groupId, dir) {\n    var resp = getResp();\n    if (!resp || !groupId || !resp.options[groupId]) return null;\n    var want = dir === 'in' ? 'In-Swing' : 'Out-Swing';\n    var vals = resp.options[groupId].values;\n    for (var i = 0; i < vals.length; i++) {\n      var v = resp.values[vals[i]];\n      if (v && v.value && String(v.value.title).trim() === want) return vals[i];\n    }\n    return null;\n  }\n\n  function getEnabledInGroup(groupId) {\n    var resp = getResp();\n    if (!resp || !groupId || !resp.options[groupId]) return null;\n    var found = null;\n    resp.options[groupId].values.forEach(function (vid) {\n      if (resp.values[vid] && resp.values[vid].enabled) found = vid;\n    });\n    return found;\n  }\n\n  // The enabled swing across ALL groups \u2192 { groupId, valueId, dir } or null.\n  // Scans every swing group because the enabled value may live in any depth's group.\n  function getEnabledSwing() {\n    var resp = getResp();\n    if (!resp) return null;\n    var ids = getSwingGroupIds();\n    for (var i = 0; i < ids.length; i++) {\n      var vid = getEnabledInGroup(ids[i]);\n      if (vid) {\n        var title = String(resp.values[vid].value.title).trim();\n        return {\n          groupId: ids[i],\n          valueId: vid,\n          dir: title === 'In-Swing' ? 'in' : 'out',\n        };\n      }\n    }\n    return null;\n  }\n\n  // Does the active depth offer an In-Swing option? (5\u00BC\u2033 depth is Out-Swing only.)\n  function activeDepthAllowsInSwing() {\n    return !!swingValueByDir(getActiveSwingGroupId(), 'in');\n  }\n\n  // After a swing/hinge change, the correct Jamb Depth group becomes visible (In @\n  // 6\u00BD\u2033 uses a different group than In @ 8\u00BC\u2033/10\u2033/12\u2033, and Out uses another). Select\n  // the first value of whichever Jamb group is currently shown if none is set, so\n  // APO's required-Jamb validation passes regardless of depth/swing combination.\n  function ensureJambDefault() {\n    var resp = getResp();\n    if (!resp || !resp.options) return;\n    var jambIds = Object.keys(resp.options).filter(function (oid) {\n      var t = resp.options[oid].title || '';\n      return t.indexOf('Jamb') === 0 && t !== 'Custom Jamb Depth';\n    });\n    for (var i = 0; i < jambIds.length; i++) {\n      var cont = document.querySelector(\n        '.mw-option[data-option-id=\"' + jambIds[i] + '\"]'\n      );\n      if (cont && !cont.classList.contains('mw-hidden')) {\n        if (!getEnabledInGroup(jambIds[i])) {\n          var first = resp.options[jambIds[i]].values[0];\n          if (first) triggerApoSwatchClick(first);\n        }\n        return;\n      }\n    }\n  }\n\n  // \u2500\u2500 Trigger APO's native click on a value swatch \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n  // The right click target is the .mw-option__swatch-media div inside the label\n  // for that value ID. This fires APO's natural event cascade, which:\n  //   \u2022 updates internal enabled state\n  //   \u2022 adds .mw-option__value--selected to the clicked value div\n  //   \u2022 removes --selected from siblings\n  //   \u2022 un-hides conditional groups (e.g. selecting Paint Grade unhides PG Finish)\n  // Clicking the input directly is unreliable (mw-visually-hidden interferes).\n  // Clicking the .mw-option__value div sometimes doesn't trigger the full cascade.\n  // Clicking .mw-option__swatch-media triggers the full chain just like a real user.\n\n  function triggerApoSwatchClick(valueId) {\n    var swatchMedia = document.querySelector(\n      'label[for=\"' + valueId + '\"] .mw-option__swatch-media'\n    );\n    if (!swatchMedia) return false;\n    swatchMedia.click();\n    return true;\n  }\n\n  // \u2500\u2500 Cancelable apply guards (rapid-click protection) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n  // Both applyColorSelection and applySwingSelection drive APO through *chained*\n  // swatch clicks with deliberate delays \u2014 a swatch click reveals its dependent\n  // group (wood\u2192finish, swing\u2192hinge/jamb), and we must wait for that reveal before\n  // clicking into it. If the user clicks a second tile before the first chain\n  // finishes, the two chains INTERLEAVE: the earlier chain's still-queued clicks\n  // fire into the state the later click already changed, scrambling APO's shared\n  // `values` object so the last click doesn't persist (rapid-click desync,\n  // QA 2026-07-14). Guard by generation: each apply bumps a token and registers its\n  // pending timers; a newer apply cancels the older chain's timers, and the token\n  // check aborts any deferred step that already slipped onto the queue. Net effect:\n  // last-click-wins, with the UI staying fully responsive (no lockout).\n  var _applyGen = { color: 0, swing: 0 };\n  var _applyTimers = { color: [], swing: [] };\n  function cancelApply(kind) {\n    _applyTimers[kind].forEach(clearTimeout);\n    _applyTimers[kind] = [];\n  }\n  function scheduleApply(kind, fn, ms) {\n    var id = setTimeout(fn, ms);\n    _applyTimers[kind].push(id);\n    return id;\n  }\n\n  // \u2500\u2500 Apply color selection: click wood swatch \u2192 wait for cascade \u2192 click finish \u2500\u2500\n  // Mimics the natural human flow: click Wood Type swatch (APO unhides the matching\n  // finish group + auto-selects its default) \u2192 click Finish swatch (APO transitions).\n  // We let APO handle ALL display state. No manual class manipulation.\n\n  // APO swatch behavior: clicking an already-selected swatch DESELECTS it.\n  // Guard against this by checking the current enabled value before clicking.\n\n  function applyColorSelection(woodOptId, woodValId, finishOptId, finishValId) {\n    // Supersede any in-flight color apply so overlapping chains can't interleave.\n    cancelApply('color');\n    var gen = ++_applyGen.color;\n\n    var currentWood = currentEnabledVal(woodOptId);\n    var woodNeedsClick = currentWood !== woodValId;\n\n    // Step 1: click wood swatch only if not already selected \u2014 APO would toggle off otherwise\n    if (woodNeedsClick) triggerApoSwatchClick(woodValId);\n\n    // Step 2: after APO's wood cascade settles (350ms), click finish if needed.\n    // If wood didn't change, click finish sooner (no cascade delay needed).\n    scheduleApply(\n      'color',\n      function () {\n        if (gen !== _applyGen.color) return; // superseded by a newer click\n        // Re-read finish at fire time (a newer selection or APO's own wood-cascade\n        // default may have changed it) so we don't toggle a correct swatch off.\n        var liveFinish = null;\n        ALL_FINISH_OPTS.forEach(function (oid) {\n          var v = currentEnabledVal(oid);\n          if (v) liveFinish = v;\n        });\n        if (liveFinish !== finishValId) triggerApoSwatchClick(finishValId);\n      },\n      woodNeedsClick ? 350 : 50\n    );\n  }\n\n  // Apply a QC swing tile by DIRECTION against whatever swing group is active for\n  // the current depth. Returns false (no-op) when the direction is unavailable at\n  // this depth (e.g. In-Swing while depth is 5\u00BC\u2033 Out-Swing-only) so callers don't\n  // paint an invalid tile active.\n  function applySwingSelection(dir, hingeValId) {\n    var groupId = getActiveSwingGroupId();\n    var swingValId = swingValueByDir(groupId, dir);\n    if (!swingValId) return false;\n\n    // Supersede any in-flight swing apply so overlapping chains can't interleave\n    // and scramble APO state on rapid clicks (QA 2026-07-14). See cancelApply().\n    cancelApply('swing');\n    var gen = ++_applyGen.swing;\n\n    var currentSwing = getEnabledInGroup(groupId);\n    var swingNeedsClick = currentSwing !== swingValId;\n    var hingeOpt = dir === 'in' ? APO.OPT.hingesIn : APO.OPT.hingesOut;\n    var oppositeHingeOpt = dir === 'in' ? APO.OPT.hingesOut : APO.OPT.hingesIn;\n\n    // Click the swing swatch first \u2014 APO clears BOTH hinge groups and reveals the\n    // one matching the new direction (empty, awaiting its hinge pick).\n    if (swingNeedsClick) triggerApoSwatchClick(swingValId);\n\n    // Seed the target hinge in state SYNCHRONOUSLY, right after the swing click, and\n    // clear the opposite group. getQcMissing() \u2014 the Add-to-Cart gate \u2014 reads hinge\n    // state synchronously via hingesIn||hingesOut (see wireAtcValidation). Because\n    // the swing click above clears BOTH hinge groups and the *natural* hinge swatch\n    // click is deferred (+350-550ms, to let APO reveal the group), a plain direction\n    // switch left both groups empty for that whole window \u2014 a fast ATC tap in it was\n    // spuriously blocked despite a valid, complete selection (cascade audit\n    // 2026-07-14). Seeding here keeps anyHinge continuously truthy; clearing the\n    // opposite keeps APO's cart payload unambiguous (only the active direction set).\n    // The deferred swatch click below still drives APO's real UI/cascade and no-ops\n    // when state already matches. syncQcFromApo's hinge read is direction-scoped, so\n    // a briefly-lingering opposite value can no longer un-check the selected tile.\n    setApoOption(hingeOpt, hingeValId);\n    setApoOption(oppositeHingeOpt, null);\n\n    scheduleApply(\n      'swing',\n      function () {\n        if (gen !== _applyGen.swing) return; // superseded by a newer click\n        // Reconcile APO's rendered UI to the seeded hinge via the natural swatch\n        // click (fires APO's own handlers). Skips when state already matches \u2014 e.g.\n        // APO's async swing cascade may have re-cleared the seed, in which case this\n        // re-selects it.\n        if (currentEnabledVal(hingeOpt) !== hingeValId)\n          triggerApoSwatchClick(hingeValId);\n        scheduleApply(\n          'swing',\n          function () {\n            if (gen !== _applyGen.swing) return; // superseded\n            // Heal: if the swatch click couldn't land (APO mid-re-render, revealed\n            // hinge group not yet in the DOM), re-assert the hinge in state directly\n            // (deterministic, render-independent) so it never sticks in a no-hinge\n            // state. The seed above already covers the ATC gate; this keeps APO's\n            // HTML/state in step. Re-clear the opposite in case APO's async cascade\n            // re-populated it.\n            if (currentEnabledVal(hingeOpt) !== hingeValId)\n              setApoOption(hingeOpt, hingeValId);\n            setApoOption(oppositeHingeOpt, null);\n            syncApoUi();\n            // Jamb group depends on the final swing/depth \u2014 resolve it live.\n            ensureJambDefault();\n          },\n          200\n        );\n      },\n      swingNeedsClick ? 350 : 50\n    );\n    return true;\n  }\n\n  // \u2500\u2500\u2500 DOM builders (no innerHTML \u2014 use createElement + appendChild) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n  function el(tag, attrs, children) {\n    var node = document.createElement(tag);\n    if (attrs) {\n      Object.keys(attrs).forEach(function (k) {\n        if (k === 'class') node.className = attrs[k];\n        else if (k === 'text') node.textContent = attrs[k];\n        else node.setAttribute(k, attrs[k]);\n      });\n    }\n    if (children) {\n      children.forEach(function (c) {\n        if (c)\n          node.appendChild(\n            typeof c === 'string' ? document.createTextNode(c) : c\n          );\n      });\n    }\n    return node;\n  }\n\n  function svgEl(svgString) {\n    // DOMParser is safe for our own SVG strings (no user input)\n    var parser = new DOMParser();\n    var doc = parser.parseFromString(svgString, 'image/svg+xml');\n    return doc.documentElement;\n  }\n\n  function buildSwatchTile(tile) {\n    var btn = el('button', {\n      type: 'button',\n      class: 'qc-swatch' + (tile.isDefault ? ' is-active' : ''),\n      'data-qc-tile': tile.id,\n      'aria-label': tile.label + (tile.note ? ' (' + tile.note + ')' : ''),\n      'aria-pressed': tile.isDefault ? 'true' : 'false',\n      'data-track-click': 'select_option',\n      'data-track-section': 'configurator_simplified',\n      'data-track-label': tile.label,\n    });\n    var colorDot = el('span', {\n      class: 'qc-swatch__color',\n      'aria-hidden': 'true',\n    });\n\n    if (tile.img) {\n      // Real wood-grain image for stain tiles \u2014 overlays a small tint badge to\n      // indicate relative darkness but lets the actual wood texture do the selling.\n      colorDot.style.cssText =\n        'position:relative;overflow:hidden;background:' + tile.bg + ';';\n      var imgEl = el('img', {\n        src: tile.img,\n        alt: '',\n        width: '36',\n        height: '36',\n        loading: 'lazy',\n        style:\n          'position:absolute;inset:0;width:100%;height:100%;object-fit:cover;border-radius:50%;',\n      });\n      colorDot.appendChild(imgEl);\n    } else {\n      var style = 'background:' + tile.bg + ';';\n      if (tile.border) style += 'border-color:' + tile.border + ';';\n      colorDot.setAttribute('style', style);\n    }\n\n    var nameSpan = el('span', { class: 'qc-swatch__name', text: tile.label });\n    btn.appendChild(colorDot);\n    btn.appendChild(nameSpan);\n    return btn;\n  }\n\n  function buildSwingOption(opt) {\n    var btn = el('button', {\n      type: 'button',\n      class: 'qc-swing' + (opt.isDefault ? ' is-active' : ''),\n      'data-qc-swing': opt.id,\n      'aria-label': opt.label + ', ' + opt.sub,\n      'aria-pressed': opt.isDefault ? 'true' : 'false',\n      'data-track-click': 'select_option',\n      'data-track-section': 'configurator_simplified',\n      'data-track-label': opt.label + ', ' + opt.sub,\n    });\n    var diagram = el('span', {\n      class: 'qc-swing__diagram',\n      'aria-hidden': 'true',\n    });\n    // Use real door handing images; fall back to SVG placeholder if image unavailable\n    var imgSrc = SWING_IMGS[opt.id];\n    if (imgSrc) {\n      var img = el('img', {\n        src: imgSrc + '?width=120',\n        alt: '',\n        width: '60',\n        height: '70',\n        loading: 'lazy',\n        style: 'object-fit:contain;width:100%;height:100%;',\n      });\n      diagram.appendChild(img);\n    } else {\n      diagram.appendChild(\n        svgEl(\n          swingSvg(\n            opt.id.startsWith('in') ? 'in' : 'out',\n            opt.id.endsWith('right') ? 'right' : 'left'\n          )\n        )\n      );\n    }\n    var lbl = el('span', { class: 'qc-swing__label', text: opt.label });\n    var sub = el('span', { class: 'qc-swing__sub', text: opt.sub });\n    btn.appendChild(diagram);\n    btn.appendChild(lbl);\n    btn.appendChild(sub);\n    return btn;\n  }\n\n  function buildQcUi() {\n    // \u2500\u2500 Step 1: Finish Color \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n    var swatchRow = el('div', {\n      class: 'qc-swatches',\n      role: 'group',\n      'aria-label': 'Select finish color',\n    });\n    FINISH_TILES.forEach(function (t) {\n      swatchRow.appendChild(buildSwatchTile(t));\n    });\n\n    var woodLink = el('button', {\n      type: 'button',\n      class: 'qc-open-advanced',\n      'data-qc-open-advanced': '',\n      'data-track-click': 'open_modal',\n      'data-track-section': 'configurator_simplified',\n      'data-track-label': 'open_advanced',\n    });\n    woodLink.textContent = 'More real wood species & stains \u2192';\n\n    var step1 = el('div', { class: 'qc-step', id: 'qc-step-color' }, [\n      el('h3', { class: 'qc-step__label', text: 'Step 1 \u2014 Finish Color' }),\n      swatchRow,\n      el('p', { class: 'qc-step__hint' }, [woodLink]),\n    ]);\n\n    // \u2500\u2500 Step 2: Door Width \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n    // Auto-defaults to 32\" (most-popular hardware-stocked width). No placeholder \u2014\n    // a width must always be set so APO can pass required-field validation.\n    var widthSel = el('select', {\n      id: 'qc-width-select',\n      class: 'qc-width-select',\n      // Accessible name comes from the Step 2 heading via aria-labelledby, NOT a\n      // <label for> \u2014 a label-for makes the heading text a click target that opens\n      // this native select, which inflated interaction tracking (QA 2026-07-13).\n      'aria-labelledby': 'qc-width-label',\n    });\n    WIDTH_OPTIONS.forEach(function (w) {\n      var opt = el('option', { value: w.val });\n      opt.textContent = w.door + '\" door (' + w.ro + '\" rough opening)';\n      if (w.isDefault) opt.selected = true;\n      widthSel.appendChild(opt);\n    });\n\n    var customLink = el('button', {\n      type: 'button',\n      class: 'qc-open-advanced',\n      'data-qc-open-advanced': '',\n      'data-track-click': 'open_modal',\n      'data-track-section': 'configurator_simplified',\n      'data-track-label': 'custom_size',\n    });\n    customLink.textContent = 'Need a custom size? \u2192';\n\n    // Step 2 label row: \"STEP 2 \u2014 DOOR WIDTH\" on left,\n    // [tape-measure SVG icon] + \"how to measure\" text on right.\n    // Hovering (or tapping on touch) either the icon or text reveals an\n    // inline video popup showing the measurement guide.\n    // Heading is an <h3> to MATCH Steps 1 & 3 (non-interactive). It intentionally\n    // does NOT use <label for=\"qc-width-select\"> \u2014 a label-for makes the heading a\n    // click target that opens the native select and inflates interaction tracking\n    // (QA 2026-07-13). The select is named via aria-labelledby=\"qc-width-label\".\n    var widthLabel = el('h3', {\n      class: 'qc-step__label',\n      id: 'qc-width-label',\n      text: 'Step 2 \u2014 Door Width',\n    });\n\n    var measureTip = el('button', {\n      type: 'button',\n      class: 'qc-measure-tip',\n      'aria-label': 'How to measure door width \u2014 show video',\n      'aria-expanded': 'false',\n    });\n    // APO's exact tape-measure icon (full body + inner coil paths, currentColor)\n    var TAPE_SVG =\n      '<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 512 512\" focusable=\"false\" aria-hidden=\"true\" width=\"20\" height=\"20\">' +\n      '<path fill=\"currentColor\" d=\"M0 0 C5.3223643 -7.14717492 10.30987623 -14.42251879 15 -22 C25.28432519 -20.39913806 35.69233693 -7.99269864 43 -1 C43.93972656 -0.113125 44.87945312 0.77375 45.84765625 1.6875 C58.93282413 14.34937834 68.901169 29.27933758 77.625 45.1875 C78.15794678 46.14148682 78.15794678 46.14148682 78.70166016 47.11474609 C79.54901426 48.70240653 80.28427682 50.34881407 81 52 C80 55 80 55 77.89868164 56.25854492 C76.99496826 56.66177979 76.09125488 57.06501465 75.16015625 57.48046875 C74.17982422 57.92197266 73.19949219 58.36347656 72.18945312 58.81835938 C71.15755859 59.27017578 70.12566406 59.72199219 69.0625 60.1875 C68.03447266 60.65091797 67.00644531 61.11433594 65.94726562 61.59179688 C58.30265096 65 58.30265096 65 56 65 C56.56267578 66.29357422 56.56267578 66.29357422 57.13671875 67.61328125 C68.77034354 95.08071271 70.17849411 122.55062714 70.0625 152 C70.05747197 154.23958233 70.05291138 156.47916575 70.04882812 158.71875 C70.03879274 164.14588354 70.01919979 169.57286065 70 175 C81.55 175 93.1 175 105 175 C105 186.55 105 198.1 105 210 C159.78 210 214.56 210 271 210 C271 234.42 271 258.84 271 284 C260.77 284 250.54 284 240 284 C240 269.81 240 255.62 240 241 C195.45 241 150.9 241 105 241 C105 252.88 105 264.76 105 277 C67.3512057 277.0678523 29.70242751 277.12154677 -7.94641565 277.15319599 C-12.3935578 277.156948 -16.84069983 277.16083098 -21.2878418 277.16479492 C-22.61583256 277.16597532 -22.61583256 277.16597532 -23.97065141 277.16717956 C-38.2962953 277.18022518 -52.62190299 277.20387438 -66.94752542 277.23145839 C-81.65242765 277.25953607 -96.35731094 277.27618126 -111.06223887 277.28226548 C-120.13229213 277.28637702 -129.20224305 277.29935213 -138.2722648 277.3237494 C-144.49615879 277.33963576 -150.72000006 277.3443938 -156.94391284 277.34050413 C-160.53209286 277.33858709 -164.12009433 277.34147744 -167.70824242 277.35761642 C-171.60620403 277.37502002 -175.50393565 277.36893858 -179.40193176 277.36076355 C-180.52550215 277.36950207 -181.64907254 277.3782406 -182.80669051 277.38724393 C-199.14911995 277.29484594 -213.89847475 271.03683512 -225.59765625 259.6640625 C-234.20288323 250.1213555 -241.07922697 237.21576255 -241.14717102 224.14295959 C-241.15432632 223.19183792 -241.16148163 222.24071625 -241.16885376 221.26077271 C-241.17154266 220.2286264 -241.17423157 219.1964801 -241.17700195 218.13305664 C-241.18357315 217.03625076 -241.19014435 215.93944489 -241.19691467 214.80940247 C-241.21663178 211.17631962 -241.22831422 207.54327833 -241.23828125 203.91015625 C-241.24235678 202.66242369 -241.2464323 201.41469112 -241.25063133 200.12914848 C-241.26934716 194.19175524 -241.28390451 188.25437501 -241.2922433 182.31695944 C-241.30194994 175.5212897 -241.32809298 168.72595142 -241.36874419 161.93039805 C-241.40295474 156.002166 -241.4144224 150.0740412 -241.41844749 144.14571953 C-241.42326825 141.64911102 -241.43475024 139.15250486 -241.45348549 136.65596199 C-241.58913419 117.36242176 -240.29407292 98.45231693 -233.75 80.125 C-233.45407959 79.26970703 -233.15815918 78.41441406 -232.85327148 77.53320312 C-221.69795496 46.29482262 -200.11987273 17.79159756 -172 0 C-171.4225 -0.37914551 -170.845 -0.75829102 -170.25 -1.14892578 C-121.43474359 -33.14379368 -47.95926632 -36.07192681 0 0 Z M-116 9 C-116.70850098 9.18804199 -117.41700195 9.37608398 -118.14697266 9.56982422 C-135.28479693 14.31585751 -151.41912437 22.48537101 -165 34 C-165.78383057 34.66056396 -165.78383057 34.66056396 -166.58349609 35.33447266 C-190.43336604 55.66307512 -207.21097512 85.5178456 -210 117 C-210.39736715 125.09939867 -210.33071341 133.21723543 -210.3359375 141.32421875 C-210.34237536 143.6806496 -210.34910443 146.03707968 -210.35610962 148.39350891 C-210.3680295 153.31126764 -210.37179551 158.22895637 -210.37060547 163.14672852 C-210.37040167 169.4310181 -210.39779077 175.71485859 -210.43214989 181.99904156 C-210.45443189 186.85736639 -210.45844273 191.71558293 -210.45738602 196.57395363 C-210.45973664 198.89067964 -210.4685296 201.20740888 -210.48405075 203.52408409 C-210.5037527 206.76596751 -210.49785739 210.00687861 -210.48583984 213.2487793 C-210.49707886 214.19293198 -210.50831787 215.13708466 -210.51989746 216.10984802 C-210.44226672 224.39462323 -208.42181962 231.66298153 -202.75 237.875 C-196.94932207 243.1642203 -190.29299585 246.12682006 -182.43167496 246.12304783 C-181.0559793 246.1260344 -181.0559793 246.1260344 -179.65249181 246.12908131 C-178.64860567 246.12616847 -177.64471953 246.12325563 -176.6104126 246.12025452 C-175.54118773 246.12110894 -174.47196287 246.12196337 -173.37033725 246.12284368 C-169.77584598 246.12449509 -166.18140105 246.11898261 -162.58691406 246.11352539 C-160.01492819 246.11324342 -157.44294224 246.11340145 -154.87095642 246.1139679 C-149.32761401 246.11449238 -143.78428336 246.11135341 -138.24094391 246.10573006 C-130.22619477 246.09760491 -122.21145133 246.09499879 -114.19669852 246.09374207 C-101.19346636 246.09155315 -88.19024047 246.08489738 -75.18701172 246.07543945 C-62.5551761 246.06626121 -49.92334219 246.05918239 -37.29150391 246.05493164 C-36.12367148 246.05453756 -36.12367148 246.05453756 -34.93224648 246.05413551 C-31.02648643 246.05283048 -27.12072637 246.05156677 -23.2149663 246.05032361 C9.19002721 246.03995597 41.59501229 246.02206688 74 246 C74 232.8 74 219.6 74 206 C62.12 206 50.24 206 38 206 C38.02094727 203.37836914 38.04189453 200.75673828 38.06347656 198.05566406 C38.13027677 189.31471486 38.17414469 180.57375325 38.20724869 171.8326149 C38.2279687 166.54191643 38.25599505 161.25148332 38.30175781 155.9609375 C38.34577967 150.83857431 38.36925365 145.71646349 38.37950897 140.59392548 C38.38680073 138.65665473 38.40103342 136.71939502 38.42292023 134.78223419 C38.80273149 99.71503712 27.04108062 68.16253265 2.65625 42.68359375 C-4.02337201 35.93521093 -11.06673316 30.21470188 -19 25 C-19.74507812 24.49726563 -20.49015625 23.99453125 -21.2578125 23.4765625 C-40.10255106 11.40315373 -62.98245658 5.57576446 -85.1875 5.6875 C-86.96241821 5.69595947 -86.96241821 5.69595947 -88.77319336 5.70458984 C-98.13322803 5.83358807 -106.95202714 6.58411844 -116 9 Z\" transform=\"translate(241,127)\"/>' +\n      '<path fill=\"currentColor\" d=\"M0 0 C0.75925781 0.66515625 1.51851562 1.3303125 2.30078125 2.015625 C17.06400569 15.78443536 26.38902234 35.92473318 27.38671875 56.0234375 C28.08143955 81.39425519 21.35885609 103.45463544 3.82592773 122.2890625 C-11.23044078 137.7748172 -32.04033404 146.85275463 -53.57348633 147.29296875 C-79.00500363 147.47026909 -99.82649553 139.3594019 -118.328125 121.7890625 C-135.59201659 103.50564976 -141.71455367 81.63634396 -141.31640625 57.0078125 C-140.43032762 33.40623691 -128.45035467 13.55748723 -111.59765625 -2.25390625 C-79.44913749 -29.58817095 -31.18177466 -27.78677407 0 0 Z M-97.28125 27.55859375 C-107.4299242 40.72685587 -111.47575779 54.39379994 -110 71 C-107.0425129 85.89994858 -99.01771382 98.71286835 -86.4375 107.4375 C-73.15922433 115.5351479 -59.20042178 118.25234907 -43.8125 114.875 C-29.20902071 110.68595415 -17.66824673 101.01512429 -9.85546875 88.109375 C-3.05638892 75.58073351 -1.76792221 60.73172549 -5.625 47.0625 C-10.78996323 32.49512131 -20.28076706 21.2942553 -34.203125 14.41796875 C-56.00759074 5.10005051 -81.15301757 9.46956594 -97.28125 27.55859375 Z\" transform=\"translate(212,191)\"/>' +\n      '</svg>';\n    var tapeSvg = svgEl(TAPE_SVG);\n    var tipText = el('span', {\n      class: 'qc-measure-tip__text',\n      text: 'How to measure',\n    });\n\n    // Hover popup with the actual video. No role=\"tooltip\" \u2014 that role forbids\n    // interactive descendants (we have a <video>), and ARIA-spec tooltips need\n    // an aria-describedby pointer anyway, which we don't have.\n    var tipPopup = el('div', {\n      class: 'qc-measure-tip__popup',\n      'aria-hidden': 'true',\n    });\n    var measureVideo = el('video', {\n      class: 'qc-measure-tip__video',\n      'webkit-playsinline': '',\n      playsinline: '',\n      muted: '',\n      loop: '',\n      controls: '',\n      preload: 'metadata',\n      'aria-label': 'Door width measurement guide',\n    });\n    measureVideo.muted = true;\n    var srcMp4 = document.createElement('source');\n    srcMp4.src =\n      'https://cdn.shopify.com/videos/c/o/v/4a3171677f7848c68f468d500005ad2b.mp4';\n    srcMp4.type = 'video/mp4';\n    var srcWebm = document.createElement('source');\n    srcWebm.src =\n      'https://cdn.shopify.com/videos/c/o/v/9fcf00eda2a34aac9b3ceb061a2225ef.webm';\n    srcWebm.type = 'video/webm';\n    measureVideo.appendChild(srcMp4);\n    measureVideo.appendChild(srcWebm);\n    tipPopup.appendChild(measureVideo);\n\n    measureTip.appendChild(tapeSvg);\n    measureTip.appendChild(tipText);\n    measureTip.appendChild(tipPopup);\n\n    // Hover/focus/tap behavior \u2014 play video while popup is showing, pause when hidden.\n    // Use a single `is-open` class driven by either CSS :hover or JS tap-toggle.\n    var openTip = function () {\n      measureTip.classList.add('is-open');\n      measureTip.setAttribute('aria-expanded', 'true');\n      tipPopup.setAttribute('aria-hidden', 'false');\n      var p = measureVideo.play();\n      if (p && p.catch)\n        p.catch(function () {\n          /* autoplay blocked \u2014 controls fallback */\n        });\n    };\n    var closeTip = function () {\n      measureTip.classList.remove('is-open');\n      measureTip.setAttribute('aria-expanded', 'false');\n      tipPopup.setAttribute('aria-hidden', 'true');\n      measureVideo.pause();\n      measureVideo.currentTime = 0;\n    };\n    // Touch taps synthesize a focusin (and, on many mobile browsers, a\n    // mouseenter) that fire BEFORE the click toggle. Without guarding, the tap\n    // opens the popup then the click immediately toggles it shut \u2014 the popup\n    // flashes invisibly and the \"how to measure\" video never plays on phones.\n    // Fix: only wire hover open/close on hover-capable pointers, and stand the\n    // focus-open handler down for the focus that a touch tap induces, leaving\n    // the click toggle to own the interaction on touch.\n    var hoverCapable =\n      typeof window.matchMedia === 'function' &&\n      window.matchMedia('(hover: hover)').matches;\n    var suppressFocusOpen = false;\n    measureTip.addEventListener(\n      'pointerdown',\n      function (e) {\n        if (e.pointerType === 'touch' || e.pointerType === 'pen') {\n          suppressFocusOpen = true;\n        }\n      },\n      { passive: true }\n    );\n    if (hoverCapable) {\n      measureTip.addEventListener('mouseenter', openTip);\n      measureTip.addEventListener('mouseleave', closeTip);\n    }\n    measureTip.addEventListener('focusin', function () {\n      if (suppressFocusOpen) {\n        suppressFocusOpen = false;\n        return;\n      }\n      openTip();\n    });\n    measureTip.addEventListener('focusout', closeTip);\n    // Click toggles (native <button> handles Enter/Space \u2192 click)\n    measureTip.addEventListener('click', function (e) {\n      e.preventDefault();\n      if (measureTip.classList.contains('is-open')) closeTip();\n      else openTip();\n    });\n    // Escape dismisses\n    measureTip.addEventListener('keydown', function (e) {\n      if (e.key === 'Escape') closeTip();\n    });\n\n    var step2HeaderRow = el('div', { class: 'qc-step__header' }, [\n      widthLabel,\n      measureTip,\n    ]);\n\n    var step2 = el('div', { class: 'qc-step', id: 'qc-step-width' }, [\n      step2HeaderRow,\n      widthSel,\n      el('p', { class: 'qc-step__hint' }, [\n        document.createTextNode(\n          'Width is the finished door. Rough opening is 2\u2033 larger. '\n        ),\n        customLink,\n      ]),\n    ]);\n\n    // \u2500\u2500 Step 3: Swing & Hinge \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n    var swingGrid = el('div', {\n      class: 'qc-swing-grid',\n      role: 'group',\n      'aria-label': 'Select swing and hinge direction',\n    });\n    SWING_OPTIONS.forEach(function (s) {\n      swingGrid.appendChild(buildSwingOption(s));\n    });\n\n    var step3 = el('div', { class: 'qc-step', id: 'qc-step-swing' }, [\n      el('h3', { class: 'qc-step__label', text: 'Step 3 \u2014 Swing & Hinge' }),\n      swingGrid,\n    ]);\n\n    // \u2500\u2500 Advanced Options button \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n    var advBtn = el('button', {\n      type: 'button',\n      class: 'qc-advanced-btn',\n      id: 'qc-advanced-btn',\n      'data-qc-open-advanced': '',\n      'aria-expanded': 'false',\n      'aria-controls': 'qc-advanced-panel',\n      'data-track-click': 'open_modal',\n      'data-track-section': 'configurator_simplified',\n      'data-track-label': 'open_advanced',\n    });\n    // Leading \"sliders\" (adjust/customize) icon + trailing chevron so the row\n    // reads unmistakably as an interactive control, not a passive info banner.\n    // NOTE: the xmlns + explicit width/height are REQUIRED. svgEl() parses via\n    // DOMParser('image/svg+xml'); without xmlns the root comes back namespace-null\n    // (an unknown element the stylesheet width never applies to \u2192 0\u00D70, invisible).\n    // Matches the working tape-measure SVG pattern above.\n    var advIcon = svgEl(\n      '<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"22\" height=\"22\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">' +\n        '<path d=\"M4 7h9\"/><path d=\"M18 7h2\"/><circle cx=\"15.5\" cy=\"7\" r=\"2.2\"/>' +\n        '<path d=\"M4 17h2\"/><path d=\"M11 17h9\"/><circle cx=\"8.5\" cy=\"17\" r=\"2.2\"/>' +\n        '</svg>'\n    );\n    advIcon.setAttribute('class', 'qc-advanced-btn__icon');\n    var advChevron = svgEl(\n      '<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">' +\n        '<path d=\"M9 6l6 6-6 6\"/></svg>'\n    );\n    advChevron.setAttribute('class', 'qc-advanced-btn__chevron');\n    var advBtnBody = el('span', { class: 'qc-advanced-btn__body' }, [\n      el('span', { class: 'qc-advanced-btn__title', text: 'Advanced Options' }),\n      el('span', {\n        class: 'qc-advanced-btn__hint',\n        text: 'custom sizes, cabinet doors, locks, ...',\n      }),\n    ]);\n    advBtn.appendChild(advIcon);\n    advBtn.appendChild(advBtnBody);\n    advBtn.appendChild(advChevron);\n\n    // \u2500\u2500 QC container \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n    var qcContainer = el(\n      'div',\n      {\n        class: 'qc-container',\n        id: 'qc-container',\n        role: 'group',\n        'aria-label': 'Quick Configure',\n      },\n      [step1, step2, step3, advBtn]\n    );\n\n    // \u2500\u2500 Advanced panel \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n    var closeBtn = el('button', {\n      type: 'button',\n      class: 'qc-advanced-panel__close',\n      id: 'qc-advanced-close',\n      'aria-label': 'Close Advanced Options',\n      text: '\u00D7',\n      'data-track-click': 'dismiss_modal',\n      'data-track-section': 'configurator_simplified',\n      'data-track-label': 'close_advanced',\n    });\n\n    var panelHeader = el('div', { class: 'qc-advanced-panel__header' }, [\n      el('h2', {\n        id: 'qc-advanced-panel-title',\n        class: 'qc-advanced-panel__title',\n        text: 'Advanced Options',\n      }),\n      closeBtn,\n    ]);\n\n    var panelSubhead = el('p', {\n      class: 'qc-advanced-panel__subhead',\n      text: 'Your quick selections are already applied. Change anything below.',\n    });\n\n    var panelBody = el('div', {\n      class: 'qc-advanced-panel__body',\n      id: 'qc-advanced-body',\n    });\n\n    var advPanel = el(\n      'div',\n      {\n        class: 'qc-advanced-panel',\n        id: 'qc-advanced-panel',\n        role: 'dialog',\n        'aria-labelledby': 'qc-advanced-panel-title',\n        'aria-hidden': 'true',\n        'aria-modal': 'true',\n      },\n      [panelHeader, panelSubhead, panelBody]\n    );\n\n    var scrim = el('div', {\n      class: 'qc-scrim',\n      id: 'qc-scrim',\n      'aria-hidden': 'true',\n    });\n\n    // SR-only live region \u2014 receives missing-step announcements when ATC validation\n    // fires. role=\"status\" + aria-live=\"polite\" lets AT users hear the error without\n    // a hijacking jump in reading focus (assertive would be too aggressive).\n    var srStatus = el('div', {\n      class: 'qc-sr-status',\n      id: 'qc-sr-status',\n      role: 'status',\n      'aria-live': 'polite',\n      'aria-atomic': 'true',\n    });\n\n    return {\n      qcContainer: qcContainer,\n      advPanel: advPanel,\n      scrim: scrim,\n      panelBody: panelBody,\n      srStatus: srStatus,\n    };\n  }\n\n  // \u2500\u2500\u2500 Advanced panel open/close \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n  // Scroll lock uses the position:fixed pattern (NOT body.overflow:hidden) because\n  // iOS Safari ignores overflow:hidden on body and keeps bouncing/scrolling the\n  // viewport. We capture the scroll position, pin the body in place, then restore\n  // on close. https://markus.oberlehner.net/blog/simple-solution-to-prevent-body-scrolling-on-ios/\n  //\n  // Back-button handling: pushState({qcAdvancedOpen:true}) on open so the Android\n  // hardware back button (and browser back) fires popstate, which we close on.\n  // On explicit close we replaceState back to the original entry to avoid a\n  // duplicate history entry the user has to press back through.\n\n  var _scrollLockY = 0;\n  var _historyPushed = false;\n  var _focusTrapHandler = null;\n  var _panelTrigger = null; // element that opened the Advanced panel \u2014 focus restored on close\n\n  function lockBodyScroll() {\n    _scrollLockY =\n      window.pageYOffset || document.documentElement.scrollTop || 0;\n    document.body.style.position = 'fixed';\n    document.body.style.top = '-' + _scrollLockY + 'px';\n    document.body.style.left = '0';\n    document.body.style.right = '0';\n    document.body.style.width = '100%';\n  }\n\n  function unlockBodyScroll() {\n    document.body.style.position = '';\n    document.body.style.top = '';\n    document.body.style.left = '';\n    document.body.style.right = '';\n    document.body.style.width = '';\n    if (_scrollLockY) {\n      window.scrollTo(0, _scrollLockY);\n      _scrollLockY = 0;\n    }\n  }\n\n  // Build a focus trap that wraps Tab/Shift-Tab back to the first/last focusable\n  // descendant of the panel. Stored as a module-level handler so close can detach.\n  function installFocusTrap(panel) {\n    _focusTrapHandler = function (e) {\n      if (e.key !== 'Tab') return;\n      var focusables = panel.querySelectorAll(\n        'a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex=\"-1\"])'\n      );\n      if (!focusables.length) return;\n      var first = focusables[0];\n      var last = focusables[focusables.length - 1];\n      if (e.shiftKey && document.activeElement === first) {\n        e.preventDefault();\n        last.focus();\n      } else if (!e.shiftKey && document.activeElement === last) {\n        e.preventDefault();\n        first.focus();\n      }\n    };\n    panel.addEventListener('keydown', _focusTrapHandler);\n  }\n\n  function uninstallFocusTrap(panel) {\n    if (_focusTrapHandler && panel) {\n      panel.removeEventListener('keydown', _focusTrapHandler);\n    }\n    _focusTrapHandler = null;\n  }\n\n  // Synchronise the Advanced panel's bottom edge with the sticky pricing bar.\n  // When the sticky bar is active the panel must sit above it so price + Buy Now\n  // remain visible in the unobscured strip below the drawer. The CSS custom\n  // property --qc-sticky-clearance drives the panel's bottom CSS property.\n  // Called pre-open (before is-open is added) so clearance is already applied\n  // when the slide-in transform begins \u2014 one instant reflow masked by the\n  // animation, not two concurrent ones (compositor-safe on iOS-15 hardware).\n  // The resize listener in wireAdvancedPanel already guards the is-open check,\n  // so the is-open condition is intentionally absent here to support the pre-open\n  // call path. Reset to 0px in closeAdvanced so the panel is full-height on\n  // the next open.\n  function updateStickyClearance() {\n    var panel = document.getElementById('qc-advanced-panel');\n    if (!panel) return;\n    var bar = document.querySelector('.pdp-sticky-bar');\n    if (bar && bar.classList.contains('pdp-sticky-bar--active')) {\n      panel.style.setProperty(\n        '--qc-sticky-clearance',\n        bar.getBoundingClientRect().height + 'px'\n      );\n    } else {\n      panel.style.setProperty('--qc-sticky-clearance', '0px');\n    }\n  }\n\n  function openAdvanced() {\n    var panel = document.getElementById('qc-advanced-panel');\n    var scrim = document.getElementById('qc-scrim');\n    var btn = document.getElementById('qc-advanced-btn');\n    if (!panel || panel.classList.contains('is-open')) return;\n    // Opening Advanced hands control to the full APO form. Any pending Step-3 swing\n    // intent latch is now stale \u2014 release it so a swing the user re-picks in Advanced\n    // isn't force-overridden by the old QC intent for up to 1200ms after close\n    // (cascade audit 2026-07-14).\n    releaseSwingIntent();\n    // Capture the triggering element so focus returns to it on close (WCAG 2.4.3)\n    _panelTrigger = document.activeElement;\n    // Set the freeze sentinel BEFORE updateStickyClearance and lockBodyScroll.\n    // The position:fixed lock fires a synthetic scroll event that drops\n    // window.scrollY to 0; pdp-sticky-bar's freeze guard must be set first to\n    // suppress the resulting false bar-deactivation.\n    // Routed through the shared refcounted owner (md-shared-body-scroll-lock.js)\n    // rather than a raw classList write \u2014 see that file for why a second\n    // consumer of this class needs this. Falls back to the raw write if the\n    // shared script somehow isn't loaded, so this never regresses to \"silently\n    // does nothing\" on a load-order surprise.\n    if (window.__mdBodyScrollLock) {\n      window.__mdBodyScrollLock.acquire('quick-config-advanced-panel');\n    } else {\n      document.body.classList.add('qc-advanced-open');\n    }\n    // Apply clearance BEFORE is-open: --qc-sticky-clearance is set while the\n    // panel is still in its base state, producing a single instant reflow that\n    // the slide-in animation masks. Avoids concurrent bottom+transform reflow\n    // during open (compositor-safe on iOS-15-era hardware). While the panel is\n    // open, clearance changes (resize/orientation) still animate via the bottom\n    // transition declared on .qc-advanced-panel.is-open in the CSS.\n    updateStickyClearance();\n    // Force a style recalc so the clearance write commits NOW, while the base\n    // state's transition list has no `bottom`. Without this flush, the clearance\n    // write and the is-open class-add below land in the SAME recalc \u2014 and per\n    // CSS Transitions, the AFTER state's transition list (which includes bottom\n    // via .qc-advanced-panel.is-open) governs, so bottom would animate 0\u2192clearance\n    // concurrently with the slide-in \u2014 the exact per-frame APO-subtree reflow\n    // this ordering exists to prevent.\n    void panel.offsetHeight;\n    // Hide sticky bar from the accessibility tree while the modal is open.\n    // role=dialog aria-modal=true requires content outside the dialog to be\n    // aria-hidden so VoiceOver touch-exploration cannot reach the sticky Buy Now\n    // button outside the modal. The bar remains visually tappable for sighted\n    // users. (Accessibility audit finding, PR #1384 follow-up)\n    var sb = document.querySelector('.pdp-sticky-bar');\n    if (sb) sb.setAttribute('aria-hidden', 'true');\n    panel.classList.add('is-open');\n    panel.setAttribute('aria-hidden', 'false');\n    scrim.classList.add('is-visible');\n    if (btn) btn.setAttribute('aria-expanded', 'true');\n    // Push BEFORE lockBodyScroll: the browser snapshots the current entry's scroll\n    // position at pushState time. Pushing after the lock would capture scrollY=0\n    // (the lock zeroes it), so history.back() on close would restore scroll=0 and\n    // dump the user at the top of the page instead of where they were.\n    if (!_historyPushed) {\n      try {\n        history.pushState({ qcAdvancedOpen: true }, '');\n        _historyPushed = true;\n      } catch (e) {\n        /* pushState may throw in some embedded WebViews \u2014 non-fatal */\n      }\n    }\n    lockBodyScroll();\n    installFocusTrap(panel);\n    // iOS Safari ignores programmatic .focus() outside the user-gesture call stack.\n    // requestAnimationFrame keeps the call within the gesture's rendering frame,\n    // unlike setTimeout(80) which lands in a macrotask iOS may not honor.\n    var closeBtn = document.getElementById('qc-advanced-close');\n    if (closeBtn)\n      requestAnimationFrame(function () {\n        closeBtn.focus();\n      });\n  }\n\n  // closeAdvanced has two trigger paths: explicit user action (close X, scrim,\n  // Escape) which should pop the history entry we pushed, AND a popstate event\n  // (back button) where the entry is already popped \u2014 fromPopState=true skips\n  // history.back() to avoid a double-pop.\n  function closeAdvanced(fromPopState) {\n    var panel = document.getElementById('qc-advanced-panel');\n    var scrim = document.getElementById('qc-scrim');\n    var btn = document.getElementById('qc-advanced-btn');\n    if (!panel || !panel.classList.contains('is-open')) return;\n    panel.classList.remove('is-open');\n    panel.setAttribute('aria-hidden', 'true');\n    scrim.classList.remove('is-visible');\n    if (btn) btn.setAttribute('aria-expanded', 'false');\n    // Return focus to the element that opened the panel (WCAG 2.4.3).\n    // Fall back to the primary Advanced button if trigger is no longer in the DOM.\n    var returnTarget =\n      _panelTrigger && document.body.contains(_panelTrigger)\n        ? _panelTrigger\n        : btn;\n    _panelTrigger = null;\n    if (returnTarget) returnTarget.focus();\n    unlockBodyScroll();\n    uninstallFocusTrap(panel);\n    // Release the sticky-bar freeze guard and reset panel clearance. The dispatched\n    // scroll event lets pdp-sticky-bar re-evaluate its active state at the scrollY\n    // position that unlockBodyScroll() just restored. Runs on both exit paths\n    // (explicit close button/scrim/Escape AND popstate back-button) because\n    // closeAdvanced is the single implementation for both \u2014 no duplication needed.\n    // Routed through the shared refcounted owner \u2014 see openAdvanced()'s acquire\n    // call above for why.\n    if (window.__mdBodyScrollLock) {\n      window.__mdBodyScrollLock.release('quick-config-advanced-panel');\n    } else {\n      document.body.classList.remove('qc-advanced-open');\n    }\n    // Restore sticky bar to the accessibility tree and mirror its real state.\n    // Cannot rely on the dispatched scroll event below: setBarActive early-returns\n    // when isActive === barIsActive (no state change) and skips the aria-hidden\n    // write, so the attribute would stay 'true' if the bar was already active.\n    var sb = document.querySelector('.pdp-sticky-bar');\n    if (sb)\n      sb.setAttribute(\n        'aria-hidden',\n        sb.classList.contains('pdp-sticky-bar--active') ? 'false' : 'true'\n      );\n    panel.style.setProperty('--qc-sticky-clearance', '0px');\n    window.dispatchEvent(new Event('scroll'));\n    if (_historyPushed && !fromPopState) {\n      _historyPushed = false;\n      try {\n        history.back();\n      } catch (e) {\n        /* non-fatal */\n      }\n    } else if (fromPopState) {\n      _historyPushed = false;\n    }\n    // Sync QC display from whatever the user changed in Advanced\n    syncQcFromApo();\n  }\n\n  // Enable/disable QC swing tiles to match the active depth. The 5\u00BC\u2033 depth is\n  // Out-Swing-only, so its swing group has no In-Swing value \u2014 the two In-Swing\n  // tiles must be disabled (and cleared) rather than silently no-op on click.\n  function updateSwingTileAvailability() {\n    var inAllowed = activeDepthAllowsInSwing();\n    document.querySelectorAll('[data-qc-swing]').forEach(function (b) {\n      var id = b.getAttribute('data-qc-swing');\n      var opt = null;\n      for (var i = 0; i < SWING_OPTIONS.length; i++) {\n        if (SWING_OPTIONS[i].id === id) {\n          opt = SWING_OPTIONS[i];\n          break;\n        }\n      }\n      var disabled = !!(opt && opt.dir === 'in' && !inAllowed);\n      b.disabled = disabled;\n      b.classList.toggle('qc-swing--unavailable', disabled);\n      b.setAttribute('aria-disabled', disabled ? 'true' : 'false');\n      if (disabled) {\n        b.classList.remove('is-active');\n        b.setAttribute('aria-pressed', 'false');\n      }\n    });\n  }\n\n  // Intent latch for Step 3. When the user clicks a QC swing tile, APO reaches its\n  // final swing+hinge+jamb state over ~600ms of chained swatch clicks. Every one of\n  // those fires mwApo::applyAttributeStateToHtml, and a sync that runs mid-settle\n  // sees an INCOMPLETE state (swing set but hinge not yet, or vice-versa) \u2192 resolves\n  // no matching tile \u2192 clobbers the tile the user just clicked (\"checks then\n  // un-checks\" \u2014 QA 2026-07-13). Latch the intended tile so reverse-sync keeps it\n  // lit until APO converges to it (or the settle window elapses and truth wins).\n  var _swingIntentId = null;\n  var _swingIntentTimer = null;\n  function latchSwingIntent(tileId) {\n    _swingIntentId = tileId;\n    if (_swingIntentTimer) clearTimeout(_swingIntentTimer);\n    // Release the latch if APO never converges (e.g. a selection it rejects), so a\n    // stuck intent can't outlive reality. Comfortably longer than the applySwing\n    // chain (swing 0ms \u2192 hinge ~350ms \u2192 jamb ~550ms + APO async).\n    _swingIntentTimer = setTimeout(function () {\n      _swingIntentId = null;\n      _swingIntentTimer = null;\n    }, 1200);\n  }\n  function releaseSwingIntent() {\n    _swingIntentId = null;\n    if (_swingIntentTimer) {\n      clearTimeout(_swingIntentTimer);\n      _swingIntentTimer = null;\n    }\n  }\n\n  // Read APO's current enabled state and update QC tile/swing/width active states.\n  // Called on Advanced panel close so QC reflects what the user configured in full form.\n  function syncQcFromApo() {\n    var key = getApoRespKey();\n    var resp =\n      window.mwApoInit &&\n      window.mwApoInit.response &&\n      window.mwApoInit.response[key];\n    if (!resp) return;\n\n    // \u2500\u2500 Sync color tile \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n    var enabledWood = currentEnabledVal(APO.OPT.woodType);\n    var enabledFinish = null;\n    ALL_FINISH_OPTS.forEach(function (oid) {\n      var v = currentEnabledVal(oid);\n      if (v) enabledFinish = v;\n    });\n\n    var activeTileId = null;\n    for (var i = 0; i < FINISH_TILES.length; i++) {\n      var t = FINISH_TILES[i];\n      if (t.wood === enabledWood && t.finishVal === enabledFinish) {\n        activeTileId = t.id;\n        break;\n      }\n    }\n    document.querySelectorAll('[data-qc-tile]').forEach(function (b) {\n      var match = b.getAttribute('data-qc-tile') === activeTileId;\n      b.classList.toggle('is-active', match);\n      b.setAttribute('aria-pressed', match ? 'true' : 'false');\n    });\n\n    // \u2500\u2500 Sync swing tile (depth-aware) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n    // First reflect which directions the active depth allows (disables the two\n    // In-Swing tiles at 5\u00BC\u2033), THEN mark the active tile from the enabled swing.\n    updateSwingTileAvailability();\n\n    var enabledSwing = getEnabledSwing(); // { dir } across ALL swing groups, or null\n    // Read the hinge from the group that MATCHES the active swing direction. Reading\n    // hingesIn||hingesOut blindly lets a stale flag in the hidden opposite group win,\n    // so an Out-Swing tile would match against a leftover In-Swing hinge and clear\n    // itself (QA 2026-07-13). Direction-scoped read ignores the opposite group.\n    var enabledHinge = null;\n    if (enabledSwing) {\n      enabledHinge =\n        enabledSwing.dir === 'in'\n          ? currentEnabledVal(APO.OPT.hingesIn)\n          : currentEnabledVal(APO.OPT.hingesOut);\n    }\n\n    var activeSwingId = null;\n    if (enabledSwing && enabledHinge) {\n      for (var j = 0; j < SWING_OPTIONS.length; j++) {\n        var s = SWING_OPTIONS[j];\n        if (s.dir === enabledSwing.dir && s.hinge === enabledHinge) {\n          activeSwingId = s.id;\n          break;\n        }\n      }\n    }\n    // Intent latch: if the user just applied a swing tile, keep it lit until APO's\n    // async cascade actually converges to it. Only release once state matches (or\n    // the latch times out) \u2014 otherwise a mid-settle sync would clear the selection.\n    if (_swingIntentId) {\n      if (activeSwingId === _swingIntentId) {\n        releaseSwingIntent();\n      } else {\n        activeSwingId = _swingIntentId;\n      }\n    }\n    document.querySelectorAll('[data-qc-swing]').forEach(function (b) {\n      if (b.disabled) return; // leave unavailable tiles cleared\n      var match = b.getAttribute('data-qc-swing') === activeSwingId;\n      b.classList.toggle('is-active', match);\n      b.setAttribute('aria-pressed', match ? 'true' : 'false');\n    });\n\n    // \u2500\u2500 Sync width dropdown \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n    var qcWidthSel = document.querySelector('#qc-width-select');\n    var apoWidthSel = document.querySelector(\n      'select[name=\"' + APO.doorWidth.name + '\"]'\n    );\n    reconcileWidthOption(qcWidthSel, apoWidthSel);\n    if (qcWidthSel && apoWidthSel && qcWidthSel.value !== apoWidthSel.value) {\n      qcWidthSel.value = apoWidthSel.value;\n    }\n\n    syncWidthLabelWithHeight();\n  }\n\n  // The QC dropdown deliberately curates only 7 popular widths, but APO offers 26\n  // (every inch 24\u201349\u2033 + custom). If Advanced selects a width outside the curated\n  // set, the QC <select> would blank out and getQcMissing() would falsely block ATC\n  // (the 38\u2033 bug, 2026-07-09). Fix: inject a single reusable <option> mirroring the\n  // APO-selected width so the dropdown always has a matching entry. When the user\n  // returns to a curated width, the injected option is removed. Its label is filled\n  // by syncWidthLabelWithHeight() from the door/ro parsed off APO's own option text.\n  function reconcileWidthOption(qcWidthSel, apoWidthSel) {\n    if (!qcWidthSel || !apoWidthSel || !apoWidthSel.value) return;\n    var apoVal = apoWidthSel.value;\n    var curated = false;\n    for (var i = 0; i < WIDTH_OPTIONS.length; i++) {\n      if (WIDTH_OPTIONS[i].val === apoVal) {\n        curated = true;\n        break;\n      }\n    }\n    var injected = qcWidthSel.querySelector('option[data-qc-injected]');\n    if (curated) {\n      if (injected) injected.remove();\n      return;\n    }\n    // Parse door/RO from APO's own selected option text, e.g. '38\" (Rough Opening 40\")'.\n    var apoOpt = apoWidthSel.options[apoWidthSel.selectedIndex];\n    var m = apoOpt\n      ? apoOpt.textContent.trim().match(/^(\\d+)\"\\s*\\(Rough Opening (\\d+)\"\\)/)\n      : null;\n    if (!injected) {\n      injected = document.createElement('option');\n      injected.setAttribute('data-qc-injected', '');\n      qcWidthSel.appendChild(injected);\n    }\n    injected.value = apoVal;\n    if (m) {\n      injected.dataset.door = m[1];\n      injected.dataset.ro = m[2];\n    } else {\n      // Custom / unparseable label \u2014 mirror APO's text verbatim as a safe fallback.\n      delete injected.dataset.door;\n      delete injected.dataset.ro;\n      injected.textContent = apoOpt\n        ? apoOpt.textContent.trim()\n        : 'Custom width';\n    }\n  }\n\n  // Update QC width dropdown option labels to include the height currently selected\n  // in APO's Door Height select (mw_opts[o_2314963]). Called on panel close and on\n  // any APO state change so the label stays in sync: \"32\" x 80\" door (34\" x 82\" rough opening)\".\n  function syncWidthLabelWithHeight() {\n    var qcSel = document.getElementById('qc-width-select');\n    if (!qcSel) return;\n    var heightSel = document.querySelector(\n      'select[name=\"mw_opts[' + APO.OPT.doorHeight + ']\"]'\n    );\n    var heightDoor = null,\n      heightRo = null;\n    if (heightSel && heightSel.value) {\n      var text = heightSel.options[heightSel.selectedIndex].textContent.trim();\n      // Standard: '80\" (Rough Opening 82\") (+$165.00)' \u2192 door=80, ro=82\n      var m = text.match(/^(\\d+)\"\\s*\\(Rough Opening (\\d+)\"\\)/);\n      if (m) {\n        heightDoor = m[1];\n        heightRo = m[2];\n      } else {\n        // Range option: 'Height from 36\" to 59\" (+$70.00)' \u2192 show as 36\"\u201359\"\n        var r = text.match(/Height from (\\d+)\" to (\\d+)\"/);\n        if (r) heightDoor = r[1] + '\u2013' + r[2] + '\"'; // 36\"\u201359\"\n      }\n    }\n    // Iterate the actual <option> nodes (not WIDTH_OPTIONS by index) so the injected\n    // out-of-curated width option is labelled too. Curated options resolve door/ro\n    // from WIDTH_OPTIONS by value; the injected option carries them in its dataset.\n    Array.prototype.forEach.call(qcSel.options, function (opt) {\n      var door = null,\n        ro = null;\n      if (opt.hasAttribute('data-qc-injected')) {\n        // Custom / unparseable injected width keeps the verbatim text set at inject time.\n        if (opt.dataset.door === undefined) return;\n        door = opt.dataset.door;\n        ro = opt.dataset.ro;\n      } else {\n        for (var i = 0; i < WIDTH_OPTIONS.length; i++) {\n          if (WIDTH_OPTIONS[i].val === opt.value) {\n            door = WIDTH_OPTIONS[i].door;\n            ro = WIDTH_OPTIONS[i].ro;\n            break;\n          }\n        }\n        if (door === null) return;\n      }\n      if (heightDoor) {\n        var roSuffix = heightRo ? ' x ' + heightRo + '\"' : '';\n        opt.textContent =\n          door +\n          '\" x ' +\n          heightDoor +\n          '\" door (' +\n          ro +\n          '\"' +\n          roSuffix +\n          ' rough opening)';\n      } else {\n        opt.textContent = door + '\" door (' + ro + '\" rough opening)';\n      }\n    });\n  }\n\n  // \u2500\u2500\u2500 Interaction wiring \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n  function wireColorTiles(qcContainer) {\n    qcContainer.querySelectorAll('[data-qc-tile]').forEach(function (btn) {\n      btn.addEventListener('click', function () {\n        var tileId = btn.getAttribute('data-qc-tile');\n        var tile;\n        for (var i = 0; i < FINISH_TILES.length; i++) {\n          if (FINISH_TILES[i].id === tileId) {\n            tile = FINISH_TILES[i];\n            break;\n          }\n        }\n        if (!tile) return;\n\n        // Update Quick Config UI active state\n        qcContainer.querySelectorAll('[data-qc-tile]').forEach(function (b) {\n          b.classList.remove('is-active');\n          b.setAttribute('aria-pressed', 'false');\n        });\n        btn.classList.add('is-active');\n        btn.setAttribute('aria-pressed', 'true');\n\n        // Direct APO state update \u2014 no label.click() timing games\n        applyColorSelection(\n          tile.woodOpt,\n          tile.wood,\n          tile.finishOpt,\n          tile.finishVal\n        );\n        clearQcMissing('color');\n      });\n    });\n  }\n\n  // Push the QC width selection to APO's own select element (now living in the\n  // Advanced panel) AND mutate the response.values enabled flag so APO accepts\n  // the value at cart submission. The QC select itself doesn't carry a `name`\n  // attribute (would conflict with APO's), so we sync via APO's select element.\n  function pushWidthToApo(valueId) {\n    if (!valueId) return;\n    // Find APO's width select \u2014 it's the one with the proper name attribute\n    var apoSel = document.querySelector(\n      'select[name=\"' + APO.doorWidth.name + '\"]'\n    );\n    if (apoSel && apoSel.value !== valueId) {\n      apoSel.value = valueId;\n      apoSel.dispatchEvent(new Event('change', { bubbles: true }));\n      apoSel.dispatchEvent(new Event('input', { bubbles: true }));\n    }\n    // Belt + suspenders: also flip the enabled flag in APO's internal state\n    setApoOption(APO.OPT.doorWidth, valueId);\n  }\n\n  function wireWidthSelect(qcContainer) {\n    var sel = qcContainer.querySelector('#qc-width-select');\n    if (!sel) return;\n    // Push the auto-default (32\") to APO at init so its required-field\n    // validation passes even if the customer never touches the dropdown.\n    if (sel.value) pushWidthToApo(sel.value);\n\n    sel.addEventListener('change', function () {\n      if (!sel.value) return;\n      pushWidthToApo(sel.value);\n      clearQcMissing('width');\n    });\n  }\n\n  function wireSwingOptions(qcContainer) {\n    qcContainer.querySelectorAll('[data-qc-swing]').forEach(function (btn) {\n      btn.addEventListener('click', function () {\n        var swingId = btn.getAttribute('data-qc-swing');\n        var opt;\n        for (var i = 0; i < SWING_OPTIONS.length; i++) {\n          if (SWING_OPTIONS[i].id === swingId) {\n            opt = SWING_OPTIONS[i];\n            break;\n          }\n        }\n        if (!opt) return;\n\n        // Ignore clicks on a direction the active depth doesn't offer (the tile is\n        // also visually disabled by updateSwingTileAvailability, but guard anyway).\n        if (btn.disabled) return;\n\n        // Direct APO state update \u2014 resolves swing value against the active group.\n        var applied = applySwingSelection(opt.dir, opt.hinge);\n        if (!applied) return;\n\n        // Latch the intent so the reverse-sync cascade can't un-check this tile\n        // while APO settles through its chained swing\u2192hinge\u2192jamb clicks.\n        latchSwingIntent(swingId);\n\n        // Update Quick Config UI only after a successful apply\n        qcContainer.querySelectorAll('[data-qc-swing]').forEach(function (b) {\n          b.classList.remove('is-active');\n          b.setAttribute('aria-pressed', 'false');\n        });\n        btn.classList.add('is-active');\n        btn.setAttribute('aria-pressed', 'true');\n        clearQcMissing('swing');\n      });\n    });\n  }\n\n  // \u2500\u2500\u2500 Required-field validation (matches APO's wiggle UX) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n  // When the customer clicks ATC without making all QC selections, intercept\n  // the click BEFORE APO processes it and highlight the missing QC step(s).\n  // If all 3 QC steps are satisfied AND APO still rejects (some other required\n  // field elsewhere), APO's native wiggle takes over.\n\n  // Re-assert the customer's QC selections into APO's state model from the lit\n  // tiles + the width dropdown \u2014 deterministic and render-independent (setApoOption\n  // flips the enabled flag directly; no swatch clicks, no waiting on APO's async\n  // reveal). Called at ATC submit so the cart payload always matches what the QC UI\n  // shows, no matter where APO's swing\u2192hinge\u2192jamb cascade happens to be. This makes\n  // the synchronous seed + heal in applySwingSelection reinforcing belt rather than\n  // the sole guarantor of a correct payload. 2026-07-14.\n  function flushQcIntentToApo() {\n    // Color \u2192 wood + finish groups (from the lit finish tile).\n    var litColor = document.querySelector('[data-qc-tile].is-active');\n    if (litColor) {\n      var cid = litColor.getAttribute('data-qc-tile');\n      for (var i = 0; i < FINISH_TILES.length; i++) {\n        if (FINISH_TILES[i].id === cid) {\n          setApoOption(FINISH_TILES[i].woodOpt, FINISH_TILES[i].wood);\n          setApoOption(FINISH_TILES[i].finishOpt, FINISH_TILES[i].finishVal);\n          break;\n        }\n      }\n    }\n    // Width \u2192 APO width select + model (idempotent when already set).\n    var w = document.getElementById('qc-width-select');\n    if (w && w.value) pushWidthToApo(w.value);\n    // Swing + hinge \u2192 active-depth swing group + hinge group (from the lit tile),\n    // clearing the opposite hinge group so APO's payload is unambiguous.\n    var litSwing = document.querySelector('[data-qc-swing].is-active');\n    if (litSwing) {\n      var sid = litSwing.getAttribute('data-qc-swing');\n      for (var j = 0; j < SWING_OPTIONS.length; j++) {\n        var o = SWING_OPTIONS[j];\n        if (o.id !== sid) continue;\n        var gid = getActiveSwingGroupId();\n        var sv = swingValueByDir(gid, o.dir);\n        if (sv) setApoOption(gid, sv);\n        setApoOption(o.hingeOpt, o.hinge);\n        setApoOption(\n          o.dir === 'in' ? APO.OPT.hingesOut : APO.OPT.hingesIn,\n          null\n        );\n        ensureJambDefault();\n        break;\n      }\n    }\n  }\n\n  // True when the Quick Config UI is the ACTIVE, visible configurator. False when a\n  // FigPii experiment variant (the R_Bookcase_PDP_Simplified_Configurator \"control\"\n  // cohort adds a *_d-none / display:none class directly to #qc-container so the raw\n  // MageWorx APO form drives the purchase) \u2014 or when QC never initialized \u2014 hides it.\n  // We read computed `display` rather than offsetParent because offsetParent depends on\n  // a layout engine (it's always null in jsdom, breaking tests) whereas the control\n  // variant's hide is a display:none ON the element itself, which getComputedStyle\n  // reports reliably in real browsers and defaults to a non-'none' block in jsdom.\n  function isQuickConfigActive() {\n    var qc = document.getElementById('qc-container');\n    if (!qc) return false;\n    if (qc.hidden) return false;\n    // Class-based hide (FigPii's *_d-none rule) \u2192 only computed style reveals it.\n    try {\n      var view = qc.ownerDocument && qc.ownerDocument.defaultView;\n      var cs = view && view.getComputedStyle ? view.getComputedStyle(qc) : null;\n      if (cs && cs.display === 'none') return false;\n    } catch (e) {\n      /* getComputedStyle unavailable \u2014 fall through to the inline check */\n    }\n    // Inline hide (and the path jsdom can evaluate in tests).\n    if (qc.style && qc.style.display === 'none') return false;\n    return true;\n  }\n\n  function getQcMissing() {\n    var missing = [];\n    var wood = currentEnabledVal(APO.OPT.woodType);\n    var anyFinish = false;\n    ALL_FINISH_OPTS.forEach(function (oid) {\n      if (currentEnabledVal(oid)) anyFinish = true;\n    });\n    if (!wood || !anyFinish) missing.push('color');\n\n    // Width is \"missing\" if the QC dropdown is on the placeholder (value=\"\")\n    // OR the QC dropdown's value doesn't match what APO has actively selected.\n    // We use the QC dropdown as the source of truth \u2014 the customer's explicit pick.\n    var qcWidth = document.getElementById('qc-width-select');\n    if (!qcWidth || !qcWidth.value) missing.push('width');\n\n    // Swing is satisfied when a QC swing tile is lit. The lit tile IS QC's\n    // reconciled Step-3 intent: syncQcFromApo keeps it correct across APO's async\n    // swing\u2192hinge\u2192jamb cascade (latched through the settle \u2014 see the \"keeps the\n    // just-clicked tile lit mid-settle\" regression) and clears it when a depth\n    // change invalidates the pick (\"changing depth clears the stale swing\n    // selection\"). Reading the tile instead of APO's mid-cascade `values` model\n    // closes the ATC-block window STRUCTURALLY: on a direction switch APO briefly\n    // clears BOTH hinge groups, and the old getEnabledSwing()/anyHinge read saw\n    // that empty window and spuriously blocked an otherwise-complete selection\n    // (the race the synchronous seed in applySwingSelection was patching). The lit\n    // tile never flickers, so the gate can't be fooled by APO's timing. 2026-07-14.\n    if (!document.querySelector('[data-qc-swing].is-active'))\n      missing.push('swing');\n    return missing;\n  }\n\n  function getStepFormControl(step, stepEl) {\n    if (step === 'width') return document.getElementById('qc-width-select');\n    return stepEl ? stepEl.querySelector('[role=\"group\"]') : null;\n  }\n\n  function clearQcMissing(step) {\n    var stepEl = document.getElementById('qc-step-' + step);\n    if (stepEl) {\n      stepEl.classList.remove('qc-step--missing');\n      var ctrl = getStepFormControl(step, stepEl);\n      if (ctrl) ctrl.removeAttribute('aria-invalid');\n    }\n  }\n\n  // Human-readable labels for the SR live-region announcement.\n  var QC_STEP_LABELS = {\n    color: 'finish color',\n    width: 'door width',\n    swing: 'swing and hinge direction',\n  };\n\n  function showQcMissing(missingSteps) {\n    missingSteps.forEach(function (step) {\n      var stepEl = document.getElementById('qc-step-' + step);\n      if (!stepEl) return;\n      stepEl.classList.add('qc-step--missing');\n      // aria-invalid belongs on the form control or role=group, not the container div (WCAG 3.3.1)\n      var ctrl = getStepFormControl(step, stepEl);\n      if (ctrl) ctrl.setAttribute('aria-invalid', 'true');\n      // Restart shake animation by forcing a reflow\n      stepEl.classList.remove('qc-step--shake');\n      void stepEl.offsetWidth;\n      stepEl.classList.add('qc-step--shake');\n      setTimeout(function () {\n        stepEl.classList.remove('qc-step--shake');\n      }, 500);\n    });\n    var firstMissing = document.getElementById('qc-step-' + missingSteps[0]);\n    if (firstMissing)\n      firstMissing.scrollIntoView({ behavior: 'smooth', block: 'center' });\n    // Announce to screen readers via the SR-only live region.\n    var srStatus = document.getElementById('qc-sr-status');\n    if (srStatus) {\n      var labels = missingSteps\n        .map(function (s) {\n          return QC_STEP_LABELS[s] || s;\n        })\n        .join(', ');\n      // Clear first so identical re-announcements still fire.\n      srStatus.textContent = '';\n      setTimeout(function () {\n        srStatus.textContent = 'Please make a selection for: ' + labels + '.';\n      }, 50);\n    }\n  }\n\n  function wireAtcValidation() {\n    // Capture phase listener fires BEFORE APO's bubble-phase handler \u2014 we can\n    // call stopImmediatePropagation to block APO from processing if QC is incomplete.\n    document.addEventListener(\n      'click',\n      function (e) {\n        var btn =\n          e.target.closest &&\n          e.target.closest(\n            '.mw-apo-add-to-cart-custom, .mw-apo-buy-it-now-cloned, .sticky-atc-proxy-btn'\n          );\n        if (!btn) return;\n        // Only gate the add when Quick Config is the ACTIVE configurator. In the FigPii\n        // control variant #qc-container is display:none and the raw APO form drives the\n        // purchase \u2014 the QC completeness mirror (swing tile / width select) never reflects\n        // the customer's real APO selections there, so running this capture-phase gate\n        // would spuriously stopImmediatePropagation() and kill APO's native add-to-cart,\n        // dumping the customer into an empty cart (custom-height report, 2026-07-15). When\n        // QC is hidden, APO's own required-field validation is authoritative \u2014 stay inert.\n        if (!isQuickConfigActive()) return;\n        var missing = getQcMissing();\n        if (missing.length === 0) {\n          // Flush QC intent \u2192 APO state synchronously, in capture phase, BEFORE\n          // APO's bubble-phase handler builds the cart payload. setApoOption writes\n          // the same model the cart reads and needs no DOM reveal, so this is\n          // render-independent and ordered-before APO: no cascade timing window can\n          // submit an incomplete config, even a fast tap mid-direction-switch.\n          flushQcIntentToApo();\n          return; // QC complete \u2014 let APO process\n        }\n        e.preventDefault();\n        e.stopImmediatePropagation();\n        showQcMissing(missing);\n      },\n      true\n    );\n  }\n\n  function wireAdvancedPanel(qcContainer) {\n    document\n      .querySelectorAll('[data-qc-open-advanced]')\n      .forEach(function (trigger) {\n        trigger.addEventListener('click', function (e) {\n          e.preventDefault();\n          openAdvanced();\n        });\n      });\n    var closeBtn = document.getElementById('qc-advanced-close');\n    if (closeBtn)\n      closeBtn.addEventListener('click', function () {\n        closeAdvanced();\n      });\n    var scrim = document.getElementById('qc-scrim');\n    if (scrim)\n      scrim.addEventListener('click', function () {\n        closeAdvanced();\n      });\n    document.addEventListener('keydown', function (e) {\n      if (e.key === 'Escape') {\n        var p = document.getElementById('qc-advanced-panel');\n        if (p && p.classList.contains('is-open')) closeAdvanced();\n      }\n    });\n    // Android hardware back-button / browser back closes the panel rather than\n    // navigating away. Pairs with history.pushState() in openAdvanced().\n    window.addEventListener('popstate', function () {\n      var p = document.getElementById('qc-advanced-panel');\n      if (p && p.classList.contains('is-open')) closeAdvanced(true);\n    });\n    // iOS Safari BFCache: if the user navigates away with the panel open and\n    // then returns, the page is restored with body still in position:fixed but\n    // _scrollLockY reset to 0. Unconditionally unlock on BFCache restore so the\n    // user isn't stranded with a frozen body. Also remove qc-advanced-open so\n    // pdp-sticky-bar's freeze guard doesn't persist across BFCache restores,\n    // and restore the sticky bar's aria-hidden (openAdvanced sets it 'true';\n    // without this, a BFCache restore with the drawer open would leave Buy Now\n    // hidden from VoiceOver/TalkBack for the rest of the page session).\n    window.addEventListener('pageshow', function (e) {\n      if (e.persisted) {\n        unlockBodyScroll();\n        // Unconditional release is intentional and safe \u2014 release() on an\n        // ownerId never acquired (e.g. the sheet, not this panel, held the\n        // lock when the page was frozen for BFCache) is a documented no-op.\n        if (window.__mdBodyScrollLock) {\n          window.__mdBodyScrollLock.release('quick-config-advanced-panel');\n        } else {\n          document.body.classList.remove('qc-advanced-open');\n        }\n        var sb = document.querySelector('.pdp-sticky-bar');\n        if (sb)\n          sb.setAttribute(\n            'aria-hidden',\n            sb.classList.contains('pdp-sticky-bar--active') ? 'false' : 'true'\n          );\n      }\n    });\n    // Recompute panel clearance on resize/orientation change \u2014 the sticky bar\n    // height may change (e.g. orientation flip narrows the viewport, causing the\n    // bar to reflow taller). Early-return when the panel is not open to avoid\n    // unnecessary DOM reads during page-wide resize events.\n    window.addEventListener(\n      'resize',\n      function () {\n        var p = document.getElementById('qc-advanced-panel');\n        if (!p || !p.classList.contains('is-open')) return;\n        updateStickyClearance();\n      },\n      { passive: true }\n    );\n\n    // \u2500\u2500 Circular attribution: APO \u2194 QC \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n    // Forward (QC \u2192 APO): wireColorTiles/wireSwingOptions call applyColorSelection\n    // which mutates APO state and paints --selected on matching APO value divs.\n    //\n    // Reverse (APO \u2192 QC): APO's own click handlers work natively inside the\n    // Advanced panel \u2014 clicking a Wood Type or Finish swatch fires APO's full\n    // event cascade (state + unhide + --selected). It also fires\n    // mwApo::applyAttributeStateToHtml at the end, which we listen for here\n    // and use to re-sync our QC tile + width + swing display.\n    var _syncPending = false;\n    document.addEventListener('mwApo::applyAttributeStateToHtml', function () {\n      if (_syncPending) return;\n      _syncPending = true;\n      requestAnimationFrame(function () {\n        syncQcFromApo();\n        _syncPending = false;\n      });\n    });\n  }\n\n  // APO's own click handlers inside the Advanced panel work natively (verified\n  // by clicking .mw-option__swatch-media triggers the full cascade). We no longer\n  // intercept clicks \u2014 instead we listen for mwApo::applyAttributeStateToHtml\n  // (fired by APO after any state change) and re-sync the QC tile/swing display.\n\n  // \u2500\u2500\u2500 APO detection \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n  // Max-retry guard prevents runaway recursion if mwApoInit never populates\n  // (e.g. APO script broke or product has no APO config). At 200ms \u00D7 50 = 10s\n  // we give up \u2014 the user sees no QC UI and APO's native form remains visible.\n  var APO_READY_MAX_RETRIES = 50;\n  var _apoReadyRetries = 0;\n\n  function onApoReady(apoContainer) {\n    var apoInit = window.mwApoInit;\n    var respKey = getApoRespKey();\n    if (!apoInit || !respKey || !apoInit.response[respKey]) {\n      if (_apoReadyRetries >= APO_READY_MAX_RETRIES) return;\n      _apoReadyRetries++;\n      setTimeout(function () {\n        onApoReady(apoContainer);\n      }, 200);\n      return;\n    }\n    var apoProductId = apoInit.product && apoInit.product.id;\n    if (String(apoProductId) !== String(PRODUCT_ID)) return;\n    initQuickConfig(apoContainer);\n  }\n\n  function waitForApo() {\n    var existing = document.querySelector('.mw-apo-container');\n    if (existing) {\n      onApoReady(existing);\n      return;\n    }\n    var observer = new MutationObserver(function (_, obs) {\n      var c = document.querySelector('.mw-apo-container');\n      if (c) {\n        obs.disconnect();\n        onApoReady(c);\n      }\n    });\n    observer.observe(document.body, { childList: true, subtree: true });\n    setTimeout(function () {\n      observer.disconnect();\n    }, 15000);\n  }\n\n  // \u2500\u2500\u2500 Extract APO's ATC button back to the product form \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n  // APO injects its own validated ATC button (.mw-apo-add-to-cart-custom)\n  // adjacent to the .mw-apo-container. When we move the container into the\n  // Advanced panel, APO's button travels with it (or lands in the panel body).\n  // This function pulls it back to .product-form__buttons so it stays visible.\n\n  // rehomeApoAtcBtn is defined above with syncApoUi \u2014 this is its alias for init use.\n  // (avoids duplicate function body)\n\n  // \u2500\u2500\u2500 Init \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n  function initQuickConfig(apoContainer) {\n    // Double-init guard \u2014 protects against APO re-injecting .mw-apo-container\n    // (rare, but bulletproof). Without this guard a second pass would clone\n    // every UI element + listener into the DOM.\n    if (document.getElementById('qc-container')) return;\n    var ui = buildQcUi();\n\n    // Inject Quick Config UI before where APO was\n    var parent = apoContainer.parentNode;\n    parent.insertBefore(ui.qcContainer, apoContainer);\n\n    // Append the Advanced panel and scrim to <body> \u2014 NOT inside the product form.\n    // Shopify's scroll-trigger animation classes apply CSS transforms to product\n    // section wrappers, which breaks position:fixed on any descendant. Appending\n    // to body ensures the panel stacks correctly at the viewport level.\n    document.body.appendChild(ui.advPanel);\n    document.body.appendChild(ui.scrim);\n    document.body.appendChild(ui.srStatus);\n\n    // Move APO form inside the Advanced panel body\n    ui.panelBody.appendChild(apoContainer);\n    apoContainer.removeAttribute('data-qc-hidden');\n    apoContainer.style.display = '';\n\n    // APO's ATC button may have moved with the container or be adjacent to it.\n    // Wait briefly for APO to finish any button injection, then rehome it.\n    setTimeout(rehomeApoAtcBtn, 300);\n\n    // Wire all interactions\n    wireColorTiles(ui.qcContainer);\n    wireWidthSelect(ui.qcContainer);\n    wireSwingOptions(ui.qcContainer);\n    wireAdvancedPanel(ui.qcContainer);\n    wireAtcValidation();\n    // Reflect the initial depth (default 8\u00BC\u2033 allows both directions) and the\n    // initial width+height label before the customer touches anything.\n    updateSwingTileAvailability();\n    syncWidthLabelWithHeight();\n\n    // No auto-defaults: the customer should see the marketing carousel image\n    // on first load. Their first QC click will trigger APO's gallery cascade\n    // (because clicking the wood swatch swaps the gallery to that material's photo).\n    // ATC will show APO's \"Wood Type is required\" prompt until the customer\n    // makes a Step 1 selection \u2014 APO's natural required-field validation.\n  }\n\n  if (document.readyState === 'loading') {\n    document.addEventListener('DOMContentLoaded', waitForApo);\n  } else {\n    waitForApo();\n  }\n})();\n"],
  "mappings": "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",
  "names": []
}
