{
  "version": 3,
  "sources": ["/cdn/shop/t/36/assets/ct-bespoke-mobile.js?ctv=20260715081934"],
  "sourcesContent": ["/* ChinaTourly \u00B7 mobile bespoke wizard (iframe-isolated). Built by \u738B\u8D1D\u5C14. */\n(function(){\n  var CTM_HTML = \"\\u003c!DOCTYPE html>\\n\\u003chtml lang=\\\"en\\\">\\n\\u003chead>\\n\\u003cmeta charset=\\\"utf-8\\\">\\n\\u003cmeta name=\\\"viewport\\\" content=\\\"width=device-width, initial-scale=1\\\">\\n\\u003ctitle>Bespoke Builder \u00B7 Mobile (demo)\\u003c/title>\\n\\u003clink rel=\\\"preconnect\\\" href=\\\"https://fonts.googleapis.com\\\">\\n\\u003clink rel=\\\"preconnect\\\" href=\\\"https://fonts.gstatic.com\\\" crossorigin>\\n\\u003clink href=\\\"https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,400;0,500;0,600;1,400;1,500&family=Inter:wght@400;500;600;700&display=swap\\\" rel=\\\"stylesheet\\\">\\n\\u003cstyle>\\n*{margin:0;padding:0;box-sizing:border-box;-webkit-tap-highlight-color:transparent}\\n:root{\\n  --ivory:#FAF5EC; --ivory-2:#FFFDFA; --ivory-3:#F5EDDF;\\n  --bronze:#C9A84C; --bronze-dark:#8B6F47; --bronze-light:#E8C97A;\\n  --ink:#1f1811; --ink-2:#3a342c; --mute:#7A6B54; --rule:rgba(122,107,84,.16);\\n  --gold-bg:rgba(201,168,76,.10); --green:#4a7c4e; --red:#b0413e;\\n  --glass:rgba(255,253,250,.72); --glass-strong:rgba(255,253,250,.86);\\n  --serif:'Cormorant Garamond',Georgia,serif; --sans:'Inter',system-ui,sans-serif;\\n  --paper-shadow:0 18px 40px rgba(31,24,17,.10);\\n}\\nbody{font-family:var(--sans);background:#e9e2d4;color:var(--ink);min-height:100vh;\\n  display:flex;flex-direction:column;align-items:center;padding:30px 10px 60px;\\n  background-image:radial-gradient(1200px 500px at 50% -10%,rgba(201,168,76,.18),transparent 70%);}\\n.demo-cap{text-align:center;margin-bottom:18px;color:var(--ink-2);max-width:420px}\\n.demo-cap b{font-family:var(--serif);font-size:22px;font-weight:600;color:var(--ink);display:block;letter-spacing:-.01em}\\n.demo-cap span{font-size:12px;color:var(--mute);letter-spacing:.02em}\\n\\n/* ===== PHONE FRAME ===== */\\n.phone{position:relative;width:390px;max-width:100%;height:830px;border-radius:46px;\\n  background:#15110b;padding:13px;box-shadow:0 40px 90px rgba(31,24,17,.42),0 0 0 2px rgba(201,168,76,.18);}\\n.phone__screen{position:relative;width:100%;height:100%;border-radius:34px;overflow:hidden;background:var(--ivory);}\\n.phone__notch{position:absolute;top:0;left:50%;transform:translateX(-50%);width:128px;height:26px;background:#15110b;border-radius:0 0 16px 16px;z-index:60}\\n.scroll{position:absolute;inset:0;overflow-y:auto;overflow-x:hidden;-webkit-overflow-scrolling:touch;scroll-behavior:smooth}\\n.scroll::-webkit-scrollbar{width:0}\\n\\n/* ===== HERO ===== */\\n.hero{position:relative;padding:46px 26px 30px;text-align:center;\\n  background:linear-gradient(178deg,var(--ivory) 0%,var(--ivory-3) 100%);border-bottom:1px solid var(--rule)}\\n.hero__tag{display:inline-flex;align-items:center;gap:10px;font-size:9.5px;letter-spacing:.34em;\\n  text-transform:uppercase;color:var(--bronze-dark);font-weight:700;margin-bottom:16px}\\n.hero__tag::before,.hero__tag::after{content:'';width:16px;height:1px;background:var(--bronze)}\\n.hero__title{font-family:var(--serif);font-size:42px;line-height:1.02;font-weight:500;letter-spacing:-.02em;color:var(--ink)}\\n.hero__title em{font-style:italic;color:var(--bronze-dark)}\\n.hero__sub{font-size:13.5px;line-height:1.6;color:var(--ink-2);max-width:300px;margin:16px auto 0}\\n.hero__rule{display:block;width:54px;height:1px;margin:20px auto 0;\\n  background:linear-gradient(90deg,transparent,var(--bronze),transparent)}\\n\\n/* ===== STICKY RAIL (glass) ===== */\\n.rail{position:sticky;top:0;z-index:40;padding:11px 18px 12px;\\n  background:var(--glass);backdrop-filter:blur(20px) saturate(1.5);-webkit-backdrop-filter:blur(20px) saturate(1.5);\\n  border-bottom:1px solid rgba(201,168,76,.20);box-shadow:0 6px 20px rgba(31,24,17,.06)}\\n.rail__top{display:flex;align-items:baseline;justify-content:space-between;margin-bottom:9px}\\n.rail__step{font-size:10px;letter-spacing:.2em;text-transform:uppercase;color:var(--bronze-dark);font-weight:700}\\n.rail__label{font-family:var(--serif);font-size:16px;font-weight:600;color:var(--ink);font-style:italic}\\n.rail__dots{position:relative;display:flex;justify-content:space-between;align-items:center}\\n.rail__dots::before{content:'';position:absolute;left:8px;right:8px;top:50%;height:2px;background:var(--rule);transform:translateY(-50%);border-radius:2px}\\n.rail__dots::after{content:'';position:absolute;left:8px;top:50%;height:2px;width:var(--progress,0%);max-width:calc(100% - 16px);\\n  background:linear-gradient(90deg,var(--bronze-light),var(--bronze));transform:translateY(-50%);border-radius:2px;transition:width .45s cubic-bezier(.4,0,.2,1)}\\n.dot{position:relative;z-index:2;width:16px;height:16px;border-radius:50%;background:var(--ivory-2);border:1.5px solid var(--rule);\\n  display:flex;align-items:center;justify-content:center;font-size:8px;font-weight:700;color:var(--mute);transition:all .3s}\\n.dot.is-active{background:var(--ink);border-color:var(--ink);color:var(--ivory-2);transform:scale(1.18);box-shadow:0 4px 10px rgba(31,24,17,.3)}\\n.dot.is-done{background:var(--bronze);border-color:var(--bronze);color:var(--ink)}\\n\\n/* ===== STEP COMMON ===== */\\n.main{padding:24px 20px 0}\\n.step-pop{animation:pop .5s cubic-bezier(.2,.7,.3,1)}\\n@keyframes pop{from{opacity:0;transform:translateY(14px)}to{opacity:1;transform:none}}\\n.eyebrow{font-size:10px;letter-spacing:.24em;text-transform:uppercase;color:var(--bronze-dark);font-weight:700}\\n.title{font-family:var(--serif);font-size:34px;line-height:1.04;font-weight:500;letter-spacing:-.02em;color:var(--ink);margin:9px 0 10px}\\n.title em{font-style:italic;color:var(--bronze-dark)}\\n.lede{font-size:13.5px;line-height:1.55;color:var(--ink-2);margin-bottom:6px}\\n.lede strong{color:var(--bronze-dark);font-weight:600}\\n.rule{display:block;width:46px;height:1px;background:var(--bronze);margin:16px 0 22px}\\n.sec-label{font-size:10px;letter-spacing:.2em;text-transform:uppercase;color:var(--bronze-dark);font-weight:700;display:block;margin:6px 0 12px}\\n\\n/* ===== CHOICE CARDS ===== */\\n.mcards{display:flex;flex-direction:column;gap:13px}\\n.mcard{position:relative;display:block;width:100%;text-align:left;border:0;cursor:pointer;\\n  min-height:132px;border-radius:20px;overflow:hidden;padding:0;font-family:inherit;\\n  background-image:linear-gradient(120deg,#3a342c,#1f1811);box-shadow:var(--paper-shadow);\\n  transition:transform .3s,box-shadow .3s}\\n.mcard::before{content:'';position:absolute;inset:0;background-image:var(--img);background-size:cover;background-position:center;opacity:.92;transition:transform .5s}\\n.mcard::after{content:'';position:absolute;inset:0;background:linear-gradient(180deg,rgba(20,15,9,.06) 0%,rgba(20,15,9,.40) 48%,rgba(20,15,9,.86) 100%)}\\n.mcard:active{transform:scale(.985)}\\n.mcard__num{position:absolute;top:13px;left:15px;z-index:3;font-family:var(--serif);font-size:13px;font-weight:600;\\n  color:var(--ivory-2);opacity:.85;letter-spacing:.05em}\\n.mcard__body{position:relative;z-index:3;display:flex;flex-direction:column;height:100%;justify-content:flex-end;padding:16px 17px 15px;min-height:132px}\\n.mcard__title{font-family:var(--serif);font-size:25px;line-height:1.05;font-weight:600;color:#fff;letter-spacing:-.01em}\\n.mcard__sub{font-size:12px;line-height:1.45;color:rgba(255,253,250,.82);margin-top:5px}\\n.mcard__meta{display:inline-block;font-size:9.5px;letter-spacing:.14em;text-transform:uppercase;color:var(--bronze-light);font-weight:700;margin-top:9px}\\n.mcard.is-sel{box-shadow:0 0 0 2.5px var(--bronze),0 18px 38px rgba(201,168,76,.34)}\\n.mcard.is-sel::before{transform:scale(1.04)}\\n.mcard__check{position:absolute;top:12px;right:13px;z-index:4;width:30px;height:30px;border-radius:50%;\\n  background:var(--bronze);color:var(--ink);display:none;align-items:center;justify-content:center;font-size:15px;font-weight:800;\\n  border:2px solid var(--ivory-2);box-shadow:0 4px 12px rgba(0,0,0,.35)}\\n.mcard.is-sel .mcard__check{display:flex}\\n\\n/* ===== DAYS SLIDER ===== */\\n.days-card{background:var(--ivory-2);border:1px solid var(--rule);border-radius:24px;padding:30px 24px;box-shadow:var(--paper-shadow)}\\n.days-num{font-family:var(--serif);font-size:78px;line-height:.9;font-weight:500;color:var(--ink);text-align:center;letter-spacing:-.03em}\\n.days-cap{text-align:center;font-size:10px;letter-spacing:.24em;text-transform:uppercase;color:var(--mute);font-weight:700;margin-top:6px}\\n.days-hint{text-align:center;font-family:var(--serif);font-size:17px;font-style:italic;color:var(--bronze-dark);margin:10px 0 22px;min-height:24px}\\n.range{width:100%;height:8px;-webkit-appearance:none;appearance:none;border-radius:999px;\\n  background:linear-gradient(to right,var(--bronze) 0%,var(--bronze) var(--p,30%),var(--rule) var(--p,30%),var(--rule) 100%)}\\n.range::-webkit-slider-thumb{-webkit-appearance:none;width:30px;height:30px;border-radius:50%;background:var(--ink);border:4px solid var(--ivory-2);cursor:pointer;box-shadow:0 6px 16px rgba(31,24,17,.30)}\\n.range::-moz-range-thumb{width:30px;height:30px;border-radius:50%;background:var(--ink);border:4px solid var(--ivory-2);cursor:pointer;box-shadow:0 6px 16px rgba(31,24,17,.30)}\\n.range-legend{display:flex;justify-content:space-between;font-size:9.5px;letter-spacing:.2em;text-transform:uppercase;color:var(--mute);font-weight:700;margin-top:12px}\\n\\n/* ===== TRAVELLERS ===== */\\n.tr-count{background:var(--ivory-2);border:1px solid var(--rule);border-radius:20px;padding:20px 22px;display:flex;align-items:center;justify-content:space-between;box-shadow:var(--paper-shadow);margin-bottom:18px}\\n.tr-count__label{font-size:10px;letter-spacing:.2em;text-transform:uppercase;color:var(--bronze-dark);font-weight:700;margin-bottom:4px}\\n.tr-count__val{font-family:var(--serif);font-size:52px;line-height:.9;font-weight:500;color:var(--ink)}\\n.tr-count__meta{font-size:11px;color:var(--mute);margin-top:6px}\\n.tr-count__meta b{color:var(--ink)} .tr-count__meta i{color:var(--green);font-style:normal}\\n.tr-count__ctrl{display:inline-flex;background:var(--ivory);border:1px solid var(--rule);border-radius:999px;overflow:hidden}\\n.tr-count__btn{width:46px;height:46px;border:0;background:transparent;font-size:24px;color:var(--ink);font-family:var(--serif);cursor:pointer}\\n.tr-count__btn:active{background:var(--gold-bg)}\\n.tr-row{background:var(--ivory-2);border:1px solid var(--rule);border-radius:16px;padding:17px 18px;margin-bottom:11px;position:relative;transition:all .3s}\\n.tr-row.is-free{border-color:rgba(201,168,76,.4);background:linear-gradient(135deg,var(--gold-bg),var(--ivory-2))}\\n.tr-row__rm{position:absolute;top:12px;right:14px;width:26px;height:26px;border-radius:50%;border:1px solid var(--rule);background:var(--ivory);color:var(--mute);font-size:15px;cursor:pointer;line-height:1}\\n.tr-row__head{display:flex;align-items:center;gap:12px;margin-bottom:13px;padding-right:30px}\\n.tr-row__num{font-family:var(--serif);font-size:21px;font-weight:600;color:var(--ink)}\\n.tr-row__cat{font-size:9.5px;letter-spacing:.16em;text-transform:uppercase;color:var(--bronze-dark);font-weight:700;margin-top:1px}\\n.tr-row__free{margin-left:auto;font-size:9px;letter-spacing:.1em;text-transform:uppercase;font-weight:700;color:var(--green);background:rgba(74,124,78,.12);padding:4px 9px;border-radius:999px}\\n.tr-pills{display:flex;flex-wrap:wrap;gap:7px;margin-bottom:13px}\\n.pill-sm{display:inline-flex;align-items:center;gap:5px;padding:6px 12px;border-radius:999px;border:1px solid var(--rule);background:var(--ivory);cursor:pointer;font-size:11.5px;color:var(--ink-2);font-weight:500;transition:all .2s;user-select:none}\\n.pill-sm:active{transform:scale(.96)}\\n.pill-sm.is-on{background:var(--ink);color:var(--ivory-2);border-color:var(--ink)}\\n.tr-age{display:flex;align-items:center;gap:12px}\\n.tr-age__label{font-size:10px;letter-spacing:.16em;text-transform:uppercase;color:var(--mute);font-weight:700}\\n.tr-age__input{width:62px;padding:8px 10px;border:1px solid var(--rule);border-radius:9px;font-size:15px;font-weight:600;color:var(--ink);text-align:center;background:var(--ivory);font-family:inherit}\\n.tr-age__input:focus{outline:none;border-color:var(--bronze);background:#fff}\\n.tr-age__slider{flex:1;height:6px}\\n.tr-notes{margin-top:8px;padding:9px 0 0}\\n.tr-notes textarea{width:100%;min-height:74px;padding:12px 13px;border:1px solid var(--rule);border-radius:12px;background:var(--ivory);color:var(--ink);font-family:inherit;font-size:13px;line-height:1.5;resize:vertical}\\n.tr-notes textarea:focus{outline:none;border-color:var(--bronze);background:#fff}\\n\\n/* ===== CITIES ===== */\\n.rec-banner{display:flex;gap:12px;align-items:flex-start;background:var(--gold-bg);border:1px solid rgba(201,168,76,.4);border-radius:16px;padding:15px 16px;margin-bottom:18px}\\n.rec-banner__ic{font-size:24px;line-height:1;flex:none}\\n.rec-banner__k{font-size:9.5px;letter-spacing:.2em;text-transform:uppercase;color:var(--bronze-dark);font-weight:700}\\n.rec-banner__t{font-family:var(--serif);font-size:19px;font-weight:600;color:var(--ink);margin:2px 0 3px}\\n.rec-banner__t em{font-style:italic;color:var(--bronze-dark)}\\n.rec-banner__d{font-size:12px;line-height:1.45;color:var(--ink-2)}\\n.rec-add{color:var(--bronze-dark);font-weight:600} .rec-over{color:var(--red);font-weight:600} .rec-ok{color:var(--green);font-weight:600}\\n.scenes{display:flex;flex-direction:column;gap:14px}\\n.scene{position:relative;border-radius:20px;overflow:hidden;min-height:230px;box-shadow:var(--paper-shadow);background:linear-gradient(120deg,#3a342c,#1f1811)}\\n.scene::before{content:'';position:absolute;inset:0;background-image:var(--img);background-size:cover;background-position:center;transition:transform .5s}\\n.scene::after{content:'';position:absolute;inset:0;background:linear-gradient(180deg,rgba(20,15,9,.10) 0%,rgba(20,15,9,.40) 42%,rgba(20,15,9,.90) 100%)}\\n.scene.is-added::before{transform:scale(1.05)}\\n.scene.is-added{box-shadow:0 0 0 2.5px var(--bronze),0 18px 38px rgba(201,168,76,.30)}\\n.scene__check{position:absolute;top:14px;right:14px;z-index:4;width:34px;height:34px;border-radius:50%;background:var(--ink);color:var(--ivory-2);display:none;align-items:center;justify-content:center;font-size:16px;font-weight:800;border:2px solid var(--ivory-2)}\\n.scene.is-added .scene__check{display:flex}\\n.scene__c{position:relative;z-index:3;display:flex;flex-direction:column;height:100%;justify-content:flex-end;padding:18px 18px 17px;min-height:230px}\\n.scene__name{font-family:var(--serif);font-size:30px;font-weight:600;color:#fff;letter-spacing:-.01em}\\n.scene__intro{font-size:12px;line-height:1.5;color:rgba(255,253,250,.85);margin:7px 0 8px}\\n.scene__must{font-size:11.5px;line-height:1.5;color:rgba(255,253,250,.78)}\\n.scene__must b{color:var(--bronze-light);font-weight:600}\\n.scene__rec{display:inline-block;font-size:9.5px;letter-spacing:.14em;text-transform:uppercase;color:var(--bronze-light);font-weight:700;margin:10px 0 12px}\\n.scene__add{display:block;width:100%;padding:12px;border-radius:999px;border:0;cursor:pointer;font-family:inherit;\\n  font-size:10.5px;letter-spacing:.16em;text-transform:uppercase;font-weight:700;\\n  background:rgba(255,253,250,.94);color:var(--ink);transition:all .25s}\\n.scene.is-added .scene__add{background:var(--bronze);color:var(--ink)}\\n.scene__add:active{transform:scale(.97)}\\n.seq{display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin-top:18px;padding:14px 15px;background:var(--ivory-2);border:1px solid var(--rule);border-radius:14px}\\n.seq__label{font-size:9.5px;letter-spacing:.2em;text-transform:uppercase;color:var(--bronze-dark);font-weight:700;width:100%;margin-bottom:2px}\\n.chip-gold{display:inline-flex;align-items:center;gap:6px;padding:6px 13px;border-radius:999px;background:var(--gold-bg);border:1px solid rgba(201,168,76,.4);font-size:12px;font-weight:600;color:var(--ink)}\\n.chip-gold b{font-family:var(--serif);color:var(--bronze-dark);font-size:14px}\\n.empty-note{font-family:var(--serif);font-style:italic;font-size:15px;color:var(--mute);margin-top:16px}\\n\\n/* ===== ITINERARY ===== */\\n.defaults{background:var(--ivory-2);border:1px solid var(--rule);border-radius:18px;padding:18px;margin-bottom:18px;box-shadow:var(--paper-shadow)}\\n.def-group{margin-bottom:16px} .def-group:last-child{margin-bottom:0}\\n.def-k{font-size:9.5px;letter-spacing:.18em;text-transform:uppercase;color:var(--mute);font-weight:700;margin-bottom:9px}\\n.opt{position:relative;display:flex;align-items:center;gap:12px;padding:13px 15px;background:var(--ivory);border:1px solid var(--rule);border-radius:13px;cursor:pointer;margin-bottom:8px;transition:all .25s}\\n.opt:last-child{margin-bottom:0}\\n.opt.is-on{border-color:var(--bronze);background:var(--gold-bg);box-shadow:0 5px 14px rgba(201,168,76,.2)}\\n.opt__body{flex:1;min-width:0}\\n.opt__title{font-family:var(--serif);font-size:17px;font-weight:600;color:var(--ink);line-height:1.2}\\n.opt__sub{font-size:11px;line-height:1.4;color:var(--mute);margin-top:2px}\\n.opt__price{margin-left:auto;font-family:var(--serif);font-size:17px;font-weight:600;color:var(--bronze-dark);white-space:nowrap}\\n.opt__price small{font-size:9px;color:var(--mute)}\\n.opt__free{margin-left:auto;font-size:10px;font-style:italic;color:var(--mute)}\\n.opt__burst{position:absolute;top:-8px;right:-6px;background:var(--bronze);color:var(--ink);border-radius:8px;padding:3px 7px;text-align:center;box-shadow:0 4px 10px rgba(201,168,76,.4);transform:rotate(4deg)}\\n.opt__burst b{display:block;font-size:9px;font-weight:800;letter-spacing:.08em;line-height:1}\\n.opt__burst s{display:block;font-size:8px;opacity:.7;line-height:1.2}\\n.opt__tier{display:inline-block;font-size:8px;letter-spacing:.1em;font-weight:800;padding:2px 7px;border-radius:5px;margin-left:7px;vertical-align:middle}\\n.opt__tier--private{background:rgba(122,107,84,.14);color:var(--bronze-dark)}\\n.opt__tier--vip{background:rgba(201,168,76,.2);color:var(--bronze-dark);border:1px solid rgba(201,168,76,.4)}\\n.opt__tier--ultra{background:var(--ink);color:var(--bronze-light)}\\n.iti-day{position:relative;display:flex;gap:0;background:var(--ivory-2);border:1px solid var(--rule);border-radius:16px;overflow:hidden;margin-bottom:11px;cursor:pointer;transition:all .25s}\\n.iti-day:active{transform:scale(.99)}\\n.iti-day.is-cust{border-color:var(--bronze)}\\n.iti-day__img{width:84px;flex:none;background-size:cover;background-position:center;background-image:linear-gradient(120deg,#3a342c,#1f1811)}\\n.iti-day__b{flex:1;min-width:0;padding:15px 15px}\\n.iti-day__top{display:flex;justify-content:space-between;align-items:flex-start;gap:10px}\\n.iti-day__k{font-size:9.5px;letter-spacing:.16em;text-transform:uppercase;color:var(--bronze-dark);font-weight:700}\\n.iti-day__acts{font-size:12.5px;line-height:1.4;color:var(--ink);font-weight:500;margin-top:4px}\\n.iti-day__acts i{font-style:italic;color:var(--mute);font-weight:400}\\n.iti-day__price{font-family:var(--serif);font-size:21px;font-weight:600;color:var(--ink);line-height:1;text-align:right}\\n.iti-day__pp{font-size:8.5px;letter-spacing:.1em;text-transform:uppercase;color:var(--bronze-dark);font-weight:700;margin-top:4px;text-align:right;white-space:nowrap}\\n\\n/* ===== BOTTOM BAR (glass) ===== */\\n.botbar{position:absolute;left:0;right:0;bottom:0;z-index:50;padding:12px 16px calc(14px + env(safe-area-inset-bottom));\\n  background:var(--glass-strong);backdrop-filter:blur(24px) saturate(1.6);-webkit-backdrop-filter:blur(24px) saturate(1.6);\\n  border-top:1px solid rgba(201,168,76,.28);box-shadow:0 -10px 30px rgba(31,24,17,.10)}\\n.botbar__price-row{display:flex;align-items:flex-end;justify-content:space-between;margin-bottom:11px;cursor:pointer}\\n.botbar__pk{font-size:9px;letter-spacing:.18em;text-transform:uppercase;color:var(--bronze-dark);font-weight:700}\\n.botbar__pv{font-family:var(--serif);font-size:30px;font-weight:600;color:var(--ink);line-height:1;letter-spacing:-.02em}\\n.botbar__pb{font-size:10.5px;color:var(--mute);margin-top:3px}\\n.botbar__brief{font-size:10px;letter-spacing:.1em;text-transform:uppercase;color:var(--bronze-dark);font-weight:700;display:flex;align-items:center;gap:5px;white-space:nowrap}\\n.botbar__score{display:block;font-family:var(--serif);font-size:15px;font-style:italic;color:var(--ink);text-align:right;margin-bottom:2px}\\n.botbar__nav{display:flex;gap:10px;align-items:center}\\n.pill{display:inline-flex;align-items:center;justify-content:center;gap:8px;padding:14px 22px;border-radius:999px;\\n  font-size:11px;letter-spacing:.16em;text-transform:uppercase;font-weight:700;border:0;cursor:pointer;font-family:inherit;transition:all .3s}\\n.pill-main{flex:1;background:var(--ink);color:var(--ivory-2)}\\n.pill-main:active{transform:scale(.98)}\\n.pill-main:disabled{opacity:.4;cursor:not-allowed}\\n.pill-ghost{background:var(--ivory-2);color:var(--ink);border:1.5px solid var(--rule)}\\n.pill-ghost:disabled{opacity:.35}\\n.nav-hint{font-size:10px;letter-spacing:.1em;text-transform:uppercase;color:var(--red);font-weight:700;text-align:center;margin-bottom:8px;min-height:13px;transition:opacity .25s}\\n\\n/* ===== SHEETS ===== */\\n.sheet-back{position:absolute;inset:0;z-index:70;background:rgba(20,15,9,.5);backdrop-filter:blur(3px);\\n  opacity:0;pointer-events:none;transition:opacity .3s}\\n.sheet-back.is-open{opacity:1;pointer-events:auto}\\n.sheet{position:absolute;left:0;right:0;bottom:0;z-index:80;max-height:90%;display:flex;flex-direction:column;\\n  background:var(--ivory);border-radius:26px 26px 0 0;transform:translateY(102%);transition:transform .42s cubic-bezier(.2,.7,.3,1);\\n  box-shadow:0 -20px 60px rgba(31,24,17,.4);border-top:1px solid rgba(201,168,76,.3)}\\n.sheet.is-open{transform:translateY(0)}\\n.sheet--brief{max-height:74%}\\n.sheet__grip{width:42px;height:4px;border-radius:4px;background:var(--rule);margin:11px auto 4px;flex:none}\\n.sheet__head{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;padding:8px 22px 6px;flex:none}\\n.sheet__x{width:34px;height:34px;border-radius:50%;border:1px solid var(--rule);background:var(--ivory-2);color:var(--mute);font-size:20px;cursor:pointer;line-height:1;flex:none}\\n.sheet__body{overflow-y:auto;padding:6px 22px 26px;-webkit-overflow-scrolling:touch}\\n.sheet__body::-webkit-scrollbar{width:0}\\n.brief-row{display:flex;justify-content:space-between;gap:12px;padding:12px 0;border-bottom:1px solid var(--rule)}\\n.brief-row__k{font-size:9.5px;letter-spacing:.16em;text-transform:uppercase;color:var(--mute);font-weight:700}\\n.brief-row__v{font-size:13.5px;color:var(--ink);font-weight:500;text-align:right}\\n.brief-score{display:flex;align-items:center;justify-content:space-between;margin:4px 0 14px}\\n.brief-score__t{font-family:var(--serif);font-size:24px;font-weight:600;color:var(--ink)}\\n.brief-score__n{font-size:12px;font-weight:700;color:var(--bronze-dark)}\\n\\n/* day sheet schedule */\\n.sched-row{display:flex;gap:11px;padding:13px 14px;background:var(--ivory-2);border:1px solid var(--rule);border-radius:13px;margin-bottom:8px;transition:all .25s}\\n.sched-row.is-mod{border-color:var(--bronze);background:linear-gradient(135deg,var(--gold-bg),var(--ivory-2))}\\n.sched-row.is-skip{opacity:.5}\\n.sched-time{flex:none;width:68px}\\n.sched-time input{font-family:var(--serif);font-size:17px;font-weight:600;color:var(--ink);background:transparent;border:0;border-bottom:1px dashed var(--rule);width:60px;padding:1px 0;outline:none}\\n.sched-time input::-webkit-calendar-picker-indicator{display:none;-webkit-appearance:none;opacity:0;width:0;margin:0}\\n.sched-time input::-webkit-date-and-time-value{text-align:left}\\n.sched-time input:focus{border-bottom-color:var(--bronze);color:var(--bronze-dark)}\\n.sched-dur{display:block;font-size:9px;color:var(--mute);margin-top:3px;letter-spacing:.04em}\\n.sched-b{flex:1;min-width:0}\\n.sched-title{font-family:var(--serif);font-size:15px;font-weight:600;color:var(--ink);line-height:1.3}\\n.sched-loc{font-size:11px;color:var(--mute);margin-top:3px}\\n.sched-warn{font-size:10.5px;line-height:1.4;color:var(--bronze-dark);background:var(--gold-bg);border-radius:8px;padding:6px 8px;margin-top:7px}\\n.sched-acts{display:flex;flex-direction:column;gap:6px;flex:none}\\n.sched-btn{font-size:9px;letter-spacing:.08em;text-transform:uppercase;font-weight:700;padding:6px 9px;border:1px solid var(--rule);background:var(--ivory);color:var(--mute);border-radius:999px;cursor:pointer;white-space:nowrap}\\n.sched-btn.is-active{border-color:var(--bronze);color:var(--bronze-dark);background:var(--gold-bg)}\\n.sched-alts{margin-top:9px;padding:10px;background:var(--ivory);border:1px dashed var(--rule);border-radius:10px}\\n.sched-alts__l{font-size:9px;letter-spacing:.14em;text-transform:uppercase;color:var(--bronze-dark);font-weight:700;margin-bottom:7px}\\n.alt-chip{display:inline-block;font-size:11.5px;padding:6px 11px;margin:0 4px 5px 0;background:var(--ivory-2);border:1px solid var(--rule);border-radius:999px;color:var(--ink);cursor:pointer;font-family:var(--serif);font-weight:500}\\n.alt-chip.is-picked{background:var(--bronze);color:var(--ink);border-color:var(--bronze)}\\n.incl{background:linear-gradient(135deg,var(--gold-bg),var(--ivory-2));border:1px solid rgba(201,168,76,.3);border-radius:14px;padding:15px 16px;margin:8px 0 18px}\\n.incl__h{display:flex;gap:10px;align-items:flex-start;margin-bottom:11px}\\n.incl__ck{width:26px;height:26px;border-radius:50%;background:var(--bronze);color:var(--ink);display:flex;align-items:center;justify-content:center;font-weight:800;font-size:14px;flex:none}\\n.incl__t{font-family:var(--serif);font-size:15px;font-weight:600;color:var(--ink)}\\n.incl__s{font-size:11px;color:var(--mute);margin-top:2px}\\n.incl__chip{display:inline-block;font-size:11px;padding:5px 10px;margin:0 5px 6px 0;background:var(--ivory-2);border:1px solid var(--rule);border-radius:8px;color:var(--ink-2)}\\n.addon-lede{font-size:11px;line-height:1.5;font-style:italic;color:var(--bronze-dark);margin:-2px 0 12px}\\n.sheet-foot{display:flex;gap:10px;padding:14px 22px calc(18px + env(safe-area-inset-bottom));border-top:1px solid var(--rule);background:var(--glass-strong);backdrop-filter:blur(20px);flex:none}\\n/* ===== IFRAME FULL-BLEED OVERRIDES (no phone frame; iframe IS the device) ===== */\\nhtml,body{height:100%}\\nbody{padding:0;background:var(--ivory);display:block;align-items:initial}\\n.demo-cap{display:none}\\n.phone{width:100%;max-width:none;height:100vh;height:100dvh;border-radius:0;padding:0;box-shadow:none;background:var(--ivory)}\\n.phone__screen{border-radius:0}\\n.phone__notch{display:none}\\n.backchip{position:absolute;top:14px;left:14px;z-index:30;display:inline-flex;align-items:center;gap:6px;\\n  padding:8px 14px 8px 11px;border-radius:999px;border:1px solid rgba(201,168,76,.3);\\n  background:var(--glass);backdrop-filter:blur(14px);-webkit-backdrop-filter:blur(14px);\\n  font-size:10px;letter-spacing:.14em;text-transform:uppercase;font-weight:700;color:var(--bronze-dark);\\n  text-decoration:none;cursor:pointer}\\n.backchip span{font-size:13px;line-height:1}\\n\\u003c/style>\\n\\u003c/head>\\n\\u003cbody>\\n\\u003cdiv class=\\\"demo-cap\\\">\\n  \\u003cb>Bespoke Builder \u00B7 Mobile\\u003c/b>\\n  \\u003cspan>\u540C PC 7 \u6B65\u903B\u8F91 \u00B7 \u5355\u5217\u54CD\u5E94\u5F0F \u00B7 \u73BB\u7483\u6DB2\u6001 \u00B7 demo \u4EC5\u4F9B\u5BA1\u65B9\u5411\\u003c/span>\\n\\u003c/div>\\n\\n\\u003cdiv class=\\\"phone\\\">\\n  \\u003cdiv class=\\\"phone__screen\\\">\\n    \\u003cdiv class=\\\"phone__notch\\\">\\u003c/div>\\n    \\u003cdiv class=\\\"scroll\\\" id=\\\"scroll\\\">\\n      \\u003cheader class=\\\"hero\\\">\\n        \\u003ca class=\\\"backchip\\\" onclick=\\\"window.top.location.href='/'\\\">\\u003cspan>&#8592;\\u003c/span> ChinaTourly\\u003c/a>\\n        \\u003cspan class=\\\"hero__tag\\\">Bespoke Builder \u00B7 Private Design\\u003c/span>\\n        \\u003ch1 class=\\\"hero__title\\\">Design \\u003cem>your own\\u003c/em>\\u003cbr>China journey\\u003c/h1>\\n        \\u003cp class=\\\"hero__sub\\\">Build your itinerary and planning estimate, then review your brief before sending an inquiry.\\u003c/p>\\n        \\u003cspan class=\\\"hero__rule\\\">\\u003c/span>\\n      \\u003c/header>\\n\\n      \\u003cdiv class=\\\"rail\\\" id=\\\"rail\\\">\\n        \\u003cdiv class=\\\"rail__top\\\">\\n          \\u003cspan class=\\\"rail__step\\\" id=\\\"railStep\\\">Step 1 of 7\\u003c/span>\\n          \\u003cspan class=\\\"rail__label\\\" id=\\\"railLabel\\\">Your party\\u003c/span>\\n        \\u003c/div>\\n        \\u003cdiv class=\\\"rail__dots\\\" id=\\\"railDots\\\">\\u003c/div>\\n      \\u003c/div>\\n\\n      \\u003cmain class=\\\"main\\\">\\u003cdiv id=\\\"stepArea\\\">\\u003c/div>\\u003c/main>\\n      \\u003cdiv style=\\\"height:172px\\\">\\u003c/div>\\n    \\u003c/div>\\n\\n    \\u003cdiv class=\\\"botbar\\\" id=\\\"botbar\\\">\\n      \\u003cdiv class=\\\"nav-hint\\\" id=\\\"navHint\\\">\\u003c/div>\\n      \\u003cdiv class=\\\"botbar__price-row\\\" id=\\\"briefToggle\\\">\\n        \\u003cdiv>\\n          \\u003cdiv class=\\\"botbar__pk\\\">Estimated total\\u003c/div>\\n          \\u003cdiv class=\\\"botbar__pv\\\" id=\\\"priceTotal\\\">$0\\u003c/div>\\n          \\u003cdiv class=\\\"botbar__pb\\\" id=\\\"priceBreak\\\">Pick pace + cities to see the price.\\u003c/div>\\n        \\u003c/div>\\n        \\u003cdiv>\\n          \\u003cspan class=\\\"botbar__score\\\" id=\\\"briefScore\\\">0%\\u003c/span>\\n          \\u003cspan class=\\\"botbar__brief\\\">View brief \\u003cspan style=\\\"font-size:13px\\\">&#9650;\\u003c/span>\\u003c/span>\\n        \\u003c/div>\\n      \\u003c/div>\\n      \\u003cdiv class=\\\"botbar__nav\\\">\\n        \\u003cbutton class=\\\"pill pill-ghost\\\" id=\\\"backBtn\\\" disabled>&#8592; Back\\u003c/button>\\n        \\u003cbutton class=\\\"pill pill-main\\\" id=\\\"nextBtn\\\">Continue &#8594;\\u003c/button>\\n      \\u003c/div>\\n    \\u003c/div>\\n\\n    \\u003cdiv class=\\\"sheet-back\\\" id=\\\"sheetBack\\\">\\u003c/div>\\n\\n    \\u003cdiv class=\\\"sheet sheet--brief\\\" id=\\\"briefSheet\\\">\\n      \\u003cdiv class=\\\"sheet__grip\\\">\\u003c/div>\\n      \\u003cdiv class=\\\"sheet__head\\\">\\n        \\u003cdiv>\\u003cspan class=\\\"eyebrow\\\">Live brief\\u003c/span>\\u003cdiv class=\\\"brief-score__t\\\" id=\\\"briefHeadline\\\" style=\\\"margin-top:4px\\\">Tell us about your party\\u003c/div>\\u003c/div>\\n        \\u003cbutton class=\\\"sheet__x\\\" data-close-brief>&times;\\u003c/button>\\n      \\u003c/div>\\n      \\u003cdiv class=\\\"sheet__body\\\">\\n        \\u003cdiv class=\\\"brief-score\\\">\\u003cspan class=\\\"brief-score__n\\\" id=\\\"briefScore2\\\">0% complete\\u003c/span>\\u003c/div>\\n        \\u003cdiv id=\\\"briefList\\\">\\u003cdiv class=\\\"empty-note\\\">Your selections will appear here.\\u003c/div>\\u003c/div>\\n      \\u003c/div>\\n    \\u003c/div>\\n\\n    \\u003cdiv class=\\\"sheet\\\" id=\\\"daySheet\\\" style=\\\"max-height:92%\\\">\\n      \\u003cdiv class=\\\"sheet__grip\\\">\\u003c/div>\\n      \\u003cdiv class=\\\"sheet__head\\\" id=\\\"dayHead\\\">\\u003c/div>\\n      \\u003cdiv class=\\\"sheet__body\\\" id=\\\"dayBody\\\">\\u003c/div>\\n      \\u003cdiv class=\\\"sheet-foot\\\">\\n        \\u003cbutton class=\\\"pill pill-main\\\" data-save-day style=\\\"flex:1\\\">Save &amp; close\\u003c/button>\\n        \\u003cbutton class=\\\"pill pill-ghost\\\" data-reset-day>Reset\\u003c/button>\\n      \\u003c/div>\\n    \\u003c/div>\\n  \\u003c/div>\\n\\u003c/div>\\n\\n\\u003cscript>\\n/* === DEMO image overrides (real ChinaTourly theme assets) === */\\nconst CDN_A=\\\"https://cdn.shopify.com/s/files/1/0748/7419/2040/t/21/assets/\\\";\\nconst CDN_F=\\\"https://cdn.shopify.com/s/files/1/0748/7419/2040/files/\\\";\\nconst DEMO_CITY_IMG={\\n  beijing:CDN_F+\\\"ct-card-forbidden-city.jpg\\\", shanghai:CDN_A+\\\"ct-city-shanghai.jpg\\\",\\n  xian:CDN_A+\\\"ct-city-xian.jpg\\\", chengdu:CDN_F+\\\"ct-card-panda-morning.jpg\\\",\\n  guilin:CDN_A+\\\"ct-city-guilin.jpg\\\", lhasa:CDN_F+\\\"ct-card-potala.jpg\\\",\\n  lijiang:CDN_A+\\\"ct-city-lijiang.jpg\\\", hangzhou:CDN_A+\\\"ct-city-hangzhou.jpg\\\"\\n};\\nfunction cityImg(c){return DEMO_CITY_IMG[c.id]||c.img;}\\n\\n/* === STATE (same shape as PC) === */\\nconst STATE={step:0,party:null,\\n  travellers:[{id:1,age:35,gender:'m',notes:[]},{id:2,age:32,gender:'f',notes:[]}],\\n  travelNotes:'',days:10,pace:null,interests:new Set(),cities:[],perDay:{},\\n  defaultHotel:'h5',defaultTransport:'t2',defaultMeal:'m1'};\\n\\n\\n/* ---- PARTIES..STANDARD_DAY_PLAN ---- */\\nconst PARTIES = [\\n  {id:'solo', icon:'\\u003cspan class=\\\\\\\"mono-circle\\\\\\\">S\\u003c/span>',  title:'Solo',              sub:'Just me. Senior guide, slow pace.', meta:'1 traveller', multiplier:1, img:'https://cdn.shopify.com/s/files/1/0748/7419/2040/t/21/assets/ct-hero-our-guides.jpg'},\\n  {id:'couple', icon:'\\u003cspan class=\\\\\\\"mono-circle\\\\\\\">C\\u003c/span>',  title:'Couple',             sub:'Two travellers \u2014 milestone or honeymoon.', meta:'2 travellers', multiplier:2, img:'https://cdn.shopify.com/s/files/1/0748/7419/2040/t/21/assets/ct-card-lijiang-courtyard.jpg'},\\n  {id:'family', icon:'\\u003cspan class=\\\\\\\"mono-circle\\\\\\\">F\\u003c/span>', title:'Family with kids',   sub:'Parents + kids. Mid-day breaks. Kid-tolerant restaurants.', meta:'3-5 travellers', multiplier:4, img:'https://cdn.shopify.com/s/files/1/0748/7419/2040/t/21/assets/ct-coll-family.jpg'},\\n  {id:'multigen', icon:'\\u003cspan class=\\\\\\\"mono-circle\\\\\\\">M\\u003c/span>',  title:'Multi-generation',   sub:'3 generations. Accessibility built-in.', meta:'5-8 travellers', multiplier:6, img:'https://cdn.shopify.com/s/files/1/0748/7419/2040/t/21/assets/ct-coll-journeys.jpg'},\\n  {id:'brothers', icon:'\\u003cspan class=\\\\\\\"mono-circle\\\\\\\">B\\u003c/span>',  title:'Brothers / Friends', sub:'2-4 friends. Active pace. Whisky bars by night.', meta:'2-4 travellers', multiplier:4, img:'https://cdn.shopify.com/s/files/1/0748/7419/2040/t/21/assets/ct-prod-guide.jpg'},\\n  {id:'girls', icon:'\\u003cspan class=\\\\\\\"mono-circle\\\\\\\">G\\u003c/span>',  title:'Girlfriends',        sub:'4-6 women. Spa days. Suzhou silk. Afternoon tea.', meta:'4-6 travellers', multiplier:5, img:'https://cdn.shopify.com/s/files/1/0748/7419/2040/t/21/assets/ct-card-tea.jpg'},\\n];\\nconst PACES = [\\n  {id:'handson',  icon:'',  title:'Hands-on',  sub:'4 sites/day \u00B7 maximise coverage \u00B7 standard restaurants', base:2000, meta:'Service basics included', img:'https://cdn.shopify.com/s/files/1/0748/7419/2040/t/21/assets/ct-prod-dining.jpg'},\\n  {id:'cultural', icon:'',   title:'Cultural',  sub:'2-3 sites/day \u00B7 3-night minimums \u00B7 earn depth', base:2000, meta:'+ 1 ICH master session/trip', img:'https://cdn.shopify.com/s/files/1/0748/7419/2040/t/21/assets/ct-prod-hotel.jpg'},\\n  {id:'insider',  icon:'', title:'Insider',   sub:'1 site/day \u00B7 slow courtyards \u00B7 early-morning private access', base:2000, meta:'+ 3 master sessions \u00B7 private kitchens \u00B7 Aman tier defaults', img:'https://cdn.shopify.com/s/files/1/0748/7419/2040/t/21/assets/ct-prod-day.jpg'},\\n];\\nconst INTERESTS = [\\n  {id:'food',     icon:'', title:'Cuisine',          sub:'8 regional traditions \u00B7 markets \u00B7 masters', img:'https://cdn.shopify.com/s/files/1/0748/7419/2040/t/21/assets/ct-hero-meet-the-masters.jpg'},\\n  {id:'arch',     icon:'', title:'Ancient Architecture', sub:'Forbidden City \u00B7 Terracotta \u00B7 Tang Wall', img:'https://cdn.shopify.com/s/files/1/0748/7419/2040/t/21/assets/ct-card-shaxi.jpg'},\\n  {id:'heritage', icon:'', title:'Intangible Heritage', sub:'Calligraphy \u00B7 tea \u00B7 porcelain \u00B7 opera', img:'https://cdn.shopify.com/s/files/1/0748/7419/2040/t/21/assets/ct-hero-tea-culture.jpg'},\\n  {id:'scenery',  icon:'', title:'Landscape',        sub:'Karst \u00B7 alpine lakes \u00B7 rice terraces', img:'https://cdn.shopify.com/s/files/1/0748/7419/2040/t/21/assets/ct-insta-li-river.jpg'},\\n  {id:'spiritual',icon:'', title:'Spiritual',        sub:'Tibetan Buddhism \u00B7 Wutai \u00B7 Taoist mountain', img:'https://cdn.shopify.com/s/files/1/0748/7419/2040/t/21/assets/ct-card-wutaishan.jpg'},\\n  {id:'wellness', icon:'', title:'Wellness \u00B7 Slow',  sub:'Tea ceremony \u00B7 qigong \u00B7 Aman tea estates', img:'https://cdn.shopify.com/s/files/1/0748/7419/2040/t/21/assets/ct-insta-tea.jpg'},\\n];\\nconst CITIES = [{\\\"id\\\":\\\"beijing\\\",\\\"name\\\":\\\"Beijing\\\",\\\"icon\\\":\\\"\\\",\\\"must\\\":\\\"Forbidden City \u00B7 Mutianyu Great Wall \u00B7 Hutong courtyards \u00B7 Peking Duck\\\",\\\"rec\\\":\\\"3-5 days\\\",\\\"intro\\\":\\\"700 years of imperial capital. Best in Apr-May and Sept-Oct.\\\",\\\"img\\\":\\\"https://cdn.shopify.com/s/files/1/0748/7419/2040/files/ct-card-forbidden-city.jpg\\\"},{\\\"id\\\":\\\"shanghai\\\",\\\"name\\\":\\\"Shanghai\\\",\\\"icon\\\":\\\"\\\",\\\"must\\\":\\\"The Bund \u00B7 Yu Garden \u00B7 Xiao Long Bao \u00B7 French Concession\\\",\\\"rec\\\":\\\"2-3 days\\\",\\\"intro\\\":\\\"Modern gateway to Jiangnan. Year-round; avoid summer humidity.\\\",\\\"img\\\":\\\"https://cdn.shopify.com/s/files/1/0748/7419/2040/t/21/assets/ct-city-shanghai.jpg\\\"},{\\\"id\\\":\\\"xian\\\",\\\"name\\\":\\\"Xi'an\\\",\\\"icon\\\":\\\"\\\",\\\"must\\\":\\\"Terracotta Army \u00B7 Tang City Wall \u00B7 Hui Muslim Quarter \u00B7 Beilin\\\",\\\"rec\\\":\\\"2-3 days\\\",\\\"intro\\\":\\\"Tang dynasty heart. Silk Road origin. Best Apr-May, Oct.\\\",\\\"img\\\":\\\"https://cdn.shopify.com/s/files/1/0748/7419/2040/t/21/assets/ct-city-xian.jpg\\\"},{\\\"id\\\":\\\"chengdu\\\",\\\"name\\\":\\\"Chengdu\\\",\\\"icon\\\":\\\"\\\",\\\"must\\\":\\\"Giant Pandas \u00B7 Sichuan Hot Pot \u00B7 Mt Emei \u00B7 Jiuzhaigou\\\",\\\"rec\\\":\\\"3-5 days\\\",\\\"intro\\\":\\\"Panda capital + numbing-spicy food. Mild year-round; Jiuzhai Sept-Oct only.\\\",\\\"img\\\":\\\"https://cdn.shopify.com/s/files/1/0748/7419/2040/files/ct-card-panda-morning.jpg\\\"},{\\\"id\\\":\\\"guilin\\\",\\\"name\\\":\\\"Guilin\\\",\\\"icon\\\":\\\"\\\",\\\"must\\\":\\\"Li River 83km cruise \u00B7 Yulong bamboo raft \u00B7 Longji terraces\\\",\\\"rec\\\":\\\"3-4 days\\\",\\\"intro\\\":\\\"Most photogenic karst landscape in China. Apr-Oct ideal.\\\",\\\"img\\\":\\\"https://cdn.shopify.com/s/files/1/0748/7419/2040/t/21/assets/ct-city-guilin.jpg\\\"},{\\\"id\\\":\\\"lhasa\\\",\\\"name\\\":\\\"Lhasa\\\",\\\"icon\\\":\\\"\\\",\\\"must\\\":\\\"Potala Palace \u00B7 Jokhang Temple \u00B7 Everest views \u00B7 TTP required\\\",\\\"rec\\\":\\\"5-7 days\\\",\\\"intro\\\":\\\"Tibetan plateau \u00B7 3,650m altitude \u00B7 best in June-Oct. Permit needed.\\\",\\\"img\\\":\\\"https://cdn.shopify.com/s/files/1/0748/7419/2040/files/ct-card-potala.jpg\\\"},{\\\"id\\\":\\\"lijiang\\\",\\\"name\\\":\\\"Lijiang\\\",\\\"icon\\\":\\\"\\\",\\\"must\\\":\\\"Naxi Old Town UNESCO \u00B7 Yulong Snow Mountain \u00B7 Tiger Leaping Gorge\\\",\\\"rec\\\":\\\"3-4 days\\\",\\\"intro\\\":\\\"25 ethnic groups gateway \u00B7 slow water-channel town \u00B7 cool altitude.\\\",\\\"img\\\":\\\"https://cdn.shopify.com/s/files/1/0748/7419/2040/t/21/assets/ct-city-lijiang.jpg\\\"},{\\\"id\\\":\\\"hangzhou\\\",\\\"name\\\":\\\"Hangzhou\\\",\\\"icon\\\":\\\"\\\",\\\"must\\\":\\\"West Lake \u00B7 Mingqian Longjing tea master \u00B7 Lingyin Temple\\\",\\\"rec\\\":\\\"2-3 days\\\",\\\"intro\\\":\\\"Song dynasty refinement \u00B7 Mingqian tea peak late March-early April.\\\",\\\"img\\\":\\\"https://cdn.shopify.com/s/files/1/0748/7419/2040/t/21/assets/ct-city-hangzhou.jpg\\\"},{\\\"id\\\":\\\"suzhou\\\",\\\"name\\\":\\\"Suzhou\\\",\\\"icon\\\":\\\"\\\",\\\"must\\\":\\\"Humble Administrator's Garden \u00B7 Master of Nets \u00B7 Pingjiang Road \u00B7 Silk embroidery\\\",\\\"rec\\\":\\\"2-3 days\\\",\\\"intro\\\":\\\"Jiangnan's garden capital \u2014 canals, silk, Song-dynasty refinement. Best Apr-May, Sep-Nov.\\\",\\\"img\\\":\\\"https://cdn.shopify.com/s/files/1/0748/7419/2040/files/ct-11-product-31-grand-canal-heritage.webp\\\"},{\\\"id\\\":\\\"dunhuang\\\",\\\"name\\\":\\\"Dunhuang\\\",\\\"icon\\\":\\\"\\\",\\\"must\\\":\\\"Mogao Caves \u00B7 Crescent Lake \u00B7 Singing Sand Dunes \u00B7 Yangguan Pass\\\",\\\"rec\\\":\\\"2-3 days\\\",\\\"intro\\\":\\\"Buddhist cave-art heart of the Silk Road \u2014 Tang murals in the desert. Best May-Oct.\\\",\\\"img\\\":\\\"https://cdn.shopify.com/s/files/1/0748/7419/2040/files/ct-11-product-43-silk-road-photography.webp\\\"},{\\\"id\\\":\\\"kashgar\\\",\\\"name\\\":\\\"Kashgar\\\",\\\"icon\\\":\\\"\\\",\\\"must\\\":\\\"Id Kah Mosque \u00B7 Old Town alleys \u00B7 Sunday Bazaar \u00B7 Karakoram Highway\\\",\\\"rec\\\":\\\"2-3 days\\\",\\\"intro\\\":\\\"The Silk Road's westernmost oasis \u2014 Uyghur culture at China's edge. Best Apr-Jun, Sep-Oct.\\\",\\\"img\\\":\\\"https://cdn.shopify.com/s/files/1/0748/7419/2040/files/pexels-photo-29890322.jpg\\\"},{\\\"id\\\":\\\"turpan\\\",\\\"name\\\":\\\"Turpan\\\",\\\"icon\\\":\\\"\\\",\\\"must\\\":\\\"Jiaohe ruins \u00B7 Flaming Mountains \u00B7 Karez wells \u00B7 Grape Valley\\\",\\\"rec\\\":\\\"1-2 days\\\",\\\"intro\\\":\\\"China's hottest, lowest oasis \u2014 Silk Road ruins and vineyards. Best Apr-Jun, Sep-Oct.\\\",\\\"img\\\":\\\"https://cdn.shopify.com/s/files/1/0748/7419/2040/t/21/assets/ct-day-turpan.jpg\\\"},{\\\"id\\\":\\\"kunming\\\",\\\"name\\\":\\\"Kunming\\\",\\\"icon\\\":\\\"\\\",\\\"must\\\":\\\"Stone Forest \u00B7 Green Lake \u00B7 Yuantong Temple \u00B7 Dianchi Lake\\\",\\\"rec\\\":\\\"2-3 days\\\",\\\"intro\\\":\\\"Yunnan's mild Spring City and gateway to the southwest. Pleasant year-round.\\\",\\\"img\\\":\\\"https://cdn.shopify.com/s/files/1/0748/7419/2040/files/ct-11-product-17-yunnan-family-adventure.webp\\\"},{\\\"id\\\":\\\"dali\\\",\\\"name\\\":\\\"Dali\\\",\\\"icon\\\":\\\"\\\",\\\"must\\\":\\\"Erhai Lake \u00B7 Cangshan Mountains \u00B7 Bai Old Town \u00B7 Three Pagodas\\\",\\\"rec\\\":\\\"2-3 days\\\",\\\"intro\\\":\\\"Lakeside Bai-culture town under snow peaks \u2014 slow Yunnan. Best Mar-Oct.\\\",\\\"img\\\":\\\"https://cdn.shopify.com/s/files/1/0748/7419/2040/t/21/assets/dimg-yunnan-classics-10-days-04.webp\\\"},{\\\"id\\\":\\\"shangrila\\\",\\\"name\\\":\\\"Shangri-La\\\",\\\"icon\\\":\\\"\\\",\\\"must\\\":\\\"Songzanlin Monastery \u00B7 Pudacuo Park \u00B7 Tiger Leaping Gorge \u00B7 Napa Lake\\\",\\\"rec\\\":\\\"2-3 days\\\",\\\"intro\\\":\\\"Tibetan-plateau edge at 3,200m \u2014 monasteries and alpine meadows. Best May-Oct.\\\",\\\"img\\\":\\\"https://cdn.shopify.com/s/files/1/0748/7419/2040/t/21/assets/ct-card-meili.jpg\\\"},{\\\"id\\\":\\\"guiyang\\\",\\\"name\\\":\\\"Guiyang\\\",\\\"icon\\\":\\\"\\\",\\\"must\\\":\\\"Qingyan Ancient Town \u00B7 Jiaxiu Pavilion \u00B7 Huangguoshu Falls \u00B7 Miao villages\\\",\\\"rec\\\":\\\"2-3 days\\\",\\\"intro\\\":\\\"Guizhou's green capital and gateway to minority-village country. Best Mar-Jun, Sep-Nov.\\\",\\\"img\\\":\\\"https://cdn.shopify.com/s/files/1/0748/7419/2040/t/21/assets/dimg-hidden-guizhou-miao-dong-9-days-06.webp\\\"},{\\\"id\\\":\\\"kaili\\\",\\\"name\\\":\\\"Kaili\\\",\\\"icon\\\":\\\"\\\",\\\"must\\\":\\\"Xijiang Miao village \u00B7 Langde village \u00B7 Datang Miao \u00B7 Lusheng festivals\\\",\\\"rec\\\":\\\"2-3 days\\\",\\\"intro\\\":\\\"Heart of Guizhou's Miao and Dong minority country. Best Mar-Jun, Sep-Nov.\\\",\\\"img\\\":\\\"https://cdn.shopify.com/s/files/1/0748/7419/2040/t/21/assets/ct-day-guizhou-miao.jpg\\\"},{\\\"id\\\":\\\"jiuzhaigou\\\",\\\"name\\\":\\\"Jiuzhaigou\\\",\\\"icon\\\":\\\"\\\",\\\"must\\\":\\\"108 alpine lakes \u00B7 Pearl Shoal Falls \u00B7 Five-Flower Lake \u00B7 Tibetan villages\\\",\\\"rec\\\":\\\"2-3 days\\\",\\\"intro\\\":\\\"Turquoise-lake valley in north Sichuan. Strict Sep 25 \u2013 Oct 25 colour peak.\\\",\\\"img\\\":\\\"https://cdn.shopify.com/s/files/1/0748/7419/2040/t/21/assets/ct-card-jiuzhaigou.jpg\\\"},{\\\"id\\\":\\\"zhangjiajie\\\",\\\"name\\\":\\\"Zhangjiajie\\\",\\\"icon\\\":\\\"\\\",\\\"must\\\":\\\"Avatar sandstone pillars \u00B7 Tianzi Mountain \u00B7 Glass bridge \u00B7 Bailong elevator\\\",\\\"rec\\\":\\\"2-3 days\\\",\\\"intro\\\":\\\"The floating-mountain landscape that inspired Pandora. Best Apr-Oct.\\\",\\\"img\\\":\\\"https://cdn.shopify.com/s/files/1/0748/7419/2040/files/ct-11-product-20-zhangjiajie-avatar-mountains.webp\\\"},{\\\"id\\\":\\\"huangshan\\\",\\\"name\\\":\\\"Huangshan\\\",\\\"icon\\\":\\\"\\\",\\\"must\\\":\\\"Yellow Mountain peaks \u00B7 Sea of clouds \u00B7 Hongcun village \u00B7 Huizhou architecture\\\",\\\"rec\\\":\\\"2-3 days\\\",\\\"intro\\\":\\\"China's most-painted granite peaks and Huizhou villages. Best Apr-Nov.\\\",\\\"img\\\":\\\"https://cdn.shopify.com/s/files/1/0748/7419/2040/files/ct-11-product-22-huangshan-huizhou.webp\\\"},{\\\"id\\\":\\\"pingyao\\\",\\\"name\\\":\\\"Pingyao\\\",\\\"icon\\\":\\\"\\\",\\\"must\\\":\\\"Ming city walls \u00B7 Rishengchang bank \u00B7 Courtyard mansions \u00B7 Shanxi vinegar\\\",\\\"rec\\\":\\\"1-2 days\\\",\\\"intro\\\":\\\"China's best-preserved walled Ming-Qing city \u2014 the old banking capital. Best Apr-Oct.\\\",\\\"img\\\":\\\"https://cdn.shopify.com/s/files/1/0748/7419/2040/t/21/assets/ct-card-pingyao.jpg\\\"},{\\\"id\\\":\\\"datong\\\",\\\"name\\\":\\\"Datong\\\",\\\"icon\\\":\\\"\\\",\\\"must\\\":\\\"Yungang Grottoes \u00B7 Hanging Monastery \u00B7 Ming city walls \u00B7 Nine-Dragon Wall\\\",\\\"rec\\\":\\\"1-2 days\\\",\\\"intro\\\":\\\"Shanxi's Buddhist-grotto city on the old frontier. Best Apr-Oct.\\\",\\\"img\\\":\\\"https://cdn.shopify.com/s/files/1/0748/7419/2040/t/21/assets/ct-card-yungang.jpg\\\"},{\\\"id\\\":\\\"chongqing\\\",\\\"name\\\":\\\"Chongqing\\\",\\\"icon\\\":\\\"\\\",\\\"must\\\":\\\"Hongya Cave \u00B7 Yangtze cruise port \u00B7 Ciqikou Old Town \u00B7 Mala hot pot\\\",\\\"rec\\\":\\\"1-2 days\\\",\\\"intro\\\":\\\"Mountain megacity and Yangtze-cruise gateway \u2014 the numbing-spicy capital. Year-round.\\\",\\\"img\\\":\\\"https://cdn.shopify.com/s/files/1/0748/7419/2040/files/pexels-photo-6752827_248554a9-56f1-4dda-949e-b222b77ba76a.jpg\\\"},{\\\"id\\\":\\\"nanjing\\\",\\\"name\\\":\\\"Nanjing\\\",\\\"icon\\\":\\\"\\\",\\\"must\\\":\\\"Ming Xiaoling Tomb \u00B7 City Wall \u00B7 Confucius Temple \u00B7 Sun Yat-sen Mausoleum\\\",\\\"rec\\\":\\\"1-2 days\\\",\\\"intro\\\":\\\"Six-dynasty capital with Ming grandeur on the Yangtze. Best Mar-May, Sep-Nov.\\\",\\\"img\\\":\\\"https://cdn.shopify.com/s/files/1/0748/7419/2040/t/21/assets/ct-card-nanjing-wall.jpg\\\"},{\\\"id\\\":\\\"xiamen\\\",\\\"name\\\":\\\"Xiamen\\\",\\\"icon\\\":\\\"\\\",\\\"must\\\":\\\"Gulangyu Island \u00B7 Nanputuo Temple \u00B7 Fujian tulou \u00B7 Seaside promenade\\\",\\\"rec\\\":\\\"2-3 days\\\",\\\"intro\\\":\\\"Breezy island-city gateway to Fujian's tulou earth-houses. Best Mar-Nov.\\\",\\\"img\\\":\\\"https://cdn.shopify.com/s/files/1/0748/7419/2040/t/21/assets/ct-day-xiamen-gulangyu.jpg\\\"},{\\\"id\\\":\\\"hongkong\\\",\\\"name\\\":\\\"Hong Kong\\\",\\\"icon\\\":\\\"\\\",\\\"must\\\":\\\"Victoria Peak \u00B7 Star Ferry \u00B7 Temple Street \u00B7 Dim sum\\\",\\\"rec\\\":\\\"2-3 days\\\",\\\"intro\\\":\\\"Skyline, harbour and Cantonese energy where East meets West. Year-round.\\\",\\\"img\\\":\\\"https://cdn.shopify.com/s/files/1/0748/7419/2040/t/21/assets/dimg-hongkong-guangzhou-heritage-8-days-02.webp\\\"},{\\\"id\\\":\\\"guangzhou\\\",\\\"name\\\":\\\"Guangzhou\\\",\\\"icon\\\":\\\"\\\",\\\"must\\\":\\\"Canton Tower \u00B7 Shamian Island \u00B7 Chen Clan Academy \u00B7 Morning dim sum\\\",\\\"rec\\\":\\\"2 days\\\",\\\"intro\\\":\\\"Cantonese-cuisine capital on the Pearl River. Trade-port history. Year-round.\\\",\\\"img\\\":\\\"https://cdn.shopify.com/s/files/1/0748/7419/2040/files/ct-11-product-55-imperial-banquet-culture.webp\\\"},{\\\"id\\\":\\\"shunde\\\",\\\"name\\\":\\\"Shunde\\\",\\\"icon\\\":\\\"\\\",\\\"must\\\":\\\"Cantonese food and culinary villages\\\",\\\"rec\\\":\\\"\\\",\\\"intro\\\":\\\"Guangdong, Cantonese food circuit. Route details are confirmed in your proposal.\\\",\\\"img\\\":\\\"https://cdn.shopify.com/s/files/1/0748/7419/2040/t/31/assets/ct-dayfix-20260715-6f7e27b4f7049eda.webp?v=1784087467\\\",\\\"planningMode\\\":\\\"quote_only\\\",\\\"timingText\\\":\\\"Town / local destination - timing confirmed in your proposal\\\"},{\\\"id\\\":\\\"macau\\\",\\\"name\\\":\\\"Macau\\\",\\\"icon\\\":\\\"\\\",\\\"must\\\":\\\"Historic streets and Portuguese-Chinese heritage\\\",\\\"rec\\\":\\\"\\\",\\\"intro\\\":\\\"Pearl River Delta; Hong Kong/Guangzhou/Macau route. Route details are confirmed in your proposal.\\\",\\\"img\\\":\\\"https://cdn.shopify.com/s/files/1/0748/7419/2040/t/31/assets/ct-dayfix-20260715-40850df7c2dd6cde.webp?v=1784087390\\\",\\\"planningMode\\\":\\\"quote_only\\\",\\\"timingText\\\":\\\"Region - timing confirmed in your proposal\\\"},{\\\"id\\\":\\\"leshan\\\",\\\"name\\\":\\\"Leshan\\\",\\\"icon\\\":\\\"\\\",\\\"must\\\":\\\"Leshan Giant Buddha and riverside walks\\\",\\\"rec\\\":\\\"\\\",\\\"intro\\\":\\\"Sichuan, Chengdu-Leshan-Mount Emei corridor. Route details are confirmed in your proposal.\\\",\\\"img\\\":\\\"https://cdn.shopify.com/s/files/1/0748/7419/2040/t/21/assets/dimg-chengdu-jiuzhaigou-nature-8-days-07.webp\\\",\\\"planningMode\\\":\\\"quote_only\\\",\\\"timingText\\\":\\\"City - timing confirmed in your proposal\\\"},{\\\"id\\\":\\\"danba\\\",\\\"name\\\":\\\"Danba\\\",\\\"icon\\\":\\\"\\\",\\\"must\\\":\\\"Jiarong villages and stone watchtowers\\\",\\\"rec\\\":\\\"\\\",\\\"intro\\\":\\\"Garze, western Sichuan; Jiarong watchtower villages. Route details are confirmed in your proposal.\\\",\\\"img\\\":\\\"https://cdn.shopify.com/s/files/1/0748/7419/2040/t/31/assets/ct-dayfill-20260722-031958ad4166752f.webp?v=1784667670\\\",\\\"planningMode\\\":\\\"quote_only\\\",\\\"timingText\\\":\\\"Town / local destination - timing confirmed in your proposal\\\"},{\\\"id\\\":\\\"tagong\\\",\\\"name\\\":\\\"Tagong\\\",\\\"icon\\\":\\\"\\\",\\\"must\\\":\\\"Grasslands and monastery surroundings\\\",\\\"rec\\\":\\\"\\\",\\\"intro\\\":\\\"Kangding, Garze, Sichuan; grassland and monastery. Route details are confirmed in your proposal.\\\",\\\"img\\\":\\\"https://cdn.shopify.com/s/files/1/0748/7419/2040/t/31/assets/ct-dayfill-20260722-58eec35f7cf71e6c.webp?v=1784667784\\\",\\\"planningMode\\\":\\\"quote_only\\\",\\\"timingText\\\":\\\"Town / local destination - timing confirmed in your proposal\\\"},{\\\"id\\\":\\\"songpan\\\",\\\"name\\\":\\\"Songpan\\\",\\\"icon\\\":\\\"\\\",\\\"must\\\":\\\"Old-town walls and western Sichuan scenery\\\",\\\"rec\\\":\\\"\\\",\\\"intro\\\":\\\"Aba, Sichuan; old garrison walls. Route details are confirmed in your proposal.\\\",\\\"img\\\":\\\"https://cdn.shopify.com/s/files/1/0748/7419/2040/t/31/assets/ct-dayfix-20260715-625c683eaefe6495.webp?v=1784087439\\\",\\\"planningMode\\\":\\\"quote_only\\\",\\\"timingText\\\":\\\"Town / local destination - timing confirmed in your proposal\\\"},{\\\"id\\\":\\\"emeishan\\\",\\\"name\\\":\\\"Emeishan / Mount Emei\\\",\\\"icon\\\":\\\"\\\",\\\"must\\\":\\\"Mount Emei and mountain temples\\\",\\\"rec\\\":\\\"\\\",\\\"intro\\\":\\\"Sichuan; city/overnight base and Mount Emei scenic visit. Route details are confirmed in your proposal.\\\",\\\"img\\\":\\\"https://cdn.shopify.com/s/files/1/0748/7419/2040/t/31/assets/ct-dayfix-20260715-8c1cabbb24c08777.webp?v=1784087487\\\",\\\"planningMode\\\":\\\"quote_only\\\",\\\"timingText\\\":\\\"City - timing confirmed in your proposal\\\"},{\\\"id\\\":\\\"yangshuo\\\",\\\"name\\\":\\\"Yangshuo\\\",\\\"icon\\\":\\\"\\\",\\\"must\\\":\\\"Yulong River countryside and karst scenery\\\",\\\"rec\\\":\\\"\\\",\\\"intro\\\":\\\"Guilin, Guangxi; Yulong River and karst countryside. Route details are confirmed in your proposal.\\\",\\\"img\\\":\\\"https://cdn.shopify.com/s/files/1/0748/7419/2040/t/21/assets/dimg-guangxi-guizhou-ethnic-discovery-11-days-03.webp\\\",\\\"planningMode\\\":\\\"quote_only\\\",\\\"timingText\\\":\\\"Town / local destination - timing confirmed in your proposal\\\"},{\\\"id\\\":\\\"zhaoxing\\\",\\\"name\\\":\\\"Zhaoxing\\\",\\\"icon\\\":\\\"\\\",\\\"must\\\":\\\"Dong village lanes and drum towers\\\",\\\"rec\\\":\\\"\\\",\\\"intro\\\":\\\"Liping, Guizhou; Dong drum towers and grand song. Route details are confirmed in your proposal.\\\",\\\"img\\\":\\\"https://cdn.shopify.com/s/files/1/0748/7419/2040/t/21/assets/dimg-guangxi-guizhou-ethnic-discovery-11-days-05.webp\\\",\\\"planningMode\\\":\\\"quote_only\\\",\\\"timingText\\\":\\\"Town / local destination - timing confirmed in your proposal\\\"},{\\\"id\\\":\\\"xijiang\\\",\\\"name\\\":\\\"Xijiang Miao Village\\\",\\\"icon\\\":\\\"\\\",\\\"must\\\":\\\"Miao village architecture and local traditions\\\",\\\"rec\\\":\\\"\\\",\\\"intro\\\":\\\"Leishan, Guizhou; Thousand-Household Miao village. Route details are confirmed in your proposal.\\\",\\\"img\\\":\\\"https://cdn.shopify.com/s/files/1/0748/7419/2040/t/31/assets/ct-dayfix-20260715-f2dbf6f31d0b4dca.webp?v=1784087603\\\",\\\"planningMode\\\":\\\"quote_only\\\",\\\"timingText\\\":\\\"Town / local destination - timing confirmed in your proposal\\\"},{\\\"id\\\":\\\"danzhai\\\",\\\"name\\\":\\\"Danzhai\\\",\\\"icon\\\":\\\"\\\",\\\"must\\\":\\\"Batik, paper-making villages and Guizhou culture\\\",\\\"rec\\\":\\\"\\\",\\\"intro\\\":\\\"Qiandongnan, Guizhou; batik and paper villages. Route details are confirmed in your proposal.\\\",\\\"img\\\":\\\"https://cdn.shopify.com/s/files/1/0748/7419/2040/t/31/assets/ct-dayfix-20260715-9d63eb731d31f4d6.webp?v=1784087526\\\",\\\"planningMode\\\":\\\"quote_only\\\",\\\"timingText\\\":\\\"Town / local destination - timing confirmed in your proposal\\\"},{\\\"id\\\":\\\"kaiping\\\",\\\"name\\\":\\\"Kaiping\\\",\\\"icon\\\":\\\"\\\",\\\"must\\\":\\\"Diaolou towers and Guangdong countryside\\\",\\\"rec\\\":\\\"\\\",\\\"intro\\\":\\\"Guangdong; countryside and diaolou circuit. Route details are confirmed in your proposal.\\\",\\\"img\\\":\\\"https://cdn.shopify.com/s/files/1/0748/7419/2040/t/21/assets/dimg-hongkong-guangzhou-heritage-8-days-06.webp\\\",\\\"planningMode\\\":\\\"quote_only\\\",\\\"timingText\\\":\\\"City - timing confirmed in your proposal\\\"},{\\\"id\\\":\\\"hongcun\\\",\\\"name\\\":\\\"Hongcun\\\",\\\"icon\\\":\\\"\\\",\\\"must\\\":\\\"Huizhou village lanes and waterside architecture\\\",\\\"rec\\\":\\\"\\\",\\\"intro\\\":\\\"Yi County, Huangshan, Anhui; Huizhou villages. Route details are confirmed in your proposal.\\\",\\\"img\\\":\\\"https://cdn.shopify.com/s/files/1/0748/7419/2040/t/31/assets/ct-dayfill-20260722-115bd1a1690ea2f4.webp?v=1784667688\\\",\\\"planningMode\\\":\\\"quote_only\\\",\\\"timingText\\\":\\\"Town / local destination - timing confirmed in your proposal\\\"},{\\\"id\\\":\\\"wuzhen\\\",\\\"name\\\":\\\"Wuzhen\\\",\\\"icon\\\":\\\"\\\",\\\"must\\\":\\\"Canal lanes and stone bridges\\\",\\\"rec\\\":\\\"\\\",\\\"intro\\\":\\\"Tongxiang, Jiaxing, Zhejiang; Shanghai-Suzhou-Hangzhou triangle. Route details are confirmed in your proposal.\\\",\\\"img\\\":\\\"https://cdn.shopify.com/s/files/1/0748/7419/2040/t/21/assets/dimg-jiangnan-heritage-04.webp\\\",\\\"planningMode\\\":\\\"quote_only\\\",\\\"timingText\\\":\\\"Town / local destination - timing confirmed in your proposal\\\"},{\\\"id\\\":\\\"tashkurgan\\\",\\\"name\\\":\\\"Tashkurgan\\\",\\\"icon\\\":\\\"\\\",\\\"must\\\":\\\"Pamir landscapes and the old stone fort\\\",\\\"rec\\\":\\\"\\\",\\\"intro\\\":\\\"Kashgar Prefecture, Xinjiang; stone fort and grasslands. Route details are confirmed in your proposal.\\\",\\\"img\\\":\\\"https://cdn.shopify.com/s/files/1/0748/7419/2040/t/31/assets/ct-dayfix-20260715-176816e9522a6a3a.webp?v=1784087332\\\",\\\"planningMode\\\":\\\"quote_only\\\",\\\"timingText\\\":\\\"Town / local destination - timing confirmed in your proposal\\\"},{\\\"id\\\":\\\"yangzhou\\\",\\\"name\\\":\\\"Yangzhou\\\",\\\"icon\\\":\\\"\\\",\\\"must\\\":\\\"Gardens and Grand Canal heritage\\\",\\\"rec\\\":\\\"\\\",\\\"intro\\\":\\\"Jiangsu; Nanjing-Jiangnan Ming Heritage route. Route details are confirmed in your proposal.\\\",\\\"img\\\":\\\"https://cdn.shopify.com/s/files/1/0748/7419/2040/t/31/assets/ct-dayfill-20260722-060547f13ea86e58.webp?v=1784667677\\\",\\\"planningMode\\\":\\\"quote_only\\\",\\\"timingText\\\":\\\"City - timing confirmed in your proposal\\\"},{\\\"id\\\":\\\"shaxi\\\",\\\"name\\\":\\\"Shaxi\\\",\\\"icon\\\":\\\"\\\",\\\"must\\\":\\\"Sideng market square and Tea Horse Road heritage\\\",\\\"rec\\\":\\\"\\\",\\\"intro\\\":\\\"Jianchuan County, Dali Prefecture, Yunnan; Sideng market square. Route details are confirmed in your proposal.\\\",\\\"img\\\":\\\"https://cdn.shopify.com/s/files/1/0748/7419/2040/t/31/assets/ct-dayfill-20260722-f33895b0a416a45a.webp?v=1784667992\\\",\\\"planningMode\\\":\\\"quote_only\\\",\\\"timingText\\\":\\\"Town / local destination - timing confirmed in your proposal\\\"},{\\\"id\\\":\\\"taiyuan\\\",\\\"name\\\":\\\"Taiyuan\\\",\\\"icon\\\":\\\"\\\",\\\"must\\\":\\\"Shanxi heritage and onward rail connections\\\",\\\"rec\\\":\\\"\\\",\\\"intro\\\":\\\"Shanxi capital and gateway to Pingyao/Datong. Route details are confirmed in your proposal.\\\",\\\"img\\\":\\\"https://cdn.shopify.com/s/files/1/0748/7419/2040/t/31/assets/ct-dayfill-20260722-4fa5b6a978e387be.webp?v=1784667763\\\",\\\"planningMode\\\":\\\"quote_only\\\",\\\"timingText\\\":\\\"City - timing confirmed in your proposal\\\"},{\\\"id\\\":\\\"kangding\\\",\\\"name\\\":\\\"Kangding\\\",\\\"icon\\\":\\\"\\\",\\\"must\\\":\\\"Western Sichuan highland routes\\\",\\\"rec\\\":\\\"\\\",\\\"intro\\\":\\\"Garze, Sichuan; western overland route. Route details are confirmed in your proposal.\\\",\\\"img\\\":\\\"https://cdn.shopify.com/s/files/1/0748/7419/2040/t/21/assets/dimg-sichuan-tibet-overland-16-days-02.webp\\\",\\\"planningMode\\\":\\\"quote_only\\\",\\\"timingText\\\":\\\"City - timing confirmed in your proposal\\\"},{\\\"id\\\":\\\"litang\\\",\\\"name\\\":\\\"Litang\\\",\\\"icon\\\":\\\"\\\",\\\"must\\\":\\\"Highland town and monastery surroundings\\\",\\\"rec\\\":\\\"\\\",\\\"intro\\\":\\\"Garze, Sichuan; highland monastery area. Route details are confirmed in your proposal.\\\",\\\"img\\\":\\\"https://cdn.shopify.com/s/files/1/0748/7419/2040/t/21/assets/dimg-sichuan-tibet-overland-16-days-04.webp\\\",\\\"planningMode\\\":\\\"quote_only\\\",\\\"timingText\\\":\\\"Town / local destination - timing confirmed in your proposal\\\"},{\\\"id\\\":\\\"nyingchi\\\",\\\"name\\\":\\\"Nyingchi\\\",\\\"icon\\\":\\\"\\\",\\\"must\\\":\\\"Southeastern Tibet valleys and overland scenery\\\",\\\"rec\\\":\\\"\\\",\\\"intro\\\":\\\"Southeastern Tibet; overland route to Lhasa. Route details are confirmed in your proposal.\\\",\\\"img\\\":\\\"https://cdn.shopify.com/s/files/1/0748/7419/2040/t/21/assets/dimg-sichuan-tibet-overland-16-days-08.webp\\\",\\\"planningMode\\\":\\\"quote_only\\\",\\\"timingText\\\":\\\"City - timing confirmed in your proposal\\\"},{\\\"id\\\":\\\"gyantse\\\",\\\"name\\\":\\\"Gyantse\\\",\\\"icon\\\":\\\"\\\",\\\"must\\\":\\\"Pelkor Chode and the Kumbum\\\",\\\"rec\\\":\\\"\\\",\\\"intro\\\":\\\"Shigatse, Tibet; Kumbum and Pelkor Chode. Route details are confirmed in your proposal.\\\",\\\"img\\\":\\\"https://cdn.shopify.com/s/files/1/0748/7419/2040/t/31/assets/ct-dayfill-20260722-94a573477804b990.webp?v=1784667855\\\",\\\"planningMode\\\":\\\"quote_only\\\",\\\"timingText\\\":\\\"Town / local destination - timing confirmed in your proposal\\\"},{\\\"id\\\":\\\"shigatse\\\",\\\"name\\\":\\\"Shigatse\\\",\\\"icon\\\":\\\"\\\",\\\"must\\\":\\\"Tashilhunpo and central Tibet heritage\\\",\\\"rec\\\":\\\"\\\",\\\"intro\\\":\\\"Tibet; Tashilhunpo and central Tibet circuit. Route details are confirmed in your proposal.\\\",\\\"img\\\":\\\"https://cdn.shopify.com/s/files/1/0748/7419/2040/t/31/assets/ct-dayfix-20260715-21fac612e004be86.webp?v=1784087348\\\",\\\"planningMode\\\":\\\"quote_only\\\",\\\"timingText\\\":\\\"City - timing confirmed in your proposal\\\"},{\\\"id\\\":\\\"lanzhou\\\",\\\"name\\\":\\\"Lanzhou\\\",\\\"icon\\\":\\\"\\\",\\\"must\\\":\\\"Yellow River city and Hexi Corridor gateway\\\",\\\"rec\\\":\\\"\\\",\\\"intro\\\":\\\"Gansu; Yellow River and Hexi corridor gateway. Route details are confirmed in your proposal.\\\",\\\"img\\\":\\\"https://cdn.shopify.com/s/files/1/0748/7419/2040/t/31/assets/ct-dayfill-20260722-2d91e87f051684a4.webp?v=1784667698\\\",\\\"planningMode\\\":\\\"quote_only\\\",\\\"timingText\\\":\\\"City - timing confirmed in your proposal\\\"},{\\\"id\\\":\\\"jiayuguan\\\",\\\"name\\\":\\\"Jiayuguan\\\",\\\"icon\\\":\\\"\\\",\\\"must\\\":\\\"Great Wall fortress and Hexi Corridor heritage\\\",\\\"rec\\\":\\\"\\\",\\\"intro\\\":\\\"Gansu; city and Great Wall fortress in Hexi corridor. Route details are confirmed in your proposal.\\\",\\\"img\\\":\\\"https://cdn.shopify.com/s/files/1/0748/7419/2040/t/31/assets/ct-dayfill-20260722-6791780e5c97164b.webp?v=1784667804\\\",\\\"planningMode\\\":\\\"quote_only\\\",\\\"timingText\\\":\\\"City - timing confirmed in your proposal\\\"},{\\\"id\\\":\\\"xishuangbanna\\\",\\\"name\\\":\\\"Xishuangbanna\\\",\\\"icon\\\":\\\"\\\",\\\"must\\\":\\\"Dai villages and Mengla rainforest\\\",\\\"rec\\\":\\\"\\\",\\\"intro\\\":\\\"Southern Yunnan; Dai villages and Mengla rainforest. Route details are confirmed in your proposal.\\\",\\\"img\\\":\\\"https://cdn.shopify.com/s/files/1/0748/7419/2040/t/31/assets/ct-dayfill-20260722-ad2afd6d3396776e.webp?v=1784667885\\\",\\\"planningMode\\\":\\\"quote_only\\\",\\\"timingText\\\":\\\"Region - timing confirmed in your proposal\\\"},{\\\"id\\\":\\\"puer\\\",\\\"name\\\":\\\"Pu'er\\\",\\\"icon\\\":\\\"\\\",\\\"must\\\":\\\"Tea forests and tea-producing villages\\\",\\\"rec\\\":\\\"\\\",\\\"intro\\\":\\\"Yunnan; tea forests and producing villages. Route details are confirmed in your proposal.\\\",\\\"img\\\":\\\"https://cdn.shopify.com/s/files/1/0748/7419/2040/t/31/assets/ct-dayfix-20260715-7ffa11b36ae9ad76.webp?v=1784087484\\\",\\\"planningMode\\\":\\\"quote_only\\\",\\\"timingText\\\":\\\"City - timing confirmed in your proposal\\\"},{\\\"id\\\":\\\"yuanyang\\\",\\\"name\\\":\\\"Yuanyang\\\",\\\"icon\\\":\\\"\\\",\\\"must\\\":\\\"Hani rice terraces and village landscapes\\\",\\\"rec\\\":\\\"\\\",\\\"intro\\\":\\\"Honghe, Yunnan; Hani terraces at Duoyishu/Laohuzui. Route details are confirmed in your proposal.\\\",\\\"img\\\":\\\"https://chinatourly.com/cdn/shop/t/27/assets/ct-day-yuanyang.jpg\\\",\\\"planningMode\\\":\\\"quote_only\\\",\\\"timingText\\\":\\\"Town / local destination - timing confirmed in your proposal\\\"},{\\\"id\\\":\\\"changsha\\\",\\\"name\\\":\\\"Changsha\\\",\\\"icon\\\":\\\"\\\",\\\"must\\\":\\\"Hunan culture and regional route connections\\\",\\\"rec\\\":\\\"\\\",\\\"intro\\\":\\\"Hunan capital; Zhangjiajie-Fenghuang route gateway. Route details are confirmed in your proposal.\\\",\\\"img\\\":\\\"https://cdn.shopify.com/s/files/1/0748/7419/2040/t/31/assets/ct-dayfill-20260722-a713b107740eaa88.webp?v=1784667871\\\",\\\"planningMode\\\":\\\"quote_only\\\",\\\"timingText\\\":\\\"City - timing confirmed in your proposal\\\"},{\\\"id\\\":\\\"fenghuang\\\",\\\"name\\\":\\\"Fenghuang\\\",\\\"icon\\\":\\\"\\\",\\\"must\\\":\\\"Tuojiang riverside old town and traditional streets\\\",\\\"rec\\\":\\\"\\\",\\\"intro\\\":\\\"Xiangxi, Hunan; Tuojiang riverside old town. Route details are confirmed in your proposal.\\\",\\\"img\\\":\\\"https://cdn.shopify.com/s/files/1/0748/7419/2040/t/31/assets/ct-dayfix-20260715-f22122d418226f54.webp?v=1784087600\\\",\\\"planningMode\\\":\\\"quote_only\\\",\\\"timingText\\\":\\\"Town / local destination - timing confirmed in your proposal\\\"}];\\n// Generated into both existing planners from the same build-time source.\\nconst CT_DESTINATION_MOBILE = true;\\nfunction ctEscape(value) {\\n  return String(value == null ? '' : value).replace(/[&\\u003c>\\\"']/g, ch => ({'&':'&amp;','\\u003c':'&lt;','>':'&gt;','\\\"':'&quot;',\\\"'\\\":'&#39;'}[ch]));\\n}\\nfunction ctQuoteOnly() {\\n  return STATE.cities.some(id => { const city = CITIES.find(c => c.id === id); return !city || city.planningMode === 'quote_only'; });\\n}\\nfunction ctValidDestinations() {\\n  return STATE.cities.length > 0 && STATE.cities.every(id => CITIES.some(c => c.id === id));\\n}\\nfunction ctQuoteBrief() {\\n  if (!ctQuoteOnly() || !ctValidDestinations()) throw new Error('Review destination selection before continuing');\\n  const brief = {source:'bespoke-planner-review', total:'Planner quote required; no calculated or confirmed trip amount',\\n    reason:'Confirm route sequence, nights, transfers, admissions, activities and full price in a written proposal.'};\\n  ['party','travellers','days','pace','dates','travelNotes','defaultHotel','defaultTransport','defaultMeal'].forEach(key => {\\n    if (STATE[key] !== undefined) brief[key] = STATE[key];\\n  });\\n  brief.interests = Array.from(STATE.interests || []);\\n  brief.cities = STATE.cities.map(id => CITIES.find(c => c.id === id).name);\\n  brief.requestedStops = brief.cities.map((destination, index) => ({sequencePreference:index+1, destination}));\\n  // Carry only explicit user edits from an earlier draft, never its calculated costs or times.\\n  brief.dayRequests = Object.entries(STATE.perDay || {}).flatMap(([day, value]) => {\\n    const editedRequests = (value.schedule || []).filter(row => row.modified || row.skipped)\\n      .map(row => ({requestedTitle:row.title, skipped:Boolean(row.skipped)}));\\n    const activityRequests = Array.from(value.activities || []);\\n    if (!editedRequests.length && !activityRequests.length && !value.notes) return [];\\n    return [{priorDraftDay:day, status:'User requests only; reassign after route planning', notes:value.notes || '', activityRequests, editedRequests}];\\n  });\\n  return brief;\\n}\\nfunction ctQuoteReview() {\\n  const m = CT_DESTINATION_MOBILE;\\n  const preference = (label, items, type) => `\\u003cdiv class=\\\"${m?'def-group':'mt-4'}\\\">\\u003cdiv class=\\\"${m?'def-k':'section-label'}\\\">${label}\\u003c/div>\\u003cdiv class=\\\"${m?'':'grid grid-cols-1 md:grid-cols-3 gap-2'}\\\">${items.map(item => {\\n    const selected = STATE['default'+type[0].toUpperCase()+type.slice(1)] === item.id;\\n    const attr = m ? `data-def=\\\"${type}:${item.id}\\\"` : `data-def${type}=\\\"${item.id}\\\"`;\\n    return `\\u003cdiv class=\\\"${m?'opt':'opt-card'} ${selected?'is-on':''}\\\" ${attr}>\\u003cdiv class=\\\"${m?'opt__body':'flex-1 min-w-0'}\\\">\\u003cdiv class=\\\"${m?'opt__title':'opt-title'}\\\">${ctEscape(item.title)}\\u003c/div>\\u003cdiv class=\\\"${m?'opt__sub':'opt-sub'}\\\">Preference only; confirmed in your proposal\\u003c/div>\\u003c/div>\\u003c/div>`;\\n  }).join('')}\\u003c/div>\\u003c/div>`;\\n  const stops = STATE.cities.map((id, index) => {\\n    const city = CITIES.find(c => c.id === id);\\n    if (!city) return '';\\n    return `\\u003cdiv class=\\\"iti-day\\\" data-quote-stop=\\\"${ctEscape(id)}\\\">\\u003cdiv class=\\\"iti-day__img\\\" style=\\\"background-image:url('${ctEscape(city.img)}')\\\">\\u003cspan aria-hidden=\\\"true\\\">\\u003c/span>\\u003c/div>\\u003cdiv class=\\\"${m?'iti-day__b':'iti-day__body'}\\\">\\u003cspan class=\\\"${m?'iti-day__k':'section-label'}\\\">Preference ${index+1}\\u003c/span>\\u003ch3 class=\\\"${m?'iti-day__acts':'font-medium'}\\\"${m?'':' style=\\\"font-size:18px;line-height:1.4;margin:8px 0\\\"'}>${ctEscape(city.name)}\\u003c/h3>\\u003cp class=\\\"${m?'lede':'text-[color:var(--mute)]'}\\\"${m?'':' style=\\\"font-size:14px;line-height:1.5;margin:0\\\"'}>${ctEscape(city.must)}\\u003c/p>\\u003c/div>\\u003c/div>`;\\n  }).join('');\\n  return `\\u003cdiv class=\\\"step-pop ${m?'':'step-container'}\\\" data-ct-quote-review>\\u003cspan class=\\\"${m?'eyebrow':'step-eyebrow'}\\\">Step 7 of 7\\u003c/span>\\u003ch2 class=\\\"${m?'title':'step-title'}\\\">Your \\u003cem>route request\\u003c/em>\\u003c/h2>\\u003cp class=\\\"${m?'lede':'step-lede'}\\\">Planner quote required. Route order, nights and transfers will be confirmed in your proposal.\\u003c/p>\\u003cspan class=\\\"${m?'rule':'step-rule'}\\\">\\u003c/span>\\u003cdiv class=\\\"${m?'defaults':'mb-6'}\\\">${preference('Hotel tier',HOTELS,'hotel')}${preference('Transport',TRANSPORTS,'transport')}${preference('Dining',MEALS,'meal')}\\u003c/div>\\u003cspan class=\\\"${m?'sec-label':'section-label'}\\\">Preferred stop order\\u003c/span>${stops}\\u003c/div>`;\\n}\\nfunction ctQuoteCopy() {\\n  const m = CT_DESTINATION_MOBILE;\\n  const area = document.getElementById('stepArea');\\n  if (!area) return;\\n  if (STATE.step === 1) {\\n    const lede = area.querySelector(m?'.lede':'.step-lede');\\n    if (lede) lede.textContent = \\\"Add each traveller's age, dietary and accessibility needs. Rooming and the full party price will be confirmed in your proposal.\\\";\\n    const count = area.querySelector(m?'.tr-count__meta':'.tr-count-card .text-xs');\\n    if (count) count.textContent = 'Party pricing confirmed in your proposal';\\n    area.querySelectorAll('.tr-row__free').forEach(el => {el.textContent='';});\\n  }\\n  if (STATE.step === 2) {\\n    const lede = area.querySelector(m?'.lede':'.step-lede');\\n    if (lede) lede.textContent = 'Requested trip length. The planner will confirm feasible routing and nights at each stop.';\\n    const hint = document.getElementById('daysHint');\\n    if (hint) hint.textContent = 'Requested duration, not a confirmed itinerary';\\n  }\\n  if (STATE.step === 3) {\\n    const copy = {handson:'Active pace preference',cultural:'Balanced pace preference',insider:'Slower pace preference'};\\n    area.querySelectorAll('[data-pick^=\\\"pace:\\\"]').forEach(el => {\\n      const sub = el.querySelector(m?'.mcard__sub':'.choice-sub');\\n      const meta = el.querySelector(m?'.mcard__meta':'.choice-meta');\\n      if (sub) sub.textContent = copy[el.dataset.pick.split(':')[1]] || 'Pace preference';\\n      if (meta) meta.textContent = 'Activities and timing confirmed in your proposal';\\n    });\\n  }\\n  if (STATE.step === 5) {\\n    const banner = area.querySelector(m?'.rec-banner':'.bg-\\\\\\\\[color\\\\\\\\:var\\\\\\\\(--gold-bg\\\\\\\\)\\\\\\\\]');\\n    if (banner) banner.remove();\\n  }\\n}\\nfunction ctUpdateQuoteBrief() {\\n  const m = CT_DESTINATION_MOBILE;\\n  const entries = [['Travellers',STATE.travellers.length], ['Requested length',STATE.days+' days'],\\n    ['Preferred stops',STATE.cities.map(id => CITIES.find(c => c.id === id)?.name || 'Unavailable destination').join(' \u00B7 ')]];\\n  if (STATE.pace) entries.push(['Pace',PACES.find(p => p.id===STATE.pace)?.title || STATE.pace]);\\n  if (STATE.interests.size) entries.push(['Interests',Array.from(STATE.interests).map(id => INTERESTS.find(i=>i.id===id)?.title || id).join(' \u00B7 ')]);\\n  const notes = STATE.travellers.reduce((n,t)=>n+(t.notes || []).length,0)+(STATE.travelNotes.trim()?1:0);\\n  if (notes) entries.push(['Notes',notes+' flagged']);\\n  document.getElementById('briefList').innerHTML = entries.map(([key,value]) => m\\n    ? `\\u003cdiv class=\\\"brief-row\\\">\\u003cspan class=\\\"brief-row__k\\\">${ctEscape(key)}\\u003c/span>\\u003cspan class=\\\"brief-row__v\\\">${ctEscape(value)}\\u003c/span>\\u003c/div>`\\n    : `\\u003cdiv class=\\\"flex justify-between gap-3 py-2.5 border-b border-[color:var(--rule)]\\\">\\u003cspan class=\\\"text-[10px] uppercase text-[color:var(--mute)] font-bold\\\">${ctEscape(key)}\\u003c/span>\\u003cspan class=\\\"text-right text-sm font-medium\\\">${ctEscape(value)}\\u003c/span>\\u003c/div>`).join('');\\n  const score = Math.round(((STATE.party?1:0)+(STATE.pace?1:0)+(STATE.interests.size?1:0)+(ctValidDestinations()?1:0))/4*100);\\n  document.getElementById('briefScore').textContent = score + (m?'%':'% complete');\\n  if (m) document.getElementById('briefScore2').textContent = score + '% complete';\\n  document.getElementById('briefHeadline').textContent = ctValidDestinations() ? 'Planner review required' : 'Review destination selection';\\n  const total = document.getElementById('priceTotal');\\n  if (!total.hasAttribute('data-ct-original-style')) total.setAttribute('data-ct-original-style',total.getAttribute('style') || '');\\n  total.textContent = 'Planner quote required';\\n  total.style.fontSize = m?'14px':'22px';\\n  total.style.lineHeight = '1.35';\\n  total.style.whiteSpace = 'normal';\\n  document.getElementById(m?'priceBreak':'priceBreakdown').textContent = 'No calculated price; timing and inclusions confirmed in your proposal.';\\n  if (!m) {\\n    const button = document.getElementById('sendInquiry');\\n    button.disabled = !(score===100 && ctValidDestinations());\\n    button.onclick = () => { if (ctQuoteOnly() && ctValidDestinations() && window.CTCommerceBrief) window.CTCommerceBrief.go(ctQuoteBrief(),button); };\\n  }\\n  ctQuoteCopy();\\n}\\nfunction ctRestorePriceStyle() {\\n  const total = document.getElementById('priceTotal');\\n  if (total.hasAttribute('data-ct-original-style')) {\\n    total.setAttribute('style',total.getAttribute('data-ct-original-style'));\\n    total.removeAttribute('data-ct-original-style');\\n    if (!CT_DESTINATION_MOBILE) document.getElementById('sendInquiry').onclick = null;\\n  }\\n}\\n\\n// Activity prices = (real ticket / experience cost) \u00D7 1.35 markup. Per-person surcharge.\\n// STANDARD DAY-BY-DAY ITINERARY \u2014 what the guide does each day if no extras chosen\\n// Keyed by cityId. Each city has an array of day templates. If the trip has more\\n// days in a city than templates, the last template's \\\"Free exploration\\\" variant is used.\\n// Each row: {time, title, dur(min), loc, warn, alts:[strings], flex(false=transit/fixed)}\\nconst STANDARD_DAY_PLAN = {\\n  beijing:[\\n    [ {time:'06:00', title:'Tiananmen Square flag-raising ceremony', dur:60, loc:'Tiananmen',\\n       warn:'Flag-raising ONLY happens at sunrise (~06:00 summer / ~07:30 winter). If you move past sunrise, the ceremony will be over.',\\n       alts:['Sleep in \u2014 skip the flag, start at 09:30 with Forbidden City','Replace with Temple of Heaven morning tai-chi','Beihai Park lakeside walk + imperial garden']},\\n      {time:'08:00', title:'Hotel breakfast + freshen up', dur:90, alts:['Skip \u2014 start sightseeing earlier','Coffee at a hutong caf\u00E9','Morning jog at Beihai Park']},\\n      {time:'09:30', title:'Forbidden City (Meridian Gate \u2192 Imperial Garden full walk)', dur:240, loc:'Forbidden City',\\n       alts:['Add Treasure Gallery + Clock Hall (+1 hr)','Add private curator-led restricted halls (VIP upgrade)']},\\n      {time:'13:30', title:'Lunch \u00B7 Peking duck at Da Dong', dur:90, loc:'Wangfujing',\\n       alts:['Quanjude duck (more traditional)','Siji Minfu duck (locals\\\\' favourite)','Made in China (modern Chinese)','Skip lunch + continue']},\\n      {time:'15:30', title:'Old hutong walking tour + courtyard tea', dur:120, loc:'Nanluoguxiang',\\n       alts:['798 Art District (modern art)','Liulichang antique street','Wangfujing pedestrian street']},\\n      {time:'19:00', title:'Dinner \u00B7 regional cuisine', dur:90, alts:['Xinjiang lamb (Crescent Moon)','Yunnan rice noodles','Imperial cuisine at Fangshan']},\\n    ],\\n    [ {time:'07:30', title:'Depart for Mutianyu Great Wall (~1.5 hr drive)', dur:90, flex:false,\\n       warn:'Earlier = far fewer crowds. After 10:30 the cable-car queue can hit 45+ min in peak season.'},\\n      {time:'09:00', title:'Great Wall hike (Towers 6-20) + cable car up & down', dur:180, loc:'Mutianyu',\\n       alts:['Jinshanling Wall (wilder, less crowded, 2.5 hr drive)','Badaling Wall (closest, busiest)','Add private overnight in watchtower (ULTRA upgrade)']},\\n      {time:'12:30', title:'Farmhouse lunch near the wall', dur:60},\\n      {time:'13:30', title:'Return drive to Beijing', dur:90, flex:false},\\n      {time:'15:30', title:'Olympic Bird\\\\'s Nest + Water Cube exterior', dur:90, loc:'Olympic Park',\\n       alts:['Workers\\\\' Stadium nightlife district','Sanlitun shopping','Skip and rest at hotel']},\\n      {time:'19:00', title:'Dinner + free evening', dur:120, alts:['Peking Opera at Mei Lanfang Theatre (book ahead)','Chaoyang acrobatics show','Quiet hotel evening']},\\n    ],\\n    [ {time:'08:30', title:'Summer Palace + Marble Boat + Kunming Lake walk', dur:180, loc:'Summer Palace'},\\n      {time:'12:30', title:'Lunch \u00B7 royal-style at Tingliguan', dur:90, alts:['Tingliguan (in Summer Palace)','Quanjude branch','Local noodle shop']},\\n      {time:'14:30', title:'Temple of Heaven (Round Mound + Hall of Prayer)', dur:120, loc:'Temple of Heaven',\\n       warn:'Tai-chi practice happens 06:00-08:00. If you want to see it, swap this to tomorrow morning.'},\\n      {time:'17:00', title:'Liulichang antique street walking', dur:90, alts:['Panjiayuan antique market (weekends only)','798 Art District','Skip and free time']},\\n      {time:'19:30', title:'Peking Opera evening (Mei Lanfang Theatre)', dur:120, alts:['Acrobatics show at Chaoyang','Free evening','Beijing kung-fu legend show']},\\n    ],\\n  ],\\n  shanghai:[\\n    [ {time:'09:00', title:'Hotel breakfast + start', dur:60},\\n      {time:'10:00', title:'The Bund walking promenade \u00B7 colonial-era architecture', dur:90, loc:'Bund'},\\n      {time:'11:30', title:'Pudong skyline \u00B7 Jin Mao or SWFC viewing platform', dur:90, alts:['Shanghai Tower observation deck','Skip and add Yu Garden time']},\\n      {time:'13:00', title:'Lunch \u00B7 Xiao Long Bao at Jia Jia Tang Bao or Din Tai Fung', dur:75, alts:['Yang\\\\'s Fry-Dumpling','Lao Zheng Xing (Shanghainese)']},\\n      {time:'14:30', title:'Yu Garden + Old Town + Huxinting tea house', dur:150, loc:'Old Town'},\\n      {time:'17:30', title:'French Concession longtang walk + boutiques', dur:120, loc:'Tianzifang'},\\n      {time:'19:30', title:'Dinner + Bund night view (Pudong lights from west bank)', dur:120, alts:['Sky-bar dinner with view','Old Jazz Band at Peace Hotel','Quiet local restaurant']},\\n    ],\\n    [ {time:'09:30', title:'Shanghai Museum (People\\\\'s Square)', dur:180, loc:'People\\\\'s Square',\\n       warn:'Closed Mondays. If your day 2 falls on Monday, swap with day 1.'},\\n      {time:'12:30', title:'Lunch \u00B7 Xintiandi area', dur:90},\\n      {time:'14:00', title:'Xintiandi shikumen + Site of First CCP Congress', dur:120, alts:['M50 art zone','Power Station of Art','Jing\\\\'an Temple']},\\n      {time:'16:30', title:'Nanjing Road pedestrian street shopping', dur:120, alts:['IFC Mall (luxury)','Tianzifang (boutique)','Skip and return early']},\\n      {time:'19:00', title:'Huangpu River night cruise (1 hr)', dur:90, alts:['Sky-bar at Cloud-9 Jin Mao','ERA acrobatics show','Free evening']},\\n    ],\\n  ],\\n  xian:[\\n    [ {time:'08:30', title:'Depart for Terracotta Army (~45 min drive)', dur:45, flex:false},\\n      {time:'09:30', title:'Terracotta Army \u00B7 Pits 1, 2, 3 + bronze chariots museum', dur:180, loc:'Lintong',\\n       warn:'Earlier = fewer tour groups. After 11:00 Pit 1 viewing platform gets very crowded.',\\n       alts:['Add VIP behind-the-rope close access','Add archaeologist-led private session','Replace afternoon with Famen Temple (need full day)']},\\n      {time:'13:00', title:'Lunch \u00B7 local Shaanxi noodles', dur:75, alts:['Biang biang noodles','Roujiamo (Chinese hamburger) tasting']},\\n      {time:'15:00', title:'Big Wild Goose Pagoda + fountain square', dur:90, loc:'Big Wild Goose'},\\n      {time:'17:00', title:'Shaanxi History Museum (FREE ticket, must reserve)', dur:120, loc:'Museum District',\\n       warn:'Limited free tickets per day \u00B7 standard tour pre-reserves a slot. Don\\\\'t move past 18:00 (museum closes).'},\\n      {time:'19:30', title:'Dumpling banquet + Tang Dynasty Show', dur:150, alts:['Skip show, free evening','Hui Quarter street-food walk','Tang Dance VIP first-row upgrade']},\\n    ],\\n    [ {time:'09:00', title:'City Wall walking or cycling (top of wall, 14 km loop)', dur:150, loc:'City Wall'},\\n      {time:'12:30', title:'Lunch \u00B7 Hui Muslim Quarter street food', dur:90, loc:'Hui Quarter'},\\n      {time:'14:30', title:'Great Mosque + Hui Quarter walking', dur:120, alts:['Bell + Drum Tower interior climb','Beilin Stele Museum (calligraphy)']},\\n      {time:'17:00', title:'Bell + Drum Tower exterior view', dur:60, alts:['Beilin Stele Museum + take-home rubbing','Free time at hotel']},\\n      {time:'19:00', title:'Dinner + traditional tea house performance', dur:120},\\n    ],\\n  ],\\n  chengdu:[\\n    [ {time:'07:00', title:'Depart for Giant Panda Base (early start = pandas more active)', dur:45, flex:false,\\n       warn:'Pandas are MOST active 08:30-10:00. After 11:00 most are sleeping in the shade.'},\\n      {time:'07:45', title:'Giant Panda Base \u00B7 main enclosures + nursery', dur:180, loc:'Panda Base',\\n       alts:['Add Panda Keeper-for-a-day experience (VIP, +$580)','Add 06:30 pre-opening private slot (VIP)']},\\n      {time:'11:30', title:'Return to city + lunch', dur:90, alts:['Chen Mapo Tofu (the original)','Long Chao Shou dumpling house','Skip lunch and continue']},\\n      {time:'14:00', title:'Wenshu Monastery + tea garden', dur:120, loc:'Wenshu',\\n       alts:['Daci Temple (downtown)','Qingyang Taoist Temple','Skip and free shopping']},\\n      {time:'16:30', title:'Jinli Ancient Street walking + snacks', dur:90, loc:'Jinli'},\\n      {time:'19:00', title:'Sichuan hot pot dinner + Sichuan Opera (face-changing)', dur:150,\\n       alts:['Skip opera, just hot pot','Private Master Hu chef-anchor (PRIVATE add-on)','Backstage face-changing private lesson']},\\n    ],\\n    [ {time:'09:00', title:'People\\\\'s Park tea house + observe local life', dur:120, loc:'People\\\\'s Park',\\n       warn:'Mornings have the most locals. After 14:00 it\\\\'s much quieter \u2014 lose the atmosphere.'},\\n      {time:'11:30', title:'Lunch \u00B7 Sichuan home-style', dur:90},\\n      {time:'13:30', title:'Kuanzhai Alley walking + boutique tea shops', dur:120, loc:'Kuanzhai',\\n       alts:['Day trip to Mt Qingcheng + Dujiangyan (full day, replaces afternoon)','Du Fu\\\\'s Thatched Cottage']},\\n      {time:'16:30', title:'Sichuan Cuisine Museum + cooking demo', dur:120, alts:['Free shopping at Chunxi Road','IFS rooftop panda + sunset view','Skip and rest']},\\n      {time:'19:30', title:'Casual local dinner + free evening', dur:90},\\n    ],\\n  ],\\n  guilin:[\\n    [ {time:'07:30', title:'Hotel breakfast + depart for Zhujiang Pier', dur:60, flex:false},\\n      {time:'09:00', title:'Li River 4-hour cruise (Guilin \u2192 Yangshuo)', dur:240, loc:'Li River',\\n       warn:'The river\\\\'s most famous bends are 2-3 hrs in. Don\\\\'t rush back to the cabin for lunch \u2014 eat on deck.',\\n       alts:['Photographer\\\\'s private dawn boat (PRIVATE, depart 05:30)','Half-cruise + drive (saves 2 hrs)']},\\n      {time:'13:30', title:'Arrive Yangshuo + lunch by the river', dur:75, alts:['West Street local restaurants','Hotel-style']},\\n      {time:'15:00', title:'West Street walking + Liu Sanjie statue', dur:90, loc:'West Street'},\\n      {time:'17:00', title:'Yulong River countryside cycling (3 hrs return)', dur:180, alts:['Bamboo raft on Yulong (relaxed alternative)','Skip and rest']},\\n      {time:'20:30', title:'Impression Liu Sanjie show (Zhang Yimou production)', dur:90, alts:['Skip show, free evening','VIP box upgrade (VIP add-on)']},\\n    ],\\n    [ {time:'09:00', title:'Reed Flute Cave (200M-year-old karst formations)', dur:120, loc:'Reed Flute Cave'},\\n      {time:'12:00', title:'Lunch \u00B7 Guilin rice noodles (the real thing)', dur:60},\\n      {time:'13:30', title:'Elephant Trunk Hill + Li River bank walk', dur:90, alts:['Solitary Beauty Peak (climb)','Seven Stars Park']},\\n      {time:'15:30', title:'Free time \u00B7 tea house or massage', dur:120, alts:['Longji terraces day-trip (+full day extension)','Cormorant fishing private demo']},\\n      {time:'19:00', title:'Casual dinner + free evening', dur:90},\\n    ],\\n  ],\\n  lhasa:[\\n    [ {time:'09:00', title:'Slow acclimatisation morning at hotel (altitude 3,650 m)', dur:120, flex:false,\\n       warn:'On arrival day DO NOT exert. Avoid alcohol. Drink 3 L water. Symptoms peak 24-48 h after arrival.'},\\n      {time:'11:30', title:'Light lunch (low-fat, hydrate)', dur:60},\\n      {time:'13:30', title:'Potala Palace \u00B7 audio-guided full circuit', dur:120, loc:'Potala',\\n       warn:'Standard tickets limit you to 1 hr inside the White & Red Palaces. Move briskly.',\\n       alts:['Add private monk-led ritual circuit (VIP)','Move to morning slot tomorrow']},\\n      {time:'16:00', title:'Potala Square sunset photography + kora', dur:60},\\n      {time:'18:00', title:'Early dinner \u00B7 Tibetan home-style + free evening rest', dur:120},\\n    ],\\n    [ {time:'09:00', title:'Jokhang Temple + Barkhor Street kora (clockwise)', dur:180, loc:'Jokhang',\\n       warn:'Pilgrims circuit clockwise. Join the flow \u2014 never walk against it.'},\\n      {time:'12:30', title:'Lunch \u00B7 Tibetan noodles or sweet tea house', dur:90},\\n      {time:'14:30', title:'Sera Monastery \u00B7 afternoon monk debate (15:00-17:00)', dur:150, loc:'Sera',\\n       warn:'Debate is ONLY 15:00-17:00 weekdays. Closed Sundays \u2014 if your day 2 is Sunday, swap with day 1.',\\n       alts:['Drepung Monastery (less crowded alternative)','Skip and free time']},\\n      {time:'18:30', title:'Dinner + butter tea + free evening', dur:90, alts:['Norbulingka Summer Palace visit','Free shopping at Barkhor','Hotel rest']},\\n    ],\\n  ],\\n  lijiang:[\\n    [ {time:'09:00', title:'Lijiang Old Town walking circuit + Square Street', dur:180, loc:'Old Town',\\n       warn:'Most touristy in afternoon. Mornings are quieter and more authentic.'},\\n      {time:'12:30', title:'Lunch \u00B7 Naxi local restaurant', dur:90},\\n      {time:'14:30', title:'Black Dragon Pool + Yulong Snow Mountain view', dur:120, loc:'Black Dragon Pool',\\n       alts:['Mu Family Mansion (historic residence)','Wangu Tower viewpoint']},\\n      {time:'17:30', title:'Shuhe Old Town walk (quieter than Lijiang)', dur:90, loc:'Shuhe'},\\n      {time:'19:30', title:'Naxi music orchestra performance', dur:90, alts:['Naxi cultural dinner show','Skip and free evening','Front-row VIP upgrade']},\\n    ],\\n    [ {time:'07:30', title:'Early depart for Yulong Snow Mountain (~1 hr drive, queue can be long)', dur:60, flex:false,\\n       warn:'Cable car opens 08:30. After 10:00 queues can hit 1+ hr. Earlier = faster.'},\\n      {time:'09:00', title:'Yulong Snow cable car (Glacier Park, 4,506 m)', dur:240, loc:'Yulong Snow',\\n       warn:'Altitude 4,506 m at top. Bring oxygen can. Don\\\\'t rush.',\\n       alts:['Heli access bypass queue (ULTRA add-on)','Spruce Meadow + Yak Meadow (lower altitude)']},\\n      {time:'14:00', title:'Late lunch + return to Lijiang', dur:90},\\n      {time:'16:00', title:'Free time at hotel \u00B7 spa', dur:120, alts:['Tiger Leaping Gorge half-day trek','Naxi shaman ceremony private']},\\n      {time:'19:00', title:'Dinner + free evening', dur:90},\\n    ],\\n  ],\\n  hangzhou:[\\n    [ {time:'09:00', title:'West Lake walking circuit \u00B7 Su Causeway + Bai Causeway', dur:180, loc:'West Lake'},\\n      {time:'12:30', title:'Lunch \u00B7 Lou Wai Lou (the famous lakeside restaurant)', dur:90},\\n      {time:'14:30', title:'West Lake boat ride \u00B7 Mid-Lake Pavilion + Three Pools Mirroring the Moon', dur:120, loc:'West Lake',\\n       alts:['Private rowing with poet companion (PRIVATE add-on)','Skip boat and bike around the lake']},\\n      {time:'17:30', title:'Leifeng Pagoda sunset view', dur:90, loc:'Leifeng',\\n       warn:'Pagoda closes 17:30 winter / 19:00 summer. Check season before moving past 17:00.'},\\n      {time:'19:30', title:'Dinner \u00B7 Impression West Lake show option', dur:120, alts:['Impression West Lake (Zhang Yimou, summer only)','Hefang Street walk + casual dinner','Free evening']},\\n    ],\\n    [ {time:'09:00', title:'Lingyin Temple + Feilai Feng grottoes (Buddhist circuit)', dur:180, loc:'Lingyin',\\n       warn:'Buy ticket for outer Feilai Feng + inner Lingyin Temple (separate tickets).'},\\n      {time:'12:30', title:'Lunch \u00B7 vegetarian temple food or local', dur:90},\\n      {time:'14:30', title:'Longjing tea plantation walk + tea farmer tasting', dur:120, loc:'Longjing Village',\\n       warn:'Pre-Qingming tea (early April) is the most prized. Off-season tastings still good but no plucking.'},\\n      {time:'17:00', title:'Tea Museum + free time', dur:90, alts:['Six Harmonies Pagoda + Qiantang River','Hefang Old Street','Skip and free']},\\n      {time:'19:30', title:'Dinner + free evening', dur:90},\\n    ],\\n  ],\\n};\\n\\n\\n\\n/* ---- freeTimeHints ---- */\\nfunction freeTimeHints(timeStr){\\n  const h = parseInt(timeStr||'10', 10);\\n  if (h \\u003c 9)  return ['Hotel breakfast','Morning jog at nearest park','Hotel spa or rest','Local caf\u00E9'];\\n  if (h \\u003c 12) return ['Local wet market visit','Caf\u00E9 break','Independent museum','Take a long walk'];\\n  if (h \\u003c 14) return ['Quick noodle shop','Hotel lunch','Picnic in park','Hotel pool'];\\n  if (h \\u003c 18) return ['Shopping street walking','Tea house','Boutique browsing','Hotel rest','Local massage'];\\n  if (h \\u003c 22) return ['Quiet dinner at hotel','Sky-bar drinks','Free evening at hotel','Local night-market','Casual local bar'];\\n  return ['Hotel sleep','Late jazz bar','Free evening'];\\n}\\n\\n\\n\\n/* ---- STANDARD_INCLUDED ---- */\\nconst STANDARD_INCLUDED = {\\n  beijing:[ 'Mutianyu Great Wall (standard daytime visit + cable car)','Forbidden City (Meridian Gate \u2192 Imperial Garden full walk)','Temple of Heaven','Tiananmen Square','Summer Palace + Marble Boat','Old hutong walking tour with English guide','Daily Peking Duck lunch at recommended house' ],\\n  shanghai:[ 'The Bund walking promenade + Pudong skyline viewing platform','Yu Garden + Old Town tour','French Concession longtang walk','Nanjing Road / Xintiandi','Shanghai Museum (People\\\\'s Square)','Daily English-speaking local guide' ],\\n  xian:[ 'Terracotta Army (standard ticket \u00B7 Pits 1, 2, 3)','Tang City Wall basic walk (top-of-wall stroll)','Bell Tower + Drum Tower exterior','Hui Muslim Quarter group food walk','Big Wild Goose Pagoda','Shaanxi History Museum (standard slot)' ],\\n  chengdu:[ 'Giant Panda Base (standard daytime visit)','Wenshu Monastery','Jinli Ancient Street','People\\\\'s Park tea-house culture','Standard Sichuan home-style dining','Kuanzhai Alley walking' ],\\n  guilin:[ 'Li River 4-hour cruise (Guilin \u2192 Yangshuo)','West Street Yangshuo','Reed Flute Cave','Elephant Trunk Hill','Standard Guilin rice-noodle breakfast','Yangshuo countryside cycling (group)' ],\\n  lhasa:[ 'Potala Palace (standard ticket + audio guide)','Jokhang Temple + Barkhor Street kora','Sera Monastery (afternoon monk debate viewing)','Norbulingka Summer Palace','Standard Tibetan dinner with butter tea','Tibet Permit + altitude support' ],\\n  lijiang:[ 'Lijiang Old Town walking circuit','Black Dragon Pool','Yulong Snow Mountain (standard cable car slot)','Shuhe Old Town walk','Standard Naxi music venue evening','Mu Family Mansion' ],\\n  hangzhou:[ 'West Lake walking circuit + Su Causeway','Lingyin Temple (standard visit)','Longjing tea plantation walk + farmer tasting','Hefang Old Street','Standard Hangzhou cuisine (Lou Wai Lou level)','Six Harmonies Pagoda exterior' ],\\n};\\n\\n/* ---- ACTIVITIES ---- */\\nconst ACTIVITIES = {\\n  beijing:[\\n    {id:'gw-heli',        label:'Great Wall helicopter access (Mutianyu private landing pad)',     cat:'arch',     tier:'ultra',   price:2400, icon:''},\\n    {id:'gw-overnight',   label:'Great Wall private watchtower banquet + overnight on the wall',  cat:'heritage', tier:'ultra',   price:1850, icon:''},\\n    {id:'fc-after',       label:'Forbidden City after-hours private access (post-closing, curator-led restricted halls)', cat:'arch', tier:'vip', price:720, icon:''},\\n    {id:'fc-treasure',    label:'Forbidden Treasure Gallery + Clock Hall VIP curator',            cat:'arch',     tier:'vip',     price:285, icon:''},\\n    {id:'toh-tea',        label:'Temple of Heaven dawn private + imperial tea ceremony',          cat:'heritage', tier:'private', price:245, icon:''},\\n    {id:'duck-chef',      label:'Da Dong private kitchen \u00B7 chef demo + sommelier pairing',        cat:'food',     tier:'vip',     price:480, icon:''},\\n    {id:'hutong-cricket', label:'Hutong cricket master + courtyard kung-fu private session',      cat:'heritage', tier:'private', price:380, icon:''},\\n    {id:'opera-front',    label:'Peking Opera VIP first-row + backstage makeup tour',             cat:'heritage', tier:'vip',     price:395, icon:''},\\n    {id:'calligraphy',    label:'Calligraphy in 1,000-yr-old courtyard with national-treasure master', cat:'heritage', tier:'private', price:580, icon:''},\\n    {id:'acrobat-vip',    label:'Chaoyang acrobat VIP box + meet performers',                     cat:'heritage', tier:'vip',     price:215, icon:''},\\n    {id:'panjiayuan',     label:'Panjiayuan antique market with private appraiser',               cat:'heritage', tier:'private', price:195, icon:''},\\n  ],\\n  shanghai:[\\n    {id:'bund-heli',      label:'Pudong skyline helicopter sunset tour',                          cat:'arch',     tier:'ultra',   price:2850, icon:''},\\n    {id:'huangpu-boat',   label:'Private speedboat on Huangpu (after-dark)',                      cat:'arch',     tier:'private', price:1450, icon:''},\\n    {id:'jazz-peace',     label:'Peace Hotel Old Jazz Band VIP table + curated whisky',           cat:'heritage', tier:'vip',     price:385, icon:''},\\n    {id:'michelin-3',     label:'Three-Michelin tasting (Ultraviolet / 8\u00BD Bombana)',              cat:'food',     tier:'ultra',   price:1450, icon:''},\\n    {id:'xlb-private',    label:'Din Tai Fung private dining room + chef Q&A',                    cat:'food',     tier:'private', price:295, icon:''},\\n    {id:'yu-after',       label:'Yu Garden after-hours private + lantern-lit tea ceremony',       cat:'heritage', tier:'vip',     price:365, icon:''},\\n    {id:'m50-studio',     label:'M50 private artist studio visit + commission preview',           cat:'heritage', tier:'private', price:285, icon:''},\\n    {id:'suzhou-pri',     label:'Suzhou private day-trip with master gardener guide',             cat:'arch',     tier:'private', price:580, icon:''},\\n    {id:'silk-master',    label:'China Silk Museum private weaver studio + Hanfu fitting',        cat:'heritage', tier:'private', price:380, icon:''},\\n    {id:'jinmao-cocktail',label:'Jin Mao Cloud-9 private window table + sommelier',               cat:'arch',     tier:'vip',     price:245, icon:''},\\n  ],\\n  xian:[\\n    {id:'tq-vip',         label:'Terracotta Army behind-the-rope (archaeologist-led, Pit 1 close access)', cat:'arch', tier:'vip', price:685, icon:''},\\n    {id:'tq-restorer',    label:'Private session with active warrior-restoration archaeologist',  cat:'heritage', tier:'private', price:485, icon:''},\\n    {id:'huashan-heli',   label:'Mt Huashan helicopter sunrise + private cable car',              cat:'scenery',  tier:'ultra',   price:1850, icon:''},\\n    {id:'wall-illum',     label:'City Wall after-dark private bike (gates closed to public)',     cat:'arch',     tier:'vip',     price:245, icon:''},\\n    {id:'tang-vip',       label:'Tang Dynasty Show VIP first-row + dumpling banquet',             cat:'heritage', tier:'vip',     price:285, icon:''},\\n    {id:'hui-chef',       label:'Hui Quarter chef-anchor private walk + lamb-skewer master',      cat:'food',     tier:'private', price:245, icon:''},\\n    {id:'beilin-rub',     label:'Beilin Museum private + take-home calligraphy rubbing',          cat:'heritage', tier:'private', price:295, icon:''},\\n    {id:'hanfu-shoot',    label:'Hanfu photoshoot at Daming Palace (props + makeup + photographer)', cat:'heritage', tier:'vip', price:385, icon:''},\\n    {id:'famen',          label:'Famen Temple Sui-Tang relic crypt VIP (book ahead)',             cat:'heritage', tier:'private', price:485, icon:''},\\n    {id:'bell-dawn',      label:'Bell Tower private dawn ringing ceremony',                       cat:'heritage', tier:'private', price:195, icon:''},\\n  ],\\n  chengdu:[\\n    {id:'panda-keeper',   label:'Panda Base \\\"keeper-for-a-day\\\" (clean bamboo, feed)',             cat:'scenery',  tier:'vip',     price:580, icon:''},\\n    {id:'panda-preopen',  label:'Panda Base pre-opening private 06:30 with researcher',           cat:'scenery',  tier:'vip',     price:385, icon:''},\\n    {id:'qingcheng-master',label:'Mt Qingcheng Taoist master meditation morning',                 cat:'heritage', tier:'private', price:285, icon:''},\\n    {id:'opera-backstage',label:'Sichuan Opera backstage face-changing private lesson',           cat:'heritage', tier:'private', price:295, icon:''},\\n    {id:'hotpot-master',  label:'Master Hu private chef-anchor hot pot dinner',                   cat:'food',     tier:'private', price:385, icon:''},\\n    {id:'mahjong',        label:'Sichuan mahjong tutor afternoon (3-hr private)',                 cat:'heritage', tier:'private', price:165, icon:'\uD83C\uDC04'},\\n    {id:'dujiangyan',     label:'Dujiangyan with hydraulic-engineering historian',                cat:'heritage', tier:'private', price:285, icon:''},\\n    {id:'jiuzhai-ext',    label:'Jiuzhaigou Valley premium extension (+1 day)',                   cat:'scenery',  tier:'ultra',   price:685, icon:''},\\n    {id:'emei-overnight', label:'Mt Emei monastery overnight + 03:30 sutra service',              cat:'heritage', tier:'private', price:580, icon:''},\\n    {id:'shu-brocade',    label:'Shu brocade master-weaver private studio + take-home piece',     cat:'heritage', tier:'private', price:245, icon:''},\\n  ],\\n  guilin:[\\n    {id:'li-photog',      label:'Li River photographer\\\\'s private dawn boat (NatGeo-trained)',     cat:'scenery',  tier:'private', price:485, icon:''},\\n    {id:'cormorant',      label:'Cormorant fishing private demonstration with elder fisherman',   cat:'heritage', tier:'private', price:285, icon:''},\\n    {id:'balloon',        label:'Hot-air balloon over karst peaks (sunrise)',                     cat:'scenery',  tier:'ultra',   price:685, icon:''},\\n    {id:'longji-master',  label:'Longji terraces with rice-planting master + village overnight',  cat:'scenery',  tier:'private', price:580, icon:''},\\n    {id:'climbing',       label:'Yangshuo private rock-climbing with international guide',        cat:'scenery',  tier:'private', price:385, icon:''},\\n    {id:'bamboo-sunset',  label:'Yulong bamboo raft sunset private + village dinner',             cat:'food',     tier:'private', price:245, icon:''},\\n    {id:'impression-vip', label:'Impression Liu Sanjie VIP box (Zhang Yimou production)',         cat:'heritage', tier:'vip',     price:285, icon:''},\\n    {id:'yulong-cycle',   label:'Yulong River villages private bike with local farmer',           cat:'scenery',  tier:'private', price:195, icon:''},\\n  ],\\n  lhasa:[\\n    {id:'potala-monk',    label:'Potala monk-led ritual circuit (restricted halls)',              cat:'heritage', tier:'vip',     price:485, icon:''},\\n    {id:'tibetan-med',    label:'Mentsikhang traditional Tibetan medicine consultation',          cat:'heritage', tier:'private', price:285, icon:''},\\n    {id:'thangka',        label:'Thangka painter-master private studio + take-home commission',   cat:'heritage', tier:'private', price:580, icon:''},\\n    {id:'yamdrok-photo',  label:'Yamdrok Lake private SUV with travel photographer',              cat:'scenery',  tier:'ultra',   price:685, icon:''},\\n    {id:'blessing',       label:'Private monk blessing ceremony at family monastery',             cat:'heritage', tier:'private', price:245, icon:''},\\n    {id:'norbu-after',    label:'Norbulingka after-hours private (Dalai Lama summer palace)',     cat:'arch',     tier:'vip',     price:385, icon:''},\\n    {id:'everest-bc',     label:'Everest Base Camp from Rongbuk (+3-day extension)',              cat:'scenery',  tier:'ultra',   price:2850, icon:''},\\n    {id:'namtso-heli',    label:'Nam Tso Lake helicopter day-trip',                               cat:'scenery',  tier:'ultra',   price:4850, icon:''},\\n  ],\\n  lijiang:[\\n    {id:'shaman',         label:'Naxi Dongba shaman private ceremony',                            cat:'heritage', tier:'private', price:380, icon:''},\\n    {id:'yulong-heli',    label:'Yulong Snow Mountain heli access (skip the cable queue)',        cat:'scenery',  tier:'ultra',   price:1450, icon:''},\\n    {id:'impression-lj',  label:'Impression Lijiang VIP box (Zhang Yimou production)',            cat:'heritage', tier:'vip',     price:295, icon:''},\\n    {id:'mosuo-ext',      label:'Lugu Lake Mosuo matrilineal village (+2-day extension)',         cat:'heritage', tier:'ultra',   price:1150, icon:''},\\n    {id:'puer-tasting',   label:'200-yr-old shop Pu-erh private vertical tasting',                cat:'food',     tier:'private', price:285, icon:''},\\n    {id:'orchestra-vip',  label:'Naxi Music Orchestra VIP front-row + meet director',             cat:'heritage', tier:'vip',     price:215, icon:''},\\n    {id:'bdp-dawn',       label:'Black Dragon Pool private dawn slot (closed to public)',         cat:'scenery',  tier:'private', price:195, icon:''},\\n    {id:'shuhe-leather',  label:'Shuhe leather-master + take-home commissioned piece',            cat:'heritage', tier:'private', price:285, icon:''},\\n  ],\\n  hangzhou:[\\n    {id:'wl-poet',        label:'West Lake dawn private rowing + classical poet companion',       cat:'scenery',  tier:'private', price:295, icon:''},\\n    {id:'silk-pri',       label:'China Silk Museum private weaver studio + Hanfu fitting',        cat:'heritage', tier:'private', price:285, icon:''},\\n    {id:'longjing-pluck', label:'Longjing pluck-your-own with national-treasure master + cellar tour', cat:'food', tier:'vip', price:385, icon:''},\\n    {id:'sixharm-night',  label:'Six Harmonies Pagoda private night + Qiantang tidal viewing',    cat:'arch',     tier:'private', price:215, icon:''},\\n    {id:'lingyin-sutra',  label:'Lingyin private sutra-chanting morning service mat',             cat:'heritage', tier:'private', price:285, icon:''},\\n    {id:'xixi-private',   label:'Xixi Wetland private boat + cormorant farmer',                   cat:'scenery',  tier:'private', price:195, icon:''},\\n    {id:'meijiawu',       label:'Mei Jia Wu tea-village heritage homestay overnight',             cat:'heritage', tier:'private', price:580, icon:''},\\n    {id:'yue-tomb',       label:'General Yue tomb private historian + Hangzhou-rebellion lecture',cat:'heritage', tier:'private', price:165, icon:''},\\n  ],\\n};\\n\\n/* ---- HOTELS/TRANSPORTS/MEALS ---- */\\n// Hotels \u2014 only base tier complimentary, premium tiers paid\\nconst HOTELS = [\\n  {id:'h4', icon:'', title:'4-star comfort',           sub:'Clean modern international \u00B7 breakfast', price:0, originalPrice:180, badge:'FREE'},\\n  {id:'h5', icon:'\u2B50', title:'5-star premium',            sub:'Top international luxury chain tier',     price:340},\\n  {id:'aman', icon:'', title:'Ultra-luxury \u00B7 heritage', sub:'Aman-tier \u00B7 boutique courtyard heritage', price:780},\\n];\\n// Transports \u2014 generic labels (no brand), category by tier\\nconst TRANSPORTS = [\\n  {id:'t1', icon:'', title:'Family',        sub:'Comfortable family vehicle \u00B7 5-7 passengers \u00B7 daily driver',     price:80},\\n  {id:'t2', icon:'', title:'Luxury',         sub:'Premium SUV \u00B7 4-6 passengers \u00B7 luxury cabin',                    price:160},\\n  {id:'t3', icon:'', title:'Ultra-luxury',   sub:'Executive shuttle \u00B7 4-6 passengers \u00B7 VIP captain chairs',        price:280},\\n];\\n// Meals \u2014 only standard tier complimentary\\nconst MEALS = [\\n  {id:'m1', icon:'', title:'Standard guide-led', sub:'Recommended restaurants \u00B7 regional cuisine',                price:0, originalPrice:50,  badge:'FREE'},\\n  {id:'m2', icon:'', title:'Chef-anchor dining', sub:'Anchor restaurant per day \u00B7 Michelin / local star',         price:140},\\n  {id:'m3', icon:'', title:'Private chef',        sub:'Private kitchen \u00B7 master chef \u00B7 ICH-credentialed',          price:320},\\n];\\n\\n\\n/* ---- travellerCategory/GENDERS/NOTE_OPTIONS ---- */\\nfunction travellerCategory(age){\\n  if (age \\u003c= 2)  return {key:'infant', label:'Infant',  icon:'', free:true};\\n  if (age \\u003c= 6)  return {key:'child',  label:'Child (\\u003c120cm)',  icon:'', free:true};\\n  if (age \\u003c= 12) return {key:'kid',    label:'Kid',    icon:'', free:false};\\n  if (age >= 60) return {key:'senior', label:'Senior (60+)', icon:'', free:true};\\n  return            {key:'adult',  label:'Adult',  icon:'', free:false};\\n}\\nconst GENDERS = [\\n  {id:'m',     icon:'M', label:'Male'},\\n  {id:'f',     icon:'F', label:'Female'},\\n  {id:'other', icon:'\u00B7', label:'Other / Prefer not'},\\n];\\nconst NOTE_OPTIONS = [\\n  {id:'vegan',     icon:'', label:'Vegan / vegetarian'},\\n  {id:'halal',     icon:'', label:'Halal-certified'},\\n  {id:'allergy',   icon:'', label:'Food allergy'},\\n  {id:'mobility',  icon:'', label:'Mobility / wheelchair'},\\n  {id:'elderly',   icon:'', label:'Senior pacing'},\\n  {id:'kid',       icon:'', label:'Kid-friendly meal'},\\n  {id:'language',  icon:'', label:'Non-English speaker'},\\n  {id:'medical',   icon:'', label:'Medical condition'},\\n];\\n\\n\\n\\n/* ---- getStandardDayPlan/cloneSchedule ---- */\\nfunction getStandardDayPlan(cityId, dayIdxInCity){\\n  const plans = STANDARD_DAY_PLAN[cityId];\\n  if (!plans || !plans.length) return [];\\n  // If the trip has more days in this city than templates, reuse the last template's structure\\n  // but mark as \\\"free exploration day\\\"\\n  if (dayIdxInCity >= plans.length){\\n    return plans[plans.length-1].map(r => Object.assign({}, r));\\n  }\\n  // Deep copy so user edits don't mutate the template\\n  return plans[dayIdxInCity].map(r => Object.assign({}, r));\\n}\\n\\n// Deep-clone a schedule entry (for use when initialising user-editable copy in STATE)\\nfunction cloneSchedule(rows){ return rows.map(r => ({time:r.time, title:r.title, dur:r.dur, loc:r.loc, warn:r.warn, alts:(r.alts||[]).slice(), flex:r.flex, modified:false, skipped:false, originalTime:r.time, originalTitle:r.title})); }\\n\\n\\n\\n/* ---- buildItinerary/dayCost* ---- */\\nfunction buildItinerary(){if (ctQuoteOnly()) return [];if (!STATE.cities.length) return []; const days = STATE.days; const perCity = Math.max(2, Math.floor(days / STATE.cities.length)); const arr = []; let consumed = 0; STATE.cities.forEach(cid => {const c = CITIES.find(x=>x.id===cid); for (let i=0; i\\u003cperCity && consumed\\u003cdays; i++){arr.push({cityId:cid, cityName:c.name, cityMust:c.must, dayIdxInCity:i}); consumed++;}}); while (consumed \\u003c days){const lastCid = STATE.cities[STATE.cities.length-1]; const lastIdxInCity = arr.filter(x=>x.cityId===lastCid).length; arr.push({cityId:lastCid, cityName:'Free day / transit', cityMust:'', dayIdxInCity:lastIdxInCity}); consumed++;} return arr.slice(0, days);}\\n// Per-day cost split into base (everyone pays) + surcharge (children\\u003c=6 & seniors>=60 skip)\\nfunction dayCostBreakdown(dayN, dayInfo){\\n  const base = (PACES.find(p=>p.id===STATE.pace)?.base) || 2000;\\n  const pd = STATE.perDay[dayN] || {};\\n  const h = HOTELS.find(x=>x.id===(pd.hotel || STATE.defaultHotel)) || HOTELS[1];\\n  const t = TRANSPORTS.find(x=>x.id===(pd.transport || STATE.defaultTransport)) || TRANSPORTS[1];\\n  const m = MEALS.find(x=>x.id===(pd.meal || STATE.defaultMeal)) || MEALS[0];\\n  let acts = 0;\\n  if (pd.activities) pd.activities.forEach(aid => {const a = (ACTIVITIES[dayInfo.cityId]||[]).find(x=>x.id===aid); if (a) acts += a.price;});\\n  return {base: base + t.price, surcharge: h.price + m.price + acts};  // transport on the road = everyone; hotel+meal+activity = surcharge waived for kids/seniors\\n}\\n// Sum-per-day total across all travellers\\nfunction dayCostAllTravellers(dayN, dayInfo){\\n  const {base, surcharge} = dayCostBreakdown(dayN, dayInfo);\\n  let total = 0;\\n  STATE.travellers.forEach(t => {\\n    const cat = travellerCategory(t.age);\\n    total += base + (cat.free ? 0 : surcharge);\\n  });\\n  return Math.round(total);\\n}\\n// Legacy single-traveller cost (for display in day card \u2014 uses adult rate)\\nfunction dayCost(dayN, dayInfo){\\n  const {base, surcharge} = dayCostBreakdown(dayN, dayInfo);\\n  return Math.round(base + surcharge);\\n}\\n\\n\\n\\n\\n/* === step meta === */\\nconst STEP_LABELS=['Your party','Travellers','Trip length','Your pace','Interests','Cities','Itinerary'];\\n\\n/* === el refs === */\\nconst $=s=>document.querySelector(s), $$=s=>document.querySelectorAll(s);\\nconst stepArea=$('#stepArea');\\n\\n/* === choice card === */\\nfunction mcard(item,type,sel,num,img){\\n  return `\\u003cbutton class=\\\"mcard ${sel?'is-sel':''}\\\" data-pick=\\\"${type}:${item.id}\\\" style=\\\"--img:url('${img||item.img}')\\\">\\n    \\u003cspan class=\\\"mcard__num\\\">${num\\u003c10?'0'+num:num}\\u003c/span>\\n    \\u003cspan class=\\\"mcard__check\\\">&#10003;\\u003c/span>\\n    \\u003cspan class=\\\"mcard__body\\\">\\n      \\u003cspan class=\\\"mcard__title\\\">${item.title||item.name}\\u003c/span>\\n      \\u003cspan class=\\\"mcard__sub\\\">${item.sub||''}\\u003c/span>\\n      ${item.meta?`\\u003cspan class=\\\"mcard__meta\\\">${item.meta}\\u003c/span>`:''}\\n    \\u003c/span>\\u003c/button>`;\\n}\\nfunction priceLabel(it,unit){if(ctQuoteOnly()) return '';\\n  if(it.originalPrice&&it.price===0) return `\\u003cspan class=\\\"opt__free\\\">included\\u003c/span>`;\\n  return `\\u003cspan class=\\\"opt__price\\\">$${it.price}\\u003csmall>${unit}\\u003c/small>\\u003c/span>`;\\n}\\nfunction burst(it){if(ctQuoteOnly()) return '';return (it.originalPrice&&it.price===0)?`\\u003cspan class=\\\"opt__burst\\\">\\u003cb>FREE\\u003c/b>\\u003cs>$${it.originalPrice}\\u003c/s>\\u003c/span>`:'';}\\n\\n/* === RENDER STEP === */\\nfunction renderStep(){\\n  const s=STATE.step; let h='';\\n  if(s===0){\\n    h=`\\u003cdiv class=\\\"step-pop\\\">\\u003cspan class=\\\"eyebrow\\\">Step 1 of 7\\u003c/span>\\n      \\u003ch2 class=\\\"title\\\">Who's \\u003cem>travelling\\u003c/em>?\\u003c/h2>\\n      \\u003cp class=\\\"lede\\\">Party shape changes everything \u2014 hotels, transport, restaurant scale, daily pacing.\\u003c/p>\\n      \\u003cspan class=\\\"rule\\\">\\u003c/span>\\n      \\u003cdiv class=\\\"mcards\\\">${PARTIES.map((p,i)=>mcard(p,'party',STATE.party===p.id,i+1)).join('')}\\u003c/div>\\u003c/div>`;\\n  } else if(s===1){\\n    const paying=STATE.travellers.filter(t=>!travellerCategory(t.age).free).length;\\n    const free=STATE.travellers.length-paying;\\n    h=`\\u003cdiv class=\\\"step-pop\\\">\\u003cspan class=\\\"eyebrow\\\">Step 2 of 7\\u003c/span>\\n      \\u003ch2 class=\\\"title\\\">How many \\u003cem>travellers\\u003c/em>?\\u003c/h2>\\n      \\u003cp class=\\\"lede\\\">Add each person's age and any dietary or accessibility notes. \\u003cstrong>Children \u22646 and seniors 60+ pay no surcharge on hotels, meals or activities.\\u003c/strong>\\u003c/p>\\n      \\u003cspan class=\\\"rule\\\">\\u003c/span>\\n      \\u003cdiv class=\\\"tr-count\\\">\\n        \\u003cdiv>\\u003cdiv class=\\\"tr-count__label\\\">Total travellers\\u003c/div>\\n          \\u003cdiv class=\\\"tr-count__val\\\">${STATE.travellers.length}\\u003c/div>\\n          \\u003cdiv class=\\\"tr-count__meta\\\">\\u003cb>${paying}\\u003c/b> paying \u00B7 \\u003ci>${free} surcharge-free\\u003c/i>\\u003c/div>\\u003c/div>\\n        \\u003cdiv class=\\\"tr-count__ctrl\\\">\\u003cbutton class=\\\"tr-count__btn\\\" data-tr=\\\"dec\\\">&minus;\\u003c/button>\\u003cbutton class=\\\"tr-count__btn\\\" data-tr=\\\"inc\\\">+\\u003c/button>\\u003c/div>\\n      \\u003c/div>\\n      \\u003cspan class=\\\"sec-label\\\">Each traveller \u00B7 age + notes\\u003c/span>\\n      \\u003cdiv id=\\\"trList\\\">${STATE.travellers.map((t,i)=>trRow(t,i)).join('')}\\u003c/div>\\n      \\u003cdiv class=\\\"tr-notes\\\">\\u003cspan class=\\\"sec-label\\\">Anything else? \u00B7 trip-wide notes for the strategist\\u003c/span>\\n        \\u003ctextarea id=\\\"trGlobal\\\" placeholder=\\\"e.g. We celebrate our 30th anniversary on Day 8 \u00B7 one traveller is recovering from knee surgery \u00B7 first time in Asia\\\">${STATE.travelNotes}\\u003c/textarea>\\u003c/div>\\u003c/div>`;\\n  } else if(s===2){\\n    h=`\\u003cdiv class=\\\"step-pop\\\">\\u003cspan class=\\\"eyebrow\\\">Step 3 of 7\\u003c/span>\\n      \\u003ch2 class=\\\"title\\\">How \\u003cem>many days\\u003c/em>?\\u003c/h2>\\n      \\u003cp class=\\\"lede\\\">5-7 = single city \u00B7 8-14 = classic 2-3 city \u00B7 15+ unlocks Tibet, Yunnan, Silk Road.\\u003c/p>\\n      \\u003cspan class=\\\"rule\\\">\\u003c/span>\\n      \\u003cdiv class=\\\"days-card\\\">\\n        \\u003cdiv class=\\\"days-num\\\" id=\\\"daysOut\\\">${STATE.days}\\u003c/div>\\n        \\u003cdiv class=\\\"days-cap\\\">Days in China\\u003c/div>\\n        \\u003cdiv class=\\\"days-hint\\\" id=\\\"daysHint\\\">\\u003c/div>\\n        \\u003cinput type=\\\"range\\\" class=\\\"range\\\" id=\\\"daysRange\\\" min=\\\"5\\\" max=\\\"21\\\" step=\\\"1\\\" value=\\\"${STATE.days}\\\" style=\\\"--p:${(STATE.days-5)/16*100}%\\\">\\n        \\u003cdiv class=\\\"range-legend\\\">\\u003cspan>5 d\\u003c/span>\\u003cspan>13 d\\u003c/span>\\u003cspan>21 d\\u003c/span>\\u003c/div>\\n      \\u003c/div>\\u003c/div>`;\\n  } else if(s===3){\\n    h=`\\u003cdiv class=\\\"step-pop\\\">\\u003cspan class=\\\"eyebrow\\\">Step 4 of 7\\u003c/span>\\n      \\u003ch2 class=\\\"title\\\">How \\u003cem>fast\\u003c/em>?\\u003c/h2>\\n      \\u003cp class=\\\"lede\\\">Most travellers think they want Hands-on. Most should choose Cultural. This shapes your daily rhythm.\\u003c/p>\\n      \\u003cspan class=\\\"rule\\\">\\u003c/span>\\n      \\u003cdiv class=\\\"mcards\\\">${PACES.map((p,i)=>mcard(p,'pace',STATE.pace===p.id,i+1)).join('')}\\u003c/div>\\u003c/div>`;\\n  } else if(s===4){\\n    h=`\\u003cdiv class=\\\"step-pop\\\">\\u003cspan class=\\\"eyebrow\\\">Step 5 of 7\\u003c/span>\\n      \\u003ch2 class=\\\"title\\\">What \\u003cem>draws\\u003c/em> you?\\u003c/h2>\\n      \\u003cp class=\\\"lede\\\">Pick 2-3 anchors. More than 3 dilutes the trip \u2014 we push back when briefs feel diffused.\\u003c/p>\\n      \\u003cspan class=\\\"rule\\\">\\u003c/span>\\n      \\u003cdiv class=\\\"mcards\\\">${INTERESTS.map((it,i)=>mcard(it,'interest',STATE.interests.has(it.id),i+1)).join('')}\\u003c/div>\\u003c/div>`;\\n  } else if(s===5){\\n    let rc,rt;\\n    const d=STATE.days;\\n    if(d\\u003c=7){rc='1-2';rt='Single-city focus or one classic city + a short add-on. Beijing alone (5-6 d) or Shanghai-Jiangnan (5-7 d) are the proven first trips.';}\\n    else if(d\\u003c=10){rc='2-3';rt='Classic 2-3 city route. Beijing + Shanghai \u00B7 or Beijing + Xi\\\\'an + Shanghai (the most-booked 8-day pattern).';}\\n    else if(d\\u003c=14){rc='3-4';rt='Classic 3-city + optional extension. Beijing + Xi\\\\'an + Shanghai + Guilin/Chengdu add-on.';}\\n    else if(d\\u003c=18){rc='4-5';rt='Three-region depth unlocks. Add Tibet or Yunnan as the third region (5-7 days each).';}\\n    else{rc='5-6';rt='Full multi-region grand tour. Beijing + Xi\\\\'an + Shanghai + Tibet/Yunnan + Guilin/Lijiang.';}\\n    const n=STATE.cities.length; const hi=parseInt((rc.split('-')[1]||rc));\\n    let over = n===0?'' : n\\u003cparseInt(rc)?`\\u003cspan class=\\\"rec-add\\\">\u00B7 add ${parseInt(rc)-n} more for the recommended pace\\u003c/span>`\\n      : n>hi?`\\u003cspan class=\\\"rec-over\\\">\u00B7 that's a lot for ${d} days \u2014 consider trimming\\u003c/span>`\\n      : `\\u003cspan class=\\\"rec-ok\\\">\u00B7 good fit for ${d} days\\u003c/span>`;\\n    h=`\\u003cdiv class=\\\"step-pop\\\">\\u003cspan class=\\\"eyebrow\\\">Step 6 of 7\\u003c/span>\\n      \\u003ch2 class=\\\"title\\\">Which \\u003cem>destinations\\u003c/em>? \\u003cspan style=\\\"color:var(--bronze-dark);font-style:italic;font-size:24px\\\">(${n})\\u003c/span>\\u003c/h2>\\n      \\u003cp class=\\\"lede\\\">Tap \\u003cstrong>Add to journey\\u003c/strong> to confirm. Order is your preference; routing is confirmed in your proposal.\\u003c/p>\\n      \\u003cspan class=\\\"rule\\\">\\u003c/span>\\n      \\u003cdiv class=\\\"rec-banner\\\">\\u003cspan class=\\\"rec-banner__ic\\\">&#128161;\\u003c/span>\\n        \\u003cdiv>\\u003cdiv class=\\\"rec-banner__k\\\">Recommendation for ${d} days\\u003c/div>\\n          \\u003cdiv class=\\\"rec-banner__t\\\">Pick \\u003cem>${rc} cities\\u003c/em> ${over}\\u003c/div>\\n          \\u003cdiv class=\\\"rec-banner__d\\\">${rt}\\u003c/div>\\u003c/div>\\u003c/div>\\n      \\u003cdiv class=\\\"scenes\\\">${CITIES.map(c=>{const added=STATE.cities.includes(c.id);\\n        return `\\u003cdiv class=\\\"scene ${added?'is-added':''}\\\" data-city=\\\"${c.id}\\\" style=\\\"--img:url('${cityImg(c)}')\\\">\\n          \\u003cspan class=\\\"scene__check\\\">&#10003;\\u003c/span>\\n          \\u003cdiv class=\\\"scene__c\\\">\\n            \\u003ch4 class=\\\"scene__name\\\">${c.name}\\u003c/h4>\\n            \\u003cp class=\\\"scene__intro\\\">${c.intro}\\u003c/p>\\n            \\u003cp class=\\\"scene__must\\\">\\u003cb>Must visit:\\u003c/b> ${c.must}\\u003c/p>\\n            \\u003cspan class=\\\"scene__rec\\\">${ctQuoteOnly() || c.planningMode==='quote_only' ? (c.timingText || 'Timing confirmed in your proposal') : c.rec+' recommended'}\\u003c/span>\\n            \\u003cbutton class=\\\"scene__add\\\" data-add=\\\"${c.id}\\\">${added?'&#10005; Remove from journey':'+ Add to journey'}\\u003c/button>\\n          \\u003c/div>\\u003c/div>`;}).join('')}\\u003c/div>\\n      ${n>0?`\\u003cdiv class=\\\"seq\\\">\\u003cspan class=\\\"seq__label\\\">Sequence\\u003c/span>${STATE.cities.map((cid,i)=>{const c=CITIES.find(x=>x.id===cid);return `\\u003cspan class=\\\"chip-gold\\\">\\u003cb>${i+1}\\u003c/b> ${c.name}\\u003c/span>`;}).join('')}\\u003c/div>`\\n        :`\\u003cp class=\\\"empty-note\\\">No cities added yet. Spotlight a scene and tap Add to journey.\\u003c/p>`}\\u003c/div>`;\\n  } else if(s===6 && ctQuoteOnly()){\\n    h=ctQuoteReview();\\n  } else if(s===6){\\n    const days=buildItinerary();\\n    h=`\\u003cdiv class=\\\"step-pop\\\">\\u003cspan class=\\\"eyebrow\\\">Step 7 of 7\\u003c/span>\\n      \\u003ch2 class=\\\"title\\\">Your \\u003cem>itinerary\\u003c/em> & price\\u003c/h2>\\n      \\u003cp class=\\\"lede\\\">Tap any day to edit activities, hotel, transport, meals. Price refreshes live.\\u003c/p>\\n      \\u003cspan class=\\\"rule\\\">\\u003c/span>\\n      \\u003cdiv class=\\\"defaults\\\">\\n        \\u003cspan class=\\\"sec-label\\\" style=\\\"margin-top:0\\\">Defaults \u00B7 override per-day\\u003c/span>\\n        \\u003cdiv class=\\\"def-group\\\">\\u003cdiv class=\\\"def-k\\\">Hotel tier\\u003c/div>${HOTELS.map(x=>defOpt(x,'hotel','/n/pp')).join('')}\\u003c/div>\\n        \\u003cdiv class=\\\"def-group\\\">\\u003cdiv class=\\\"def-k\\\">Transport\\u003c/div>${TRANSPORTS.map(x=>defOpt(x,'transport','/d/pp')).join('')}\\u003c/div>\\n        \\u003cdiv class=\\\"def-group\\\">\\u003cdiv class=\\\"def-k\\\">Dining\\u003c/div>${MEALS.map(x=>defOpt(x,'meal','/d/pp')).join('')}\\u003c/div>\\n      \\u003c/div>\\n      \\u003cspan class=\\\"sec-label\\\">Day by day \u00B7 tap any day to customise\\u003c/span>\\n      ${days.map((dd,i)=>{const dn=i+1;const pd=STATE.perDay[dn]||{};\\n        const acts=pd.activities?[...pd.activities]:[];\\n        const al=acts.map(aid=>(ACTIVITIES[dd.cityId]||[]).find(a=>a.id===aid)).filter(Boolean);\\n        const cust=al.length||pd.hotel||pd.transport||pd.meal||(pd.schedule&&pd.schedule.some(r=>r.modified));\\n        const c=CITIES.find(x=>x.id===dd.cityId);\\n        return `\\u003cdiv class=\\\"iti-day ${cust?'is-cust':''}\\\" data-day=\\\"${dn}\\\">\\n          \\u003cdiv class=\\\"iti-day__img\\\" style=\\\"background-image:url('${c?cityImg(c):''}')\\\">\\u003c/div>\\n          \\u003cdiv class=\\\"iti-day__b\\\">\\u003cdiv class=\\\"iti-day__top\\\">\\n            \\u003cdiv style=\\\"min-width:0\\\">\\u003cspan class=\\\"iti-day__k\\\">Day ${dn} \u00B7 ${dd.cityName}\\u003c/span>\\n              \\u003cdiv class=\\\"iti-day__acts\\\">${al.length?al.map(a=>a.label).join(' \u00B7 '):'\\u003ci>Curated by senior guide \u2014 tap to choose\\u003c/i>'}\\u003c/div>\\u003c/div>\\n            \\u003cdiv>\\u003cdiv class=\\\"iti-day__price\\\">$${dayCostAllTravellers(dn,dd).toLocaleString()}\\u003c/div>\\n              \\u003cdiv class=\\\"iti-day__pp\\\">${STATE.travellers.length} pax \u00B7 edit &#8594;\\u003c/div>\\u003c/div>\\n          \\u003c/div>\\u003c/div>\\u003c/div>`;}).join('')}\\u003c/div>`;\\n  }\\n  stepArea.innerHTML=h;\\n  bindStep();\\n  updateRail();\\n  updateBrief();\\n  updateNav();\\n  if(s===0) $('#scroll').scrollTop=0;\\n}\\n\\nfunction trRow(t,i){\\n  const cat=travellerCategory(t.age);\\n  return `\\u003cdiv class=\\\"tr-row ${cat.free?'is-free':''}\\\" data-trid=\\\"${t.id}\\\">\\n    ${STATE.travellers.length>1?`\\u003cbutton class=\\\"tr-row__rm\\\" data-rm=\\\"${t.id}\\\">&times;\\u003c/button>`:''}\\n    \\u003cdiv class=\\\"tr-row__head\\\">\\n      \\u003cdiv>\\u003cdiv class=\\\"tr-row__num\\\">Traveller ${i+1}\\u003c/div>\\u003cdiv class=\\\"tr-row__cat\\\">${cat.label}\\u003c/div>\\u003c/div>\\n      \\u003cspan class=\\\"tr-row__free\\\" style=\\\"${cat.free?'':'display:none'}\\\">No surcharge\\u003c/span>\\u003c/div>\\n    \\u003cdiv class=\\\"tr-pills\\\">${GENDERS.map(g=>`\\u003cspan class=\\\"pill-sm ${t.gender===g.id?'is-on':''}\\\" data-g=\\\"${t.id}:${g.id}\\\">${g.label}\\u003c/span>`).join('')}\\u003c/div>\\n    \\u003cdiv class=\\\"tr-age\\\">\\u003cspan class=\\\"tr-age__label\\\">Age\\u003c/span>\\n      \\u003cinput type=\\\"number\\\" class=\\\"tr-age__input\\\" min=\\\"0\\\" max=\\\"100\\\" value=\\\"${t.age}\\\" data-age=\\\"${t.id}\\\">\\n      \\u003cinput type=\\\"range\\\" class=\\\"range tr-age__slider\\\" min=\\\"0\\\" max=\\\"100\\\" step=\\\"1\\\" value=\\\"${t.age}\\\" data-aslide=\\\"${t.id}\\\" style=\\\"--p:${t.age}%\\\">\\u003c/div>\\n    \\u003cdiv class=\\\"tr-pills\\\" style=\\\"margin:11px 0 0\\\">${NOTE_OPTIONS.map(o=>`\\u003cspan class=\\\"pill-sm ${t.notes.includes(o.id)?'is-on':''}\\\" data-note=\\\"${t.id}:${o.id}\\\">${o.label}\\u003c/span>`).join('')}\\u003c/div>\\n  \\u003c/div>`;\\n}\\nfunction defOpt(x,type,unit){\\n  const on=STATE['default'+type[0].toUpperCase()+type.slice(1)]===x.id;\\n  return `\\u003cdiv class=\\\"opt ${on?'is-on':''}\\\" data-def=\\\"${type}:${x.id}\\\">${burst(x)}\\n    \\u003cdiv class=\\\"opt__body\\\">\\u003cdiv class=\\\"opt__title\\\">${x.title}\\u003c/div>\\u003cdiv class=\\\"opt__sub\\\">${x.sub}\\u003c/div>\\u003c/div>${priceLabel(x,unit)}\\u003c/div>`;\\n}\\n\\n/* === BIND === */\\nfunction bindStep(){\\n  $$('[data-pick]').forEach(el=>el.onclick=()=>{\\n    const [type,id]=el.dataset.pick.split(':');\\n    if(type==='party')STATE.party=id;\\n    else if(type==='pace')STATE.pace=id;\\n    else if(type==='interest'){STATE.interests.has(id)?STATE.interests.delete(id):STATE.interests.add(id);}\\n    renderStep();\\n  });\\n  // travellers\\n  $$('[data-tr]').forEach(b=>b.onclick=()=>{\\n    if(b.dataset.tr==='inc'&&STATE.travellers.length\\u003c12){const nid=Math.max(0,...STATE.travellers.map(t=>t.id))+1;STATE.travellers.push({id:nid,age:30,gender:'other',notes:[]});}\\n    if(b.dataset.tr==='dec'&&STATE.travellers.length>1)STATE.travellers.pop();\\n    renderStep();\\n  });\\n  $$('[data-rm]').forEach(b=>b.onclick=()=>{STATE.travellers=STATE.travellers.filter(t=>t.id!=b.dataset.rm);renderStep();});\\n  $$('[data-g]').forEach(el=>el.onclick=()=>{const[id,g]=el.dataset.g.split(':');const t=STATE.travellers.find(x=>x.id==id);if(t){t.gender=g;renderStep();}});\\n  $$('[data-note]').forEach(el=>el.onclick=()=>{const[id,n]=el.dataset.note.split(':');const t=STATE.travellers.find(x=>x.id==id);if(t){const k=t.notes.indexOf(n);k>=0?t.notes.splice(k,1):t.notes.push(n);renderStep();}});\\n  $$('[data-age]').forEach(inp=>inp.onchange=()=>{const t=STATE.travellers.find(x=>x.id==inp.dataset.age);if(t){t.age=Math.max(0,Math.min(100,parseInt(inp.value)||0));renderStep();}});\\n  $$('[data-aslide]').forEach(inp=>{\\n    inp.oninput=()=>{const t=STATE.travellers.find(x=>x.id==inp.dataset.aslide);if(t){t.age=parseInt(inp.value);inp.style.setProperty('--p',t.age+'%');const row=inp.closest('.tr-row');const ai=row.querySelector('[data-age]');if(ai)ai.value=t.age;}};\\n    inp.onchange=()=>renderStep();\\n  });\\n  const gn=$('#trGlobal'); if(gn)gn.oninput=()=>{STATE.travelNotes=gn.value;};\\n  // days\\n  const dr=$('#daysRange');\\n  if(dr){const upd=()=>{STATE.days=parseInt(dr.value);dr.style.setProperty('--p',(STATE.days-5)/16*100+'%');\\n    $('#daysOut').textContent=STATE.days;\\n    const hints={5:'Quick taste \u00B7 one city',7:'Single region, done well',10:'Classic 2-3 cities',13:'3 cities + extension',16:'Adds a third region',19:'Grand multi-region tour',21:'The full epic'};\\n    let hk=5;Object.keys(hints).forEach(k=>{if(STATE.days>=k)hk=k;});$('#daysHint').textContent=hints[hk];updateBrief();};\\n    dr.oninput=upd;upd();}\\n  // cities\\n  $$('[data-add]').forEach(b=>b.onclick=e=>{e.stopPropagation();const cid=b.dataset.add;const k=STATE.cities.indexOf(cid);k>=0?STATE.cities.splice(k,1):STATE.cities.push(cid);renderStep();});\\n  // itinerary defaults\\n  $$('[data-def]').forEach(el=>el.onclick=()=>{const[type,id]=el.dataset.def.split(':');STATE['default'+type[0].toUpperCase()+type.slice(1)]=id;renderStep();});\\n  $$('[data-day]').forEach(el=>el.onclick=()=>openDay(parseInt(el.dataset.day)));\\n}\\n\\n/* === RAIL === */\\nfunction updateRail(){\\n  $('#railStep').textContent=`Step ${STATE.step+1} of 7`;\\n  $('#railLabel').textContent=STEP_LABELS[STATE.step];\\n  let dots='';for(let i=0;i\\u003c7;i++){const cls=i===STATE.step?'is-active':i\\u003cSTATE.step?'is-done':'';dots+=`\\u003cspan class=\\\"dot ${cls}\\\">${i\\u003cSTATE.step?'&#10003;':i+1}\\u003c/span>`;}\\n  $('#railDots').innerHTML=dots;\\n  $('#railDots').style.setProperty('--progress',(STATE.step/6)*100+'%');\\n}\\n\\n/* === BRIEF + PRICE === */\\nfunction updateBrief(){\\n  if (ctQuoteOnly()) { ctUpdateQuoteBrief(); return; }\\n  ctRestorePriceStyle();\\n  const items=[];\\n  if(STATE.party){const p=PARTIES.find(x=>x.id===STATE.party);items.push(['Party',p.title]);}\\n  const paying=STATE.travellers.filter(t=>!travellerCategory(t.age).free).length;\\n  const free=STATE.travellers.length-paying;\\n  items.push(['Travellers',`${STATE.travellers.length} (${paying} paying \u00B7 ${free} free)`]);\\n  items.push(['Length',STATE.days+' days']);\\n  if(STATE.pace){const p=PACES.find(x=>x.id===STATE.pace);items.push(['Pace',p.title]);}\\n  if(STATE.interests.size)items.push(['Interests',[...STATE.interests].map(id=>INTERESTS.find(x=>x.id===id).title).join(' \u00B7 ')]);\\n  if(STATE.cities.length)items.push(['Cities',STATE.cities.map(id=>CITIES.find(x=>x.id===id).name).join(' \u00B7 ')]);\\n  const nc=STATE.travellers.reduce((a,t)=>a+t.notes.length,0)+(STATE.travelNotes.trim()?1:0);\\n  if(nc)items.push(['Notes',nc+' flagged']);\\n  $('#briefList').innerHTML=items.map(([k,v])=>`\\u003cdiv class=\\\"brief-row\\\">\\u003cspan class=\\\"brief-row__k\\\">${k}\\u003c/span>\\u003cspan class=\\\"brief-row__v\\\">${v}\\u003c/span>\\u003c/div>`).join('');\\n  const done=(STATE.party?1:0)+(STATE.pace?1:0)+(STATE.interests.size>0?1:0)+(STATE.cities.length>0?1:0);\\n  const score=Math.round(done/4*100);\\n  $('#briefScore').textContent=score+'%';\\n  $('#briefScore2').textContent=score+'% complete';\\n  $('#briefHeadline').textContent=score===100?'Ready to send':(STATE.party?'Building your brief\u2026':'Tell us about your party');\\n  let total=0;\\n  if(STATE.cities.length&&STATE.pace){\\n    buildItinerary().forEach((d,i)=>{total+=dayCostAllTravellers(i+1,d);});\\n    $('#priceTotal').textContent='$'+total.toLocaleString();\\n    const pp=Math.round(total/Math.max(1,STATE.days)/Math.max(1,STATE.travellers.length));\\n    $('#priceBreak').textContent=`${STATE.days} d \u00D7 ${STATE.travellers.length} pax \u00B7 ~$${pp}/person/day`;\\n  } else {$('#priceTotal').textContent='$0';$('#priceBreak').textContent='Pick pace + cities to see the price.';}\\n}\\n\\n/* === NAV === */\\nfunction stepGate(s){\\n  if (s >= 5 && !ctValidDestinations()) return {ok:false,hint:'Review destination selection before continuing'};\\n  if(s===0)return{ok:!!STATE.party,hint:'Pick your party to continue'};\\n  if(s===1){if(STATE.travellers.some(t=>!t.age||t.age\\u003c=0||t.age>100))return{ok:false,hint:'Set a valid age (1-100) for everyone'};return{ok:true};}\\n  if(s===2)return{ok:STATE.days>=5,hint:'Set the number of days'};\\n  if(s===3)return{ok:!!STATE.pace,hint:'Pick a pace to continue'};\\n  if(s===4)return{ok:STATE.interests.size>=1,hint:'Pick at least 1 interest (2-3 ideal)'};\\n  if(s===5)return{ok:STATE.cities.length>=1,hint:'Add at least 1 city to your journey'};\\n  return{ok:true};\\n}\\nfunction updateNav(){\\n  const g=stepGate(STATE.step);\\n  const next=$('#nextBtn'),back=$('#backBtn'),hint=$('#navHint');\\n  back.disabled=STATE.step===0;\\n  next.disabled=!g.ok;\\n  next.innerHTML=STATE.step===6?'Review inquiry &#8594;':'Continue &#8594;';\\n  hint.textContent=g.ok?'':(g.hint||'');\\n  hint.style.opacity=g.ok?0:1;\\n}\\n$('#nextBtn').onclick=()=>{\\n  const g=stepGate(STATE.step);if(!g.ok)return;\\n  if(STATE.step===6){\\n    if (window.top.CTCommerceBrief) window.top.CTCommerceBrief.go((ctQuoteOnly()?ctQuoteBrief():{...STATE,itinerary:buildItinerary(),total:$('#priceTotal').textContent}),$('#nextBtn'));\\n    else { $('#nextBtn').textContent='Brief not sent. Reload to retry.'; }\\n    return;\\n  }\\n  STATE.step++;renderStep();$('#scroll').scrollTo({top:0,behavior:'smooth'});\\n};\\n$('#backBtn').onclick=()=>{if(STATE.step>0){STATE.step--;renderStep();$('#scroll').scrollTo({top:0,behavior:'smooth'});}};\\n\\n/* === BRIEF SHEET === */\\nfunction openSheet(id){$('#sheetBack').classList.add('is-open');$(id).classList.add('is-open');}\\nfunction closeSheets(){$('#sheetBack').classList.remove('is-open');$('#briefSheet').classList.remove('is-open');$('#daySheet').classList.remove('is-open');}\\n$('#briefToggle').onclick=()=>openSheet('#briefSheet');\\n$('#sheetBack').onclick=closeSheets;\\n$$('[data-close-brief]').forEach(b=>b.onclick=closeSheets);\\n\\n/* === DAY SHEET === */\\nlet curDay=null;\\nfunction openDay(dn){if(ctQuoteOnly()) return;\\n  curDay=dn;\\n  const its=buildItinerary();const d=its[dn-1];if(!d)return;\\n  const pd=STATE.perDay[dn]||{activities:new Set()};\\n  if(!pd.activities)pd.activities=new Set();\\n  if(!pd.schedule){pd.schedule=cloneSchedule(getStandardDayPlan(d.cityId,d.dayIdxInCity||0));}\\n  STATE.perDay[dn]=pd;\\n  const acts=ACTIVITIES[d.cityId]||[];\\n  const cH=pd.hotel||STATE.defaultHotel,cT=pd.transport||STATE.defaultTransport,cM=pd.meal||STATE.defaultMeal;\\n  const isOver=(d.dayIdxInCity||0)>=(STANDARD_DAY_PLAN[d.cityId]||[]).length;\\n  $('#dayHead').innerHTML=`\\u003cdiv>\\u003cspan class=\\\"eyebrow\\\">Day ${dn} \u00B7 customise\\u003c/span>\\n    \\u003cdiv class=\\\"title\\\" style=\\\"font-size:28px;margin:5px 0 2px\\\">${d.cityName}\\u003c/div>\\n    \\u003cp class=\\\"lede\\\" style=\\\"margin:0\\\">${d.cityMust||''}\\u003c/p>\\u003c/div>\\n    \\u003cbutton class=\\\"sheet__x\\\" data-close-day>&times;\\u003c/button>`;\\n  let body='';\\n  if(pd.schedule.length){\\n    body+=`\\u003cdiv style=\\\"display:flex;justify-content:space-between;align-items:center;margin:4px 0 6px\\\">\\n      \\u003cspan class=\\\"sec-label\\\" style=\\\"margin:0\\\">&#128197; Your day${isOver?' (free exploration)':''}\\u003c/span>\\n      \\u003cspan class=\\\"sched-btn\\\" data-resetall>&#8634; Reset\\u003c/span>\\u003c/div>\\n      \\u003cp style=\\\"font-size:11px;line-height:1.5;color:var(--mute);margin:0 0 12px\\\">Tap \\u003cb>Swap\\u003c/b> for alternatives \u00B7 \\u003cb>Skip\\u003c/b> to drop and see free-time ideas. Children \u22646 and seniors 60+ aren't charged.\\u003c/p>\\n      \\u003cdiv id=\\\"schedList\\\">${pd.schedule.map((r,i)=>schedRow(r,i)).join('')}\\u003c/div>`;\\n  }\\n  const incl=STANDARD_INCLUDED[d.cityId]||[];\\n  if(incl.length){\\n    body+=`\\u003cdiv class=\\\"incl\\\">\\u003cdiv class=\\\"incl__h\\\">\\u003cspan class=\\\"incl__ck\\\">&#10003;\\u003c/span>\\n      \\u003cdiv>\\u003cdiv class=\\\"incl__t\\\">Always included in ${d.cityName.split(' ')[0]}\\u003c/div>\\n      \\u003cdiv class=\\\"incl__s\\\">Beyond today's schedule \u2014 standard sightseeing for this city.\\u003c/div>\\u003c/div>\\u003c/div>\\n      \\u003cdiv>${incl.map(x=>`\\u003cspan class=\\\"incl__chip\\\">${x}\\u003c/span>`).join('')}\\u003c/div>\\u003c/div>`;\\n  }\\n  body+=`\\u003cspan class=\\\"sec-label\\\">+ Private add-on upgrades \u00B7 tap to add/remove\\u003c/span>\\n    \\u003cp class=\\\"addon-lede\\\">Exclusive private access, VIP seating, helicopter or master-led experiences \\u003cb>not in the standard tour\\u003c/b>. Adults pay per person; children \u22646 and seniors 60+ free.\\u003c/p>\\n    \\u003cdiv>${acts.map(a=>{const tl=a.tier==='ultra'?'ULTRA':a.tier==='vip'?'VIP':'PRIVATE';\\n      return `\\u003cdiv class=\\\"opt ${pd.activities.has(a.id)?'is-on':''}\\\" data-act=\\\"${a.id}\\\">\\n        \\u003cdiv class=\\\"opt__body\\\">\\u003cdiv class=\\\"opt__title\\\" style=\\\"font-size:15px\\\">${a.label}\\u003cspan class=\\\"opt__tier opt__tier--${a.tier||'private'}\\\">${tl}\\u003c/span>\\u003c/div>\\n        \\u003cdiv class=\\\"opt__sub\\\">${a.cat}\\u003c/div>\\u003c/div>\\u003cspan class=\\\"opt__price\\\">+$${a.price}\\u003csmall>/pp\\u003c/small>\\u003c/span>\\u003c/div>`;}).join('')}\\u003c/div>\\n    \\u003cspan class=\\\"sec-label\\\">Hotel tier (this day)\\u003c/span>\\u003cdiv>${HOTELS.map(x=>`\\u003cdiv class=\\\"opt ${cH===x.id?'is-on':''}\\\" data-dh=\\\"${x.id}\\\">${burst(x)}\\u003cdiv class=\\\"opt__body\\\">\\u003cdiv class=\\\"opt__title\\\">${x.title}\\u003c/div>\\u003cdiv class=\\\"opt__sub\\\">${x.sub}\\u003c/div>\\u003c/div>${priceLabel(x,'/n/pp')}\\u003c/div>`).join('')}\\u003c/div>\\n    \\u003cspan class=\\\"sec-label\\\">Transport (this day)\\u003c/span>\\u003cdiv>${TRANSPORTS.map(x=>`\\u003cdiv class=\\\"opt ${cT===x.id?'is-on':''}\\\" data-dt=\\\"${x.id}\\\">${burst(x)}\\u003cdiv class=\\\"opt__body\\\">\\u003cdiv class=\\\"opt__title\\\">${x.title}\\u003c/div>\\u003cdiv class=\\\"opt__sub\\\">${x.sub}\\u003c/div>\\u003c/div>${priceLabel(x,'/d/pp')}\\u003c/div>`).join('')}\\u003c/div>\\n    \\u003cspan class=\\\"sec-label\\\">Dining (this day)\\u003c/span>\\u003cdiv>${MEALS.map(x=>`\\u003cdiv class=\\\"opt ${cM===x.id?'is-on':''}\\\" data-dm=\\\"${x.id}\\\">${burst(x)}\\u003cdiv class=\\\"opt__body\\\">\\u003cdiv class=\\\"opt__title\\\">${x.title}\\u003c/div>\\u003cdiv class=\\\"opt__sub\\\">${x.sub}\\u003c/div>\\u003c/div>${priceLabel(x,'/d/pp')}\\u003c/div>`).join('')}\\u003c/div>`;\\n  $('#dayBody').innerHTML=body;\\n  bindDay(dn,pd,d);\\n  openSheet('#daySheet');\\n  $('#dayBody').scrollTop=0;\\n}\\nfunction schedRow(r,i){\\n  return `\\u003cdiv class=\\\"sched-row ${r.modified?'is-mod':''} ${r.skipped?'is-skip':''}\\\" data-sr=\\\"${i}\\\">\\n    \\u003cdiv class=\\\"sched-time\\\">\\u003cinput type=\\\"time\\\" value=\\\"${r.time}\\\" data-st=\\\"${i}\\\" ${r.skipped?'disabled':''}>${r.dur?`\\u003cspan class=\\\"sched-dur\\\">~${r.dur}m\\u003c/span>`:''}\\u003c/div>\\n    \\u003cdiv class=\\\"sched-b\\\">\\u003cdiv class=\\\"sched-title\\\">${r.title}\\u003c/div>${r.loc?`\\u003cdiv class=\\\"sched-loc\\\">&#128205; ${r.loc}\\u003c/div>`:''}${(r.warn&&!r.skipped)?`\\u003cdiv class=\\\"sched-warn\\\">${r.warn}\\u003c/div>`:''}\\u003cdiv data-slot=\\\"${i}\\\">\\u003c/div>\\u003c/div>\\n    \\u003cdiv class=\\\"sched-acts\\\">${r.skipped?`\\u003cbutton class=\\\"sched-btn\\\" data-sa=\\\"restore:${i}\\\">&#8634; Restore\\u003c/button>`:`\\u003cbutton class=\\\"sched-btn\\\" data-sa=\\\"swap:${i}\\\">&#128257; Swap\\u003c/button>\\u003cbutton class=\\\"sched-btn\\\" data-sa=\\\"skip:${i}\\\">&#10005; Skip\\u003c/button>`}\\u003c/div>\\u003c/div>`;\\n}\\nfunction bindDay(dn,pd,d){\\n  $$('[data-close-day]').forEach(b=>b.onclick=closeSheets);\\n  $$('[data-act]').forEach(c=>c.onclick=()=>{const id=c.dataset.act;pd.activities.has(id)?pd.activities.delete(id):pd.activities.add(id);c.classList.toggle('is-on');updateBrief();});\\n  $$('[data-dh]').forEach(c=>c.onclick=()=>{pd.hotel=c.dataset.dh;$$('[data-dh]').forEach(x=>x.classList.toggle('is-on',x.dataset.dh===pd.hotel));updateBrief();});\\n  $$('[data-dt]').forEach(c=>c.onclick=()=>{pd.transport=c.dataset.dt;$$('[data-dt]').forEach(x=>x.classList.toggle('is-on',x.dataset.dt===pd.transport));updateBrief();});\\n  $$('[data-dm]').forEach(c=>c.onclick=()=>{pd.meal=c.dataset.dm;$$('[data-dm]').forEach(x=>x.classList.toggle('is-on',x.dataset.dm===pd.meal));updateBrief();});\\n  const ra=$('[data-resetall]');if(ra)ra.onclick=()=>{pd.schedule=cloneSchedule(getStandardDayPlan(d.cityId,d.dayIdxInCity||0));openDay(dn);};\\n  pd.schedule&&pd.schedule.forEach((_,i)=>bindSched(i,pd));\\n}\\nfunction refreshSched(i,pd){const rowEl=document.querySelector(`[data-sr=\\\"${i}\\\"]`);if(!rowEl)return;const w=document.createElement('div');w.innerHTML=schedRow(pd.schedule[i],i).trim();rowEl.replaceWith(w.firstChild);bindSched(i,pd);}\\nfunction bindSched(i,pd){\\n  const rowEl=document.querySelector(`[data-sr=\\\"${i}\\\"]`);if(!rowEl)return;\\n  const ti=rowEl.querySelector(`[data-st=\\\"${i}\\\"]`);\\n  if(ti)ti.onchange=()=>{const r=pd.schedule[i];r.time=ti.value;r.modified=(r.time!==r.originalTime);refreshSched(i,pd);};\\n  rowEl.querySelectorAll('[data-sa]').forEach(btn=>btn.onclick=e=>{e.stopPropagation();\\n    const[act,iStr]=btn.dataset.sa.split(':');const idx=+iStr;const r=pd.schedule[idx];const slot=rowEl.querySelector(`[data-slot=\\\"${idx}\\\"]`);\\n    if(act==='swap'){\\n      if(slot.children.length){slot.innerHTML='';btn.classList.remove('is-active');return;}\\n      const alts=(r.alts&&r.alts.length)?r.alts:freeTimeHints(r.time);\\n      slot.innerHTML=`\\u003cdiv class=\\\"sched-alts\\\">\\u003cdiv class=\\\"sched-alts__l\\\">Pick an alternative \u2014 replaces \\\"${r.originalTitle}\\\"\\u003c/div>${alts.map((a,ai)=>`\\u003cspan class=\\\"alt-chip\\\" data-pa=\\\"${idx}:${ai}\\\">${a}\\u003c/span>`).join('')}\\u003cspan class=\\\"alt-chip\\\" data-pa=\\\"${idx}:original\\\" style=\\\"border-style:dashed\\\">&#8634; Keep original\\u003c/span>\\u003c/div>`;\\n      btn.classList.add('is-active');\\n      slot.querySelectorAll('[data-pa]').forEach(ch=>ch.onclick=ev=>{ev.stopPropagation();const[ri,pk]=ch.dataset.pa.split(':');const rr=pd.schedule[+ri];if(pk==='original'){rr.title=rr.originalTitle;rr.modified=false;}else{rr.title=alts[+pk];rr.modified=true;}refreshSched(+ri,pd);});\\n    }\\n    if(act==='skip'){r.skipped=true;r.modified=true;refreshSched(idx,pd);\\n      const ns=document.querySelector(`[data-slot=\\\"${idx}\\\"]`);if(ns){const hints=freeTimeHints(r.time);\\n        ns.innerHTML=`\\u003cdiv class=\\\"sched-alts\\\">\\u003cdiv class=\\\"sched-alts__l\\\">Free time around ${r.time} \u2014 try:\\u003c/div>${hints.map((hh,hi)=>`\\u003cspan class=\\\"alt-chip\\\" data-ph=\\\"${idx}:${hi}\\\">${hh}\\u003c/span>`).join('')}\\u003c/div>`;\\n        ns.querySelectorAll('[data-ph]').forEach(ch=>ch.onclick=ev=>{ev.stopPropagation();const[ri,hi]=ch.dataset.ph.split(':');const rr=pd.schedule[+ri];rr.skipped=false;rr.title=hints[+hi];rr.modified=true;refreshSched(+ri,pd);});}}\\n    if(act==='restore'){r.skipped=false;r.title=r.originalTitle;r.time=r.originalTime;r.modified=false;refreshSched(idx,pd);}\\n  });\\n}\\n$$('[data-save-day]').forEach(b=>b.onclick=()=>{closeSheets();renderStep();});\\n$$('[data-reset-day]').forEach(b=>b.onclick=()=>{if(curDay){delete STATE.perDay[curDay];closeSheets();renderStep();}});\\n\\n/* === INIT === */\\nrenderStep();\\n\\u003c/script>\\n\\u003c/body>\\n\\u003c/html>\\n\";\n  function init(){\n    if(!window.matchMedia || !window.matchMedia('(max-width:760px)').matches) return;\n    var wrap=document.getElementById('ctm-wiz');\n    if(!wrap) return;                       /* not the bespoke page */\n    if(document.getElementById('ctm-overlay')) return;  /* already built */\n    /* Append overlay to BODY (root stacking context) so it escapes the\n       section's isolation:isolate context and covers everything. */\n    var ov=document.createElement('div');\n    ov.id='ctm-overlay';\n    ov.style.cssText='position:fixed;inset:0;margin:0;padding:0;z-index:2147483000;background:#FAF5EC';\n    var f=document.createElement('iframe');\n    f.title='Design your China journey';\n    f.setAttribute('allow','clipboard-write');\n    f.style.cssText='width:100%;height:100%;border:0;display:block;background:#FAF5EC';\n    ov.appendChild(f);\n    document.body.appendChild(ov);\n    document.documentElement.style.overflow='hidden';\n    document.body.style.overflow='hidden';\n    wrap.style.display='none';              /* hide in-flow fallback */\n    var d=f.contentWindow.document; d.open(); d.write(CTM_HTML); d.close();\n  }\n  if(document.readyState==='loading') document.addEventListener('DOMContentLoaded', init);\n  else init();\n  window.addEventListener('resize', init, {passive:true});\n})();\n"],
  "mappings": "CACC,UAAU,CACT,IAAI,SAAW,809HACf,SAAS,MAAM,CACb,GAAG,GAAC,OAAO,YAAc,CAAC,OAAO,WAAW,mBAAmB,EAAE,SACjE,KAAI,KAAK,SAAS,eAAe,SAAS,EAC1C,GAAI,MACD,UAAS,eAAe,aAAa,EAGxC,KAAI,GAAG,SAAS,cAAc,KAAK,EACnC,GAAG,GAAG,cACN,GAAG,MAAM,QAAQ,kFACjB,IAAI,EAAE,SAAS,cAAc,QAAQ,EACrC,EAAE,MAAM,4BACR,EAAE,aAAa,QAAQ,iBAAiB,EACxC,EAAE,MAAM,QAAQ,mEAChB,GAAG,YAAY,CAAC,EAChB,SAAS,KAAK,YAAY,EAAE,EAC5B,SAAS,gBAAgB,MAAM,SAAS,SACxC,SAAS,KAAK,MAAM,SAAS,SAC7B,KAAK,MAAM,QAAQ,OACnB,IAAI,EAAE,EAAE,cAAc,SAAU,EAAE,KAAK,EAAG,EAAE,MAAM,QAAQ,EAAG,EAAE,MAAM,GACvE,CACG,SAAS,aAAa,UAAW,SAAS,iBAAiB,mBAAoB,IAAI,EACjF,KAAK,EACV,OAAO,iBAAiB,SAAU,KAAM,CAAC,QAAQ,EAAI,CAAC,CACxD,GAAG",
  "names": []
}
