{"id":1698,"date":"2026-01-12T06:10:31","date_gmt":"2026-01-12T06:10:31","guid":{"rendered":"https:\/\/yuiyto.com\/?page_id=1698"},"modified":"2026-02-08T10:30:16","modified_gmt":"2026-02-08T10:30:16","slug":"test2","status":"publish","type":"page","link":"https:\/\/yuiyto.com\/ko\/test2\/","title":{"rendered":"test2"},"content":{"rendered":"\n\n\n<!-- Loongprt QR Code Generator (Pure Front-End) -->\n<div id=\"lp-qr-widget\" class=\"lp-qr\">\n  <div class=\"lp-qr-head\">\n    <div class=\"lp-qr-title\">\n      <div class=\"lp-qr-badge\">Static \u2022 Front-end Only<\/div>\n      <h1>Loongprt QR Code Generator<\/h1>\n      <p>Logo \u2022 Sticker \u2022 Colors \u2022 Shapes \u2022 PNG\/SVG Export. Everything stays in your browser.<\/p>\n    <\/div>\n  <\/div>\n\n  <div class=\"lp-qr-grid\">\n    <!-- LEFT -->\n    <div class=\"lp-qr-card lp-qr-builder\">\n      <!-- Step 1 -->\n      <div class=\"lp-qr-section\">\n        <div class=\"lp-qr-step\">\n          <span class=\"lp-qr-step-num\">1<\/span>\n          <h2>Choose Type<\/h2>\n        <\/div>\n\n        <div class=\"lp-qr-tabs\" role=\"tablist\" aria-label=\"QR type\">\n          <button class=\"lp-qr-tab is-active\" data-type=\"text\" type=\"button\">Text<\/button>\n          <button class=\"lp-qr-tab\" data-type=\"url\" type=\"button\">URL<\/button>\n          <button class=\"lp-qr-tab\" data-type=\"wifi\" type=\"button\">Wi-Fi<\/button>\n          <button class=\"lp-qr-tab\" data-type=\"email\" type=\"button\">Email<\/button>\n          <button class=\"lp-qr-tab\" data-type=\"phone\" type=\"button\">Phone<\/button>\n          <button class=\"lp-qr-tab\" data-type=\"sms\" type=\"button\">SMS<\/button>\n          <button class=\"lp-qr-tab\" data-type=\"vcard\" type=\"button\">vCard<\/button>\n          <button class=\"lp-qr-tab\" data-type=\"mecard\" type=\"button\">MeCard<\/button>\n          <button class=\"lp-qr-tab\" data-type=\"event\" type=\"button\">Event<\/button>\n          <button class=\"lp-qr-tab\" data-type=\"location\" type=\"button\">Location<\/button>\n          <button class=\"lp-qr-tab\" data-type=\"bitcoin\" type=\"button\">Bitcoin<\/button>\n        <\/div>\n      <\/div>\n\n      <!-- Step 2 -->\n      <div class=\"lp-qr-section\">\n        <div class=\"lp-qr-step\">\n          <span class=\"lp-qr-step-num\">2<\/span>\n          <h2>Enter Data<\/h2>\n        <\/div>\n\n        <div class=\"lp-qr-formwrap\">\n          <!-- TEXT -->\n          <div class=\"lp-qr-form is-show\" data-form=\"text\">\n            <label class=\"lp-qr-label\">Text<\/label>\n            <textarea class=\"lp-qr-input\" id=\"lpQrText\" rows=\"4\" placeholder=\"Enter any text...\"><\/textarea>\n          <\/div>\n\n          <!-- URL -->\n          <div class=\"lp-qr-form\" data-form=\"url\">\n            <label class=\"lp-qr-label\">URL<\/label>\n            <input class=\"lp-qr-input\" id=\"lpQrUrl\" type=\"url\" placeholder=\"https:\/\/example.com\" \/>\n            <div class=\"lp-qr-hint\">Tip: include https:\/\/ for best scan results.<\/div>\n          <\/div>\n\n          <!-- WIFI -->\n          <div class=\"lp-qr-form\" data-form=\"wifi\">\n            <div class=\"lp-qr-row\">\n              <div>\n                <label class=\"lp-qr-label\">Network Name (SSID)<\/label>\n                <input class=\"lp-qr-input\" id=\"lpQrWifiSsid\" type=\"text\" placeholder=\"Your Wi-Fi name\" \/>\n              <\/div>\n              <div>\n                <label class=\"lp-qr-label\">Security<\/label>\n                <select class=\"lp-qr-input\" id=\"lpQrWifiAuth\">\n                  <option value=\"WPA\" selected>WPA \/ WPA2<\/option>\n                  <option value=\"WEP\">WEP<\/option>\n                  <option value=\"nopass\">No Password<\/option>\n                <\/select>\n              <\/div>\n            <\/div>\n            <label class=\"lp-qr-label\">Password<\/label>\n            <input class=\"lp-qr-input\" id=\"lpQrWifiPwd\" type=\"text\" placeholder=\"Wi-Fi password\" \/>\n            <label class=\"lp-qr-check\">\n              <input id=\"lpQrWifiHidden\" type=\"checkbox\" \/>\n              Hidden network\n            <\/label>\n          <\/div>\n\n          <!-- EMAIL -->\n          <div class=\"lp-qr-form\" data-form=\"email\">\n            <label class=\"lp-qr-label\">To<\/label>\n            <input class=\"lp-qr-input\" id=\"lpQrEmailTo\" type=\"email\" placeholder=\"name@company.com\" \/>\n            <label class=\"lp-qr-label\">Subject<\/label>\n            <input class=\"lp-qr-input\" id=\"lpQrEmailSubject\" type=\"text\" placeholder=\"Subject (optional)\" \/>\n            <label class=\"lp-qr-label\">Body<\/label>\n            <textarea class=\"lp-qr-input\" id=\"lpQrEmailBody\" rows=\"4\" placeholder=\"Message (optional)\"><\/textarea>\n          <\/div>\n\n          <!-- PHONE -->\n          <div class=\"lp-qr-form\" data-form=\"phone\">\n            <label class=\"lp-qr-label\">Phone<\/label>\n            <input class=\"lp-qr-input\" id=\"lpQrPhone\" type=\"text\" placeholder=\"+65 9123 4567\" \/>\n            <div class=\"lp-qr-hint\">Encodes: tel:+&#8230;<\/div>\n          <\/div>\n\n          <!-- SMS -->\n          <div class=\"lp-qr-form\" data-form=\"sms\">\n            <label class=\"lp-qr-label\">Phone<\/label>\n            <input class=\"lp-qr-input\" id=\"lpQrSmsPhone\" type=\"text\" placeholder=\"+65 9123 4567\" \/>\n            <label class=\"lp-qr-label\">Message<\/label>\n            <textarea class=\"lp-qr-input\" id=\"lpQrSmsMsg\" rows=\"3\" placeholder=\"Your message...\"><\/textarea>\n          <\/div>\n\n          <!-- vCard -->\n          <div class=\"lp-qr-form\" data-form=\"vcard\">\n            <div class=\"lp-qr-row\">\n              <div>\n                <label class=\"lp-qr-label\">First Name<\/label>\n                <input class=\"lp-qr-input\" id=\"lpQrVFirst\" type=\"text\" placeholder=\"First name\" \/>\n              <\/div>\n              <div>\n                <label class=\"lp-qr-label\">Last Name<\/label>\n                <input class=\"lp-qr-input\" id=\"lpQrVLast\" type=\"text\" placeholder=\"Last name\" \/>\n              <\/div>\n            <\/div>\n            <label class=\"lp-qr-label\">Company<\/label>\n            <input class=\"lp-qr-input\" id=\"lpQrVOrg\" type=\"text\" placeholder=\"Company (optional)\" \/>\n            <label class=\"lp-qr-label\">Title<\/label>\n            <input class=\"lp-qr-input\" id=\"lpQrVTitle\" type=\"text\" placeholder=\"Job title (optional)\" \/>\n            <div class=\"lp-qr-row\">\n              <div>\n                <label class=\"lp-qr-label\">Phone<\/label>\n                <input class=\"lp-qr-input\" id=\"lpQrVPhone\" type=\"text\" placeholder=\"+86 ...\" \/>\n              <\/div>\n              <div>\n                <label class=\"lp-qr-label\">Email<\/label>\n                <input class=\"lp-qr-input\" id=\"lpQrVEmail\" type=\"email\" placeholder=\"name@company.com\" \/>\n              <\/div>\n            <\/div>\n            <label class=\"lp-qr-label\">Website<\/label>\n            <input class=\"lp-qr-input\" id=\"lpQrVUrl\" type=\"url\" placeholder=\"https:\/\/loongprt.com (optional)\" \/>\n            <label class=\"lp-qr-label\">Address<\/label>\n            <input class=\"lp-qr-input\" id=\"lpQrVAdr\" type=\"text\" placeholder=\"Street, City, Country (optional)\" \/>\n          <\/div>\n\n          <!-- MeCard -->\n          <div class=\"lp-qr-form\" data-form=\"mecard\">\n            <div class=\"lp-qr-row\">\n              <div>\n                <label class=\"lp-qr-label\">Name<\/label>\n                <input class=\"lp-qr-input\" id=\"lpQrMName\" type=\"text\" placeholder=\"Full name\" \/>\n              <\/div>\n              <div>\n                <label class=\"lp-qr-label\">Phone<\/label>\n                <input class=\"lp-qr-input\" id=\"lpQrMPhone\" type=\"text\" placeholder=\"+86 ...\" \/>\n              <\/div>\n            <\/div>\n            <label class=\"lp-qr-label\">Email<\/label>\n            <input class=\"lp-qr-input\" id=\"lpQrMEmail\" type=\"email\" placeholder=\"name@company.com\" \/>\n            <label class=\"lp-qr-label\">URL<\/label>\n            <input class=\"lp-qr-input\" id=\"lpQrMUrl\" type=\"url\" placeholder=\"https:\/\/...\" \/>\n            <label class=\"lp-qr-label\">Note<\/label>\n            <input class=\"lp-qr-input\" id=\"lpQrMNote\" type=\"text\" placeholder=\"Optional note\" \/>\n            <div class=\"lp-qr-hint\">Encodes: MECARD:&#8230;<\/div>\n          <\/div>\n\n          <!-- EVENT -->\n          <div class=\"lp-qr-form\" data-form=\"event\">\n            <label class=\"lp-qr-label\">Title<\/label>\n            <input class=\"lp-qr-input\" id=\"lpQrETitle\" type=\"text\" placeholder=\"Event title\" \/>\n            <div class=\"lp-qr-row\">\n              <div>\n                <label class=\"lp-qr-label\">Start (local)<\/label>\n                <input class=\"lp-qr-input\" id=\"lpQrEStart\" type=\"datetime-local\" \/>\n              <\/div>\n              <div>\n                <label class=\"lp-qr-label\">End (local)<\/label>\n                <input class=\"lp-qr-input\" id=\"lpQrEEnd\" type=\"datetime-local\" \/>\n              <\/div>\n            <\/div>\n            <label class=\"lp-qr-label\">Location<\/label>\n            <input class=\"lp-qr-input\" id=\"lpQrELoc\" type=\"text\" placeholder=\"Location (optional)\" \/>\n            <label class=\"lp-qr-label\">Description<\/label>\n            <textarea class=\"lp-qr-input\" id=\"lpQrEDesc\" rows=\"3\" placeholder=\"Notes (optional)\"><\/textarea>\n          <\/div>\n\n          <!-- LOCATION -->\n          <div class=\"lp-qr-form\" data-form=\"location\">\n            <div class=\"lp-qr-row\">\n              <div>\n                <label class=\"lp-qr-label\">Latitude<\/label>\n                <input class=\"lp-qr-input\" id=\"lpQrLat\" type=\"text\" placeholder=\"1.3521\" \/>\n              <\/div>\n              <div>\n                <label class=\"lp-qr-label\">Longitude<\/label>\n                <input class=\"lp-qr-input\" id=\"lpQrLng\" type=\"text\" placeholder=\"103.8198\" \/>\n              <\/div>\n            <\/div>\n            <div class=\"lp-qr-hint\">Encodes: geo:lat,lng<\/div>\n          <\/div>\n\n          <!-- BITCOIN -->\n          <div class=\"lp-qr-form\" data-form=\"bitcoin\">\n            <label class=\"lp-qr-label\">Wallet Address<\/label>\n            <input class=\"lp-qr-input\" id=\"lpQrBtcAddr\" type=\"text\" placeholder=\"bitcoin address...\" \/>\n            <div class=\"lp-qr-row\">\n              <div>\n                <label class=\"lp-qr-label\">Amount (optional)<\/label>\n                <input class=\"lp-qr-input\" id=\"lpQrBtcAmount\" type=\"text\" placeholder=\"0.001\" \/>\n              <\/div>\n              <div>\n                <label class=\"lp-qr-label\">Label (optional)<\/label>\n                <input class=\"lp-qr-input\" id=\"lpQrBtcLabel\" type=\"text\" placeholder=\"Donation\" \/>\n              <\/div>\n            <\/div>\n            <div class=\"lp-qr-hint\">Encodes: bitcoin:address?amount=&#8230;&#038;label=&#8230;<\/div>\n          <\/div>\n        <\/div>\n\n        <div class=\"lp-qr-actions\">\n          <button class=\"lp-qr-btn lp-qr-btn-primary\" id=\"lpQrGenerate\" type=\"button\">Generate<\/button>\n          <button class=\"lp-qr-btn\" id=\"lpQrReset\" type=\"button\">Reset<\/button>\n          <button class=\"lp-qr-btn lp-qr-btn-ghost\" id=\"lpQrPrintSafe\" type=\"button\">Print-Safe Mode<\/button>\n        <\/div>\n      <\/div>\n\n      <!-- Step 3: Design (Tabs) -->\n      <div class=\"lp-qr-section\">\n        <div class=\"lp-qr-step\">\n          <span class=\"lp-qr-step-num\">3<\/span>\n          <h2>Design<\/h2>\n        <\/div>\n\n        <div class=\"lp-qr-designTabs\" role=\"tablist\" aria-label=\"Design tabs\">\n          <button class=\"lp-qr-dtab is-active\" data-design-tab=\"colors\" type=\"button\">Colors<\/button>\n          <button class=\"lp-qr-dtab\" data-design-tab=\"shapes\" type=\"button\">Shapes<\/button>\n          <button class=\"lp-qr-dtab\" data-design-tab=\"logo\" type=\"button\">Logo<\/button>\n          <button class=\"lp-qr-dtab\" data-design-tab=\"sticker\" type=\"button\">Sticker<\/button>\n          <button class=\"lp-qr-dtab\" data-design-tab=\"export\" type=\"button\">Export<\/button>\n        <\/div>\n\n        <!-- COLORS PANEL -->\n        <div class=\"lp-qr-designPanel is-show\" data-design-panel=\"colors\">\n          <div class=\"lp-qr-panelTitle\">\n            <div>\n              <strong>Colors<\/strong>\n              <span>Foreground, background, transparency, gradient.<\/span>\n            <\/div>\n            <button class=\"lp-qr-btn lp-qr-btn-ghost\" id=\"lpQrPreset\" type=\"button\">Apply Preset Theme<\/button>\n          <\/div>\n\n          <div class=\"lp-qr-row\">\n            <div>\n              <label class=\"lp-qr-label\">Foreground<\/label>\n              <input class=\"lp-qr-color\" id=\"lpQrFg\" type=\"color\" value=\"#111827\" \/>\n            <\/div>\n            <div>\n              <label class=\"lp-qr-label\">Background<\/label>\n              <input class=\"lp-qr-color\" id=\"lpQrBg\" type=\"color\" value=\"#ffffff\" \/>\n            <\/div>\n          <\/div>\n\n          <label class=\"lp-qr-check\" style=\"margin-top:10px;\">\n            <input id=\"lpQrTransparent\" type=\"checkbox\" \/>\n            Transparent background (PNG)\n          <\/label>\n\n          <div class=\"lp-qr-subbox\" style=\"margin-top:10px;\">\n            <div class=\"lp-qr-row\">\n              <div>\n                <label class=\"lp-qr-label\" style=\"margin-top:0;\">Gradient<\/label>\n                <label class=\"lp-qr-check\" style=\"margin-top:8px;\">\n                  <input id=\"lpQrUseGradient\" type=\"checkbox\" \/>\n                  Use gradient on foreground (dots)\n                <\/label>\n              <\/div>\n              <div>\n                <label class=\"lp-qr-label\" style=\"margin-top:0;\">Gradient Type<\/label>\n                <select class=\"lp-qr-input\" id=\"lpQrGradType\">\n                  <option value=\"linear\" selected>Linear<\/option>\n                  <option value=\"radial\">Radial<\/option>\n                <\/select>\n              <\/div>\n            <\/div>\n\n            <div class=\"lp-qr-row\">\n              <div>\n                <label class=\"lp-qr-label\">Gradient Color 1<\/label>\n                <input class=\"lp-qr-color\" id=\"lpQrGradC1\" type=\"color\" value=\"#111827\" \/>\n              <\/div>\n              <div>\n                <label class=\"lp-qr-label\">Gradient Color 2<\/label>\n                <input class=\"lp-qr-color\" id=\"lpQrGradC2\" type=\"color\" value=\"#2563eb\" \/>\n              <\/div>\n            <\/div>\n\n            <div class=\"lp-qr-row\">\n              <div>\n                <label class=\"lp-qr-label\">Rotation (deg)<\/label>\n                <input class=\"lp-qr-input\" id=\"lpQrGradRot\" type=\"number\" min=\"0\" max=\"360\" value=\"0\" \/>\n              <\/div>\n              <div class=\"lp-qr-hint\">Tip: keep contrast high for best scanning.<\/div>\n            <\/div>\n          <\/div>\n        <\/div>\n\n        <!-- SHAPES PANEL -->\n        <div class=\"lp-qr-designPanel\" data-design-panel=\"shapes\">\n          <div class=\"lp-qr-panelTitle\">\n            <div>\n              <strong>Shapes<\/strong>\n              <span>Dots + Finder patterns (default is standard square).<\/span>\n            <\/div>\n          <\/div>\n\n          <div class=\"lp-qr-subbox\">\n            <div class=\"lp-qr-row\">\n              <div>\n                <label class=\"lp-qr-label\" style=\"margin-top:0;\">Data Dots Shape<\/label>\n                <select class=\"lp-qr-input\" id=\"lpQrDotType\">\n                  <option value=\"square\" selected>Square (Standard)<\/option>\n                  <option value=\"rounded\">Rounded<\/option>\n                  <option value=\"dots\">Dots<\/option>\n                  <option value=\"classy\">Classy<\/option>\n                  <option value=\"classy-rounded\">Classy Rounded<\/option>\n                  <option value=\"extra-rounded\">Extra Rounded<\/option>\n                <\/select>\n              <\/div>\n              <div>\n                <label class=\"lp-qr-label\" style=\"margin-top:0;\">Finder Outer<\/label>\n                <select class=\"lp-qr-input\" id=\"lpQrCornerOuter\">\n                  <option value=\"square\" selected>Square (Standard)<\/option>\n                  <option value=\"extra-rounded\">Extra Rounded<\/option>\n                  <option value=\"dot\">Dot<\/option>\n                <\/select>\n              <\/div>\n            <\/div>\n\n            <div class=\"lp-qr-row\">\n              <div>\n                <label class=\"lp-qr-label\" style=\"margin-top:0;\">Finder Inner<\/label>\n                <select class=\"lp-qr-input\" id=\"lpQrCornerInner\">\n                  <option value=\"square\" selected>Square (Standard)<\/option>\n                  <option value=\"dot\">Dot<\/option>\n                <\/select>\n              <\/div>\n              <div class=\"lp-qr-inline\">\n                <label class=\"lp-qr-check\" style=\"margin-top:28px;\">\n                  <input id=\"lpQrForceStandardFinder\" type=\"checkbox\" checked \/>\n                  Force standard finder patterns (recommended)\n                <\/label>\n              <\/div>\n            <\/div>\n          <\/div>\n        <\/div>\n\n        <!-- LOGO PANEL -->\n        <div class=\"lp-qr-designPanel\" data-design-panel=\"logo\">\n          <div class=\"lp-qr-panelTitle\">\n            <div>\n              <strong>Select a Logo<\/strong>\n              <span>Upload and style center logo.<\/span>\n            <\/div>\n            <button class=\"lp-qr-btn lp-qr-btn-danger\" id=\"lpQrRemoveLogo\" type=\"button\" disabled>Remove<\/button>\n          <\/div>\n\n          <div class=\"lp-qr-subbox\">\n            <div class=\"lp-qr-row\">\n              <div>\n                <label class=\"lp-qr-label\" style=\"margin-top:0;\">Upload Logo<\/label>\n                <input class=\"lp-qr-input\" id=\"lpQrLogoFile\" type=\"file\" accept=\"image\/*\" \/>\n                <div class=\"lp-qr-hint\">Tip: keep logo under 2MB. ECC auto switches to H.<\/div>\n              <\/div>\n\n              <div>\n                <label class=\"lp-qr-label\" style=\"margin-top:0;\">Logo Size<\/label>\n                <input class=\"lp-qr-input\" id=\"lpQrLogoSize\" type=\"range\" min=\"12\" max=\"30\" value=\"20\" \/>\n                <div class=\"lp-qr-hint\">Recommended 18\u201322%.<\/div>\n              <\/div>\n            <\/div>\n\n            <div class=\"lp-qr-row\">\n              <div>\n                <label class=\"lp-qr-label\">Logo Shape<\/label>\n                <select class=\"lp-qr-input\" id=\"lpQrLogoShape\">\n                  <option value=\"square\" selected>Square<\/option>\n                  <option value=\"rounded\">Rounded<\/option>\n                  <option value=\"circle\">Circle<\/option>\n                <\/select>\n              <\/div>\n              <div>\n                <label class=\"lp-qr-label\">Logo Corner Radius<\/label>\n                <input class=\"lp-qr-input\" id=\"lpQrLogoRadius\" type=\"number\" min=\"0\" max=\"64\" value=\"16\" \/>\n              <\/div>\n            <\/div>\n\n            <div class=\"lp-qr-row\">\n              <div>\n                <label class=\"lp-qr-label\">Logo Padding (white plate)<\/label>\n                <input class=\"lp-qr-input\" id=\"lpQrLogoPad\" type=\"number\" min=\"0\" max=\"40\" value=\"8\" \/>\n              <\/div>\n              <div>\n                <label class=\"lp-qr-label\">Logo Border<\/label>\n                <div class=\"lp-qr-row\" style=\"grid-template-columns:.9fr 1.1fr;\">\n                  <input class=\"lp-qr-input\" id=\"lpQrLogoBorderW\" type=\"number\" min=\"0\" max=\"12\" value=\"0\" \/>\n                  <input class=\"lp-qr-color\" id=\"lpQrLogoBorderC\" type=\"color\" value=\"#e5e7eb\" \/>\n                <\/div>\n                <div class=\"lp-qr-hint\">Width(px) + Color<\/div>\n              <\/div>\n            <\/div>\n\n            <label class=\"lp-qr-check\" style=\"margin-top:6px;\">\n              <input id=\"lpQrLogoHideBgDots\" type=\"checkbox\" checked \/>\n              Clear dots behind logo (safer scanning)\n            <\/label>\n          <\/div>\n        <\/div>\n\n        <!-- STICKER PANEL -->\n        <div class=\"lp-qr-designPanel\" data-design-panel=\"sticker\">\n          <div class=\"lp-qr-panelTitle\">\n            <div>\n              <strong>Sticker \/ Frame<\/strong>\n              <span>Applies to preview + PNG export (SVG is QR-only).<\/span>\n            <\/div>\n          <\/div>\n\n          <div class=\"lp-qr-subbox\">\n            <div class=\"lp-qr-row\">\n              <div>\n                <label class=\"lp-qr-label\" style=\"margin-top:0;\">Template<\/label>\n                <select class=\"lp-qr-input\" id=\"lpQrStickerType\">\n                  <option value=\"none\" selected>None<\/option>\n                  <option value=\"topBadge\">Top Badge (SCAN ME)<\/option>\n                  <option value=\"bottomLabel\">Bottom Label<\/option>\n                  <option value=\"outline\">Outline Frame<\/option>\n                  <option value=\"card\">Rounded Card<\/option>\n                <\/select>\n              <\/div>\n              <div>\n                <label class=\"lp-qr-label\" style=\"margin-top:0;\">Sticker Radius<\/label>\n                <input class=\"lp-qr-input\" id=\"lpQrStickerRadius\" type=\"number\" min=\"0\" max=\"48\" value=\"18\" \/>\n              <\/div>\n            <\/div>\n\n            <div class=\"lp-qr-row\">\n              <div>\n                <label class=\"lp-qr-label\">Sticker Padding<\/label>\n                <input class=\"lp-qr-input\" id=\"lpQrStickerPad\" type=\"number\" min=\"0\" max=\"80\" value=\"18\" \/>\n              <\/div>\n              <div>\n                <label class=\"lp-qr-label\">Sticker Border Width<\/label>\n                <input class=\"lp-qr-input\" id=\"lpQrStickerBorderW\" type=\"number\" min=\"0\" max=\"20\" value=\"0\" \/>\n              <\/div>\n            <\/div>\n\n            <div class=\"lp-qr-row\">\n              <div>\n                <label class=\"lp-qr-label\">Sticker Background<\/label>\n                <input class=\"lp-qr-color\" id=\"lpQrStickerBg\" type=\"color\" value=\"#ffffff\" \/>\n              <\/div>\n              <div>\n                <label class=\"lp-qr-label\">Sticker Border Color<\/label>\n                <input class=\"lp-qr-color\" id=\"lpQrStickerBorderC\" type=\"color\" value=\"#e5e7eb\" \/>\n              <\/div>\n            <\/div>\n\n            <div class=\"lp-qr-row\">\n              <div>\n                <label class=\"lp-qr-label\">Text<\/label>\n                <input class=\"lp-qr-input\" id=\"lpQrStickerText\" type=\"text\" value=\"SCAN ME\" \/>\n              <\/div>\n              <div>\n                <label class=\"lp-qr-label\">Text Color<\/label>\n                <input class=\"lp-qr-color\" id=\"lpQrStickerTextC\" type=\"color\" value=\"#111827\" \/>\n              <\/div>\n            <\/div>\n\n            <div class=\"lp-qr-row\">\n              <div>\n                <label class=\"lp-qr-label\">Text Size (px)<\/label>\n                <input class=\"lp-qr-input\" id=\"lpQrStickerTextS\" type=\"number\" min=\"10\" max=\"64\" value=\"20\" \/>\n              <\/div>\n              <div>\n                <label class=\"lp-qr-label\">Extra Bottom Space (px)<\/label>\n                <input class=\"lp-qr-input\" id=\"lpQrStickerBottomH\" type=\"number\" min=\"0\" max=\"160\" value=\"60\" \/>\n              <\/div>\n            <\/div>\n\n            <label class=\"lp-qr-check\" style=\"margin-top:6px;\">\n              <input id=\"lpQrStickerShadow\" type=\"checkbox\" checked \/>\n              Add subtle shadow\n            <\/label>\n          <\/div>\n        <\/div>\n\n        <!-- EXPORT PANEL -->\n        <div class=\"lp-qr-designPanel\" data-design-panel=\"export\">\n          <div class=\"lp-qr-panelTitle\">\n            <div>\n              <strong>Export &#038; QR Options<\/strong>\n              <span>Size, margin, ECC, export scale.<\/span>\n            <\/div>\n          <\/div>\n\n          <div class=\"lp-qr-subbox\">\n            <div class=\"lp-qr-row\">\n              <div>\n                <label class=\"lp-qr-label\" style=\"margin-top:0;\">QR Size (px)<\/label>\n                <input class=\"lp-qr-input\" id=\"lpQrSize\" type=\"number\" min=\"128\" max=\"1024\" value=\"320\" \/>\n                <div class=\"lp-qr-hint\">Preview auto-fits. Export uses real size.<\/div>\n              <\/div>\n              <div>\n                <label class=\"lp-qr-label\" style=\"margin-top:0;\">Quiet Zone (margin)<\/label>\n                <input class=\"lp-qr-input\" id=\"lpQrMargin\" type=\"number\" min=\"0\" max=\"64\" value=\"12\" \/>\n              <\/div>\n            <\/div>\n\n            <div class=\"lp-qr-row\">\n              <div>\n                <label class=\"lp-qr-label\">Error Correction<\/label>\n                <select class=\"lp-qr-input\" id=\"lpQrEcc\">\n                  <option value=\"L\">L (7%)<\/option>\n                  <option value=\"M\" selected>M (15%)<\/option>\n                  <option value=\"Q\">Q (25%)<\/option>\n                  <option value=\"H\">H (30%)<\/option>\n                <\/select>\n                <div class=\"lp-qr-hint\" id=\"lpQrEccHint\"><\/div>\n              <\/div>\n              <div>\n                <label class=\"lp-qr-label\">Export Scale (PNG)<\/label>\n                <select class=\"lp-qr-input\" id=\"lpQrExportScale\">\n                  <option value=\"1\" selected>1\u00d7<\/option>\n                  <option value=\"2\">2\u00d7<\/option>\n                  <option value=\"4\">4\u00d7<\/option>\n                <\/select>\n                <div class=\"lp-qr-hint\">Use 2\u00d7\/4\u00d7 for print quality.<\/div>\n              <\/div>\n            <\/div>\n\n            <label class=\"lp-qr-check\" style=\"margin-top:6px;\">\n              <input id=\"lpQrLiveUpdate\" type=\"checkbox\" checked \/>\n              Live update preview while typing\n            <\/label>\n          <\/div>\n        <\/div>\n      <\/div>\n    <\/div>\n\n    <!-- RIGHT -->\n    <div class=\"lp-qr-card lp-qr-preview\">\n      <div class=\"lp-qr-preview-top\">\n        <h2>Preview<\/h2>\n        <div class=\"lp-qr-preview-sub\">Preview auto-fits. Export uses real size.<\/div>\n      <\/div>\n\n      <div class=\"lp-qr-canvas-wrap\">\n        <div id=\"lpQrPreviewFrame\" class=\"lp-qr-preview-frame\">\n          <div id=\"lpQrCanvas\" class=\"lp-qr-canvas\" aria-label=\"QR preview\"><\/div>\n          <div id=\"lpQrPreviewText\" class=\"lp-qr-preview-text\" style=\"display:none;\"><\/div>\n        <\/div>\n\n        <div class=\"lp-qr-err\" id=\"lpQrErr\" style=\"display:none;\"><\/div>\n      <\/div>\n\n      <div class=\"lp-qr-actions\">\n        <button class=\"lp-qr-btn lp-qr-btn-primary\" id=\"lpQrDownloadPng\" type=\"button\" disabled>Download PNG<\/button>\n        <button class=\"lp-qr-btn\" id=\"lpQrDownloadSvg\" type=\"button\" disabled>Download SVG<\/button>\n        <button class=\"lp-qr-btn\" id=\"lpQrCopyEmbed\" type=\"button\" disabled>Copy Embed<\/button>\n      <\/div>\n\n      <div class=\"lp-qr-embed\">\n        <label class=\"lp-qr-label\">Embed HTML (PNG base64)<\/label>\n        <input class=\"lp-qr-input\" id=\"lpQrEmbed\" type=\"text\" readonly value=\"\" \/>\n        <div class=\"lp-qr-hint\">Embed is PNG data URL (no external request).<\/div>\n      <\/div>\n\n      <div class=\"lp-qr-footnote\">\n        This is a static QR generator. For tracking\/editable QR, you\u2019d need a backend short-link service.\n      <\/div>\n    <\/div>\n  <\/div>\n<\/div>\n\n<!-- QR library -->\n<script src=\"https:\/\/unpkg.com\/qr-code-styling@1.6.0\/lib\/qr-code-styling.js\"><\/script>\n\n<style>\n\n\/* ===== Namespaced styles ===== *\/\n#lp-qr-widget.lp-qr{font-family:system-ui,-apple-system,Segoe UI,Roboto,Arial,sans-serif;color:#0b1220;}\n#lp-qr-widget .lp-qr-head{margin:0 0 14px;}\n#lp-qr-widget .lp-qr-title{padding:18px 18px 6px;}\n#lp-qr-widget .lp-qr-badge{display:inline-block;font-size:12px;font-weight:800;letter-spacing:.2px;padding:6px 10px;border-radius:999px;background:rgba(0,166,255,.12);color:#0b5cff;margin-bottom:10px;}\n#lp-qr-widget h1{margin:0 0 6px;font-size:22px;line-height:1.2;}\n#lp-qr-widget p{margin:0;color:#4b5563;font-size:14px;}\n\n#lp-qr-widget .lp-qr-grid{display:grid;grid-template-columns:1.25fr .9fr;gap:16px;align-items:start;}\n@media (max-width:980px){#lp-qr-widget .lp-qr-grid{grid-template-columns:1fr;}}\n\n#lp-qr-widget .lp-qr-card{background:#fff;border:1px solid rgba(17,24,39,.10);border-radius:18px;box-shadow:0 10px 30px rgba(17,24,39,.06);overflow:hidden;}\n#lp-qr-widget .lp-qr-builder{padding:16px;}\n#lp-qr-widget .lp-qr-preview{padding:16px;}\n\n#lp-qr-widget .lp-qr-section{padding:14px;border-radius:14px;background:linear-gradient(180deg,#fbfdff,#ffffff);border:1px solid rgba(17,24,39,.06);margin-bottom:12px;}\n#lp-qr-widget .lp-qr-step{display:flex;gap:10px;align-items:center;margin-bottom:10px;}\n#lp-qr-widget .lp-qr-step-num{width:26px;height:26px;border-radius:8px;background:#111827;color:#fff;display:flex;align-items:center;justify-content:center;font-weight:900;font-size:13px;}\n#lp-qr-widget .lp-qr-section h2{margin:0;font-size:16px;}\n\n#lp-qr-widget .lp-qr-tabs{display:flex;flex-wrap:wrap;gap:8px;margin-top:10px;}\n#lp-qr-widget .lp-qr-tab{border:1px solid rgba(17,24,39,.14);background:#fff;border-radius:999px;padding:8px 12px;font-weight:800;font-size:13px;cursor:pointer;transition:.15s;}\n#lp-qr-widget .lp-qr-tab:hover{transform:translateY(-1px);}\n#lp-qr-widget .lp-qr-tab.is-active{background:#111827;color:#fff;border-color:#111827;}\n\n#lp-qr-widget .lp-qr-form{display:none;}\n#lp-qr-widget .lp-qr-form.is-show{display:block;}\n#lp-qr-widget .lp-qr-label{display:block;font-size:12px;font-weight:900;color:#374151;margin:10px 0 6px;}\n#lp-qr-widget .lp-qr-input{width:100%;border:1px solid rgba(17,24,39,.16);border-radius:12px;padding:10px 12px;font-size:14px;outline:none;box-sizing:border-box;}\n#lp-qr-widget .lp-qr-input:focus{border-color:rgba(0,166,255,.9);box-shadow:0 0 0 4px rgba(0,166,255,.12);}\n#lp-qr-widget textarea.lp-qr-input{resize:vertical;min-height:92px;}\n\n#lp-qr-widget .lp-qr-row{display:grid;grid-template-columns:1fr 1fr;gap:10px;}\n@media (max-width:620px){#lp-qr-widget .lp-qr-row{grid-template-columns:1fr;}}\n#lp-qr-widget .lp-qr-hint{font-size:12px;color:#6b7280;margin-top:8px;}\n#lp-qr-widget .lp-qr-inline{display:flex;align-items:end;padding-bottom:6px;}\n#lp-qr-widget .lp-qr-check{display:flex;gap:8px;align-items:center;font-size:13px;color:#374151;margin-top:10px;}\n#lp-qr-widget .lp-qr-color{width:100%;height:42px;border-radius:12px;border:1px solid rgba(17,24,39,.16);padding:6px;background:#fff;box-sizing:border-box;}\n\n#lp-qr-widget .lp-qr-actions{display:flex;gap:10px;flex-wrap:wrap;margin-top:12px;}\n#lp-qr-widget .lp-qr-btn{border:1px solid rgba(17,24,39,.16);background:#fff;border-radius:12px;padding:10px 12px;font-weight:900;font-size:13px;cursor:pointer;transition:.15s;}\n#lp-qr-widget .lp-qr-btn:hover{transform:translateY(-1px);}\n#lp-qr-widget .lp-qr-btn:disabled{opacity:.55;cursor:not-allowed;transform:none;}\n#lp-qr-widget .lp-qr-btn-primary{background:#00a6ff;border-color:#00a6ff;color:#fff;}\n#lp-qr-widget .lp-qr-btn-ghost{background:rgba(17,24,39,.04);}\n#lp-qr-widget .lp-qr-btn-danger{border-color:rgba(239,68,68,.35);background:rgba(239,68,68,.06);color:#b91c1c;}\n\n#lp-qr-widget .lp-qr-preview-top{display:flex;align-items:baseline;justify-content:space-between;gap:10px;margin-bottom:10px;}\n#lp-qr-widget .lp-qr-preview-top h2{margin:0;font-size:16px;}\n#lp-qr-widget .lp-qr-preview-sub{font-size:12px;color:#6b7280;}\n\n#lp-qr-widget .lp-qr-canvas-wrap{display:grid;place-items:center;padding:16px;border-radius:16px;border:1px dashed rgba(17,24,39,.18);background:#fafafa;}\n#lp-qr-widget .lp-qr-err{margin-top:10px;color:#b91c1c;font-weight:900;font-size:12px;}\n\n#lp-qr-widget .lp-qr-embed{margin-top:14px;}\n#lp-qr-widget .lp-qr-footnote{margin-top:12px;font-size:12px;color:#6b7280;}\n\n#lp-qr-widget .lp-qr-subbox{margin-top:10px;padding:12px;border-radius:14px;border:1px solid rgba(17,24,39,.08);background:#fff;}\n\n\/* ===== Preview sizing fix ===== *\/\n#lp-qr-widget .lp-qr-preview-frame{\n  width: 360px;\n  max-width: 100%;\n  display:grid;\n  place-items:center;\n  gap:10px;\n  padding:16px;\n  border-radius:16px;\n  background:transparent;\n}\n@media (max-width:980px){#lp-qr-widget .lp-qr-preview-frame{width:min(360px, 90vw);}}\n\n#lp-qr-widget .lp-qr-canvas{\n  width: 320px;\n  height: 320px;\n  display:grid;\n  place-items:center;\n}\n@media (max-width:980px){#lp-qr-widget .lp-qr-canvas{width:min(320px, 80vw);height:min(320px, 80vw);}}\n\n\/* Ensure generated QR never overflows preview window *\/\n#lp-qr-widget .lp-qr-canvas canvas,\n#lp-qr-widget .lp-qr-canvas svg,\n#lp-qr-widget .lp-qr-canvas img{\n  max-width:100%;\n  max-height:100%;\n  width:100% !important;\n  height:100% !important;\n  object-fit:contain;\n}\n\n\/* Sticker preview text *\/\n#lp-qr-widget .lp-qr-preview-text{\n  width:100%;\n  text-align:center;\n  font-weight:900;\n  line-height:1.1;\n}\n\n\/* ===== Design Tabs ===== *\/\n#lp-qr-widget .lp-qr-designTabs{\n  display:flex;\n  flex-wrap:wrap;\n  gap:8px;\n  margin-top:10px;\n  margin-bottom:12px;\n}\n#lp-qr-widget .lp-qr-dtab{\n  border:1px solid rgba(17,24,39,.14);\n  background:#fff;\n  border-radius:12px;\n  padding:10px 12px;\n  font-weight:900;\n  font-size:13px;\n  cursor:pointer;\n  transition:.15s;\n}\n#lp-qr-widget .lp-qr-dtab:hover{transform:translateY(-1px);}\n#lp-qr-widget .lp-qr-dtab.is-active{\n  background:#111827;\n  color:#fff;\n  border-color:#111827;\n}\n\n#lp-qr-widget .lp-qr-designPanel{\n  display:none;\n  padding:12px;\n  border-radius:14px;\n  border:1px solid rgba(17,24,39,.08);\n  background:#fff;\n}\n#lp-qr-widget .lp-qr-designPanel.is-show{display:block;}\n\n#lp-qr-widget .lp-qr-panelTitle{\n  display:flex;\n  align-items:flex-start;\n  justify-content:space-between;\n  gap:12px;\n  margin-bottom:10px;\n}\n#lp-qr-widget .lp-qr-panelTitle strong{\n  display:block;\n  font-size:14px;\n  line-height:1.2;\n}\n#lp-qr-widget .lp-qr-panelTitle span{\n  display:block;\n  font-size:12px;\n  color:#6b7280;\n  margin-top:4px;\n}\n\n<\/style>\n<script>\n(function () {\n  \"use strict\";\n\n  \/\/ =========================================================\n  \/\/ Robust init for WordPress\/Flatsome\/WP Rocket environments\n  \/\/ - waits for #lp-qr-widget exists\n  \/\/ - waits for QRCodeStyling loaded\n  \/\/ - prevents double init\n  \/\/ =========================================================\n\n  const ROOT_ID = \"lp-qr-widget\";\n  const MAX_TRIES = 180;       \/\/ ~180 * 250ms = 45s max wait\n  const TRY_INTERVAL = 250;\n\n  function $(sel, root = document) { return root.querySelector(sel); }\n  function $$(sel, root = document) { return Array.from(root.querySelectorAll(sel)); }\n\n  function waitForReady(cb) {\n    let tries = 0;\n\n    const tick = () => {\n      tries++;\n\n      const root = document.getElementById(ROOT_ID);\n\n      \/\/ Root not in DOM yet (UX Builder async insert \/ shortcode render \/ tab lazy render)\n      if (!root) {\n        if (tries < MAX_TRIES) return setTimeout(tick, TRY_INTERVAL);\n        return; \/\/ give up silently\n      }\n\n      \/\/ Prevent double init if scripts are injected twice or page builder re-renders\n      if (root.dataset.lpQrInited === \"1\") return;\n\n      \/\/ Library might be delayed by WP Rocket\n      if (typeof window.QRCodeStyling === \"undefined\") {\n        \/\/ Optional: show a gentle message if user already sees the UI\n        const err = $(\"#lpQrErr\", root);\n        if (err) {\n          err.style.display = \"block\";\n          err.textContent = \"Loading QR library\u2026 (If this stays, please exclude 'qr-code-styling' from JS delay\/defer.)\";\n        }\n\n        if (tries < MAX_TRIES) return setTimeout(tick, TRY_INTERVAL);\n        return;\n      }\n\n      \/\/ Good to init\n      root.dataset.lpQrInited = \"1\";\n      cb(root);\n    };\n\n    \/\/ Try immediately + after DOM ready\n    if (document.readyState === \"loading\") {\n      document.addEventListener(\"DOMContentLoaded\", tick, { once: true });\n    } else {\n      tick();\n    }\n  }\n\n  \/\/ =========================================================\n  \/\/ Main app (your original logic, mostly unchanged)\n  \/\/ =========================================================\n  waitForReady(function (root) {\n\n    \/\/ -------------------------\n    \/\/ Helpers\n    \/\/ -------------------------\n    const clamp = (n, min, max) => Math.min(Math.max(n, min), max);\n\n    function escapeWifi(s) { return (s || \"\").replace(\/([\\;,:\"])\/g, \"\\$1\"); }\n\n    function dateToICS(dtLocal) {\n      if (!dtLocal) return \"\";\n      const d = new Date(dtLocal);\n      if (Number.isNaN(d.getTime())) return \"\";\n      const pad = (n) => String(n).padStart(2, \"0\");\n      return (\n        d.getUTCFullYear() +\n        pad(d.getUTCMonth() + 1) +\n        pad(d.getUTCDate()) + \"T\" +\n        pad(d.getUTCHours()) +\n        pad(d.getUTCMinutes()) +\n        pad(d.getUTCSeconds()) + \"Z\"\n      );\n    }\n\n    function vcardEscapeText(s) {\n      return (s || \"\")\n        .replace(\/\\\/g, \"\\\\\")\n        .replace(\/n\/g, \"\\n\")\n        .replace(\/;\/g, \"\\;\")\n        .replace(\/,\/g, \"\\,\")\n        .trim();\n    }\n\n    function qpEncodeUtf8(s) {\n      const str = (s || \"\").toString();\n      if (!str) return \"\";\n      const enc = new TextEncoder();\n      const bytes = enc.encode(str);\n      let out = \"\";\n      for (const b of bytes) out += \"=\" + b.toString(16).toUpperCase().padStart(2, \"0\");\n      return out;\n    }\n\n    function joinVcardLines(lines) {\n      return lines.join(\"rn\");\n    }\n\n    function showError(msg) {\n      const el = $(\"#lpQrErr\", root);\n      if (!el) return;\n      if (!msg) {\n        el.style.display = \"none\";\n        el.textContent = \"\";\n        return;\n      }\n      el.style.display = \"block\";\n      el.textContent = msg;\n    }\n\n    function fileToDataUrl(file) {\n      return new Promise((resolve, reject) => {\n        const r = new FileReader();\n        r.onload = () => resolve(String(r.result || \"\"));\n        r.onerror = () => reject(new Error(\"Failed to read image\"));\n        r.readAsDataURL(file);\n      });\n    }\n\n    function loadImage(src) {\n      return new Promise((resolve, reject) => {\n        const img = new Image();\n        img.onload = () => resolve(img);\n        img.onerror = () => reject(new Error(\"Image load failed\"));\n        img.src = src;\n      });\n    }\n\n    function roundRectPath(ctx, x, y, w, h, r) {\n      const rr = Math.min(r, w \/ 2, h \/ 2);\n      ctx.beginPath();\n      ctx.moveTo(x + rr, y);\n      ctx.arcTo(x + w, y, x + w, y + h, rr);\n      ctx.arcTo(x + w, y + h, x, y + h, rr);\n      ctx.arcTo(x, y + h, x, y, rr);\n      ctx.arcTo(x, y, x + w, y, rr);\n      ctx.closePath();\n    }\n\n    function drawShadow(ctx, x, y, w, h, r) {\n      ctx.save();\n      ctx.shadowColor = \"rgba(17,24,39,.18)\";\n      ctx.shadowBlur = 18;\n      ctx.shadowOffsetY = 8;\n      roundRectPath(ctx, x, y, w, h, r);\n      ctx.fillStyle = \"rgba(255,255,255,.01)\";\n      ctx.fill();\n      ctx.restore();\n    }\n\n    \/\/ -------------------------\n    \/\/ State\n    \/\/ -------------------------\n    let logoDataUrl = \"\";\n    let lastData = \"\";\n    let qr = null;\n\n    \/\/ -------------------------\n    \/\/ Design tab switching\n    \/\/ -------------------------\n    function setDesignTab(name) {\n      $$(\".lp-qr-dtab\", root).forEach(b => {\n        b.classList.toggle(\"is-active\", b.getAttribute(\"data-design-tab\") === name);\n      });\n      $$(\".lp-qr-designPanel\", root).forEach(p => {\n        p.classList.toggle(\"is-show\", p.getAttribute(\"data-design-panel\") === name);\n      });\n    }\n\n    \/\/ -------------------------\n    \/\/ Payload builders\n    \/\/ -------------------------\n    function buildPayload(type) {\n      const err = (msg) => ({ ok: false, msg, data: \"\" });\n\n      if (type === \"text\") {\n        const v = ($(\"#lpQrText\", root).value || \"\").trim();\n        if (!v) return err(\"Please enter text.\");\n        return { ok: true, data: v };\n      }\n\n      if (type === \"url\") {\n        const v = ($(\"#lpQrUrl\", root).value || \"\").trim();\n        if (!v) return err(\"Please enter a URL.\");\n        const fixed = \/^https?:\/\/\/i.test(v) ? v : (\"https:\/\/\" + v);\n        return { ok: true, data: fixed };\n      }\n\n      if (type === \"wifi\") {\n        const ssid = ($(\"#lpQrWifiSsid\", root).value || \"\").trim();\n        const auth = $(\"#lpQrWifiAuth\", root).value;\n        const pwd = ($(\"#lpQrWifiPwd\", root).value || \"\");\n        const hidden = $(\"#lpQrWifiHidden\", root).checked ? \"true\" : \"false\";\n        if (!ssid) return err(\"Please enter SSID.\");\n        if (auth !== \"nopass\" && !pwd) return err(\"Please enter Wi-Fi password (or choose No Password).\");\n        const payload = `WIFI:T:${auth};S:${escapeWifi(ssid)};P:${escapeWifi(pwd)};H:${hidden};;`;\n        return { ok: true, data: payload };\n      }\n\n      if (type === \"email\") {\n        const to = ($(\"#lpQrEmailTo\", root).value || \"\").trim();\n        const subject = ($(\"#lpQrEmailSubject\", root).value || \"\").trim();\n        const body = ($(\"#lpQrEmailBody\", root).value || \"\").trim();\n        if (!to) return err(\"Please enter recipient email.\");\n        const qs = new URLSearchParams();\n        if (subject) qs.set(\"subject\", subject);\n        if (body) qs.set(\"body\", body);\n        const payload = `mailto:${to}${qs.toString() ? \"?\" + qs.toString() : \"\"}`;\n        return { ok: true, data: payload };\n      }\n\n      if (type === \"phone\") {\n        const phone = ($(\"#lpQrPhone\", root).value || \"\").trim();\n        if (!phone) return err(\"Please enter phone number.\");\n        return { ok: true, data: `tel:${phone}` };\n      }\n\n      if (type === \"sms\") {\n        const phone = ($(\"#lpQrSmsPhone\", root).value || \"\").trim();\n        const msg = ($(\"#lpQrSmsMsg\", root).value || \"\").trim();\n        if (!phone) return err(\"Please enter phone number.\");\n        return { ok: true, data: `smsto:${phone}:${msg}` };\n      }\n\n      if (type === \"vcard\") {\n        const fn = ($(\"#lpQrVFirst\", root).value || \"\").trim();\n        const ln = ($(\"#lpQrVLast\", root).value || \"\").trim();\n        const org = ($(\"#lpQrVOrg\", root).value || \"\").trim();\n        const title = ($(\"#lpQrVTitle\", root).value || \"\").trim();\n        const phone = ($(\"#lpQrVPhone\", root).value || \"\").trim();\n        const email = ($(\"#lpQrVEmail\", root).value || \"\").trim();\n        const url = ($(\"#lpQrVUrl\", root).value || \"\").trim();\n        const adr = ($(\"#lpQrVAdr\", root).value || \"\").trim();\n\n        if (!fn && !ln) return err(\"Please enter at least a name.\");\n\n        const fullName = [fn, ln].filter(Boolean).join(\" \").trim() || (fn || ln);\n\n        const lines = [\n          \"BEGIN:VCARD\",\n          \"VERSION:3.0\",\n          `N;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:${qpEncodeUtf8(ln)};${qpEncodeUtf8(fn)};;;`,\n          `FN;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:${qpEncodeUtf8(fullName)}`\n        ];\n\n        if (org) lines.push(`ORG;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:${qpEncodeUtf8(org)}`);\n        if (title) lines.push(`TITLE;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:${qpEncodeUtf8(title)}`);\n\n        if (phone) lines.push(`TEL;TYPE=CELL:${vcardEscapeText(phone)}`);\n        if (email) lines.push(`EMAIL:${vcardEscapeText(email)}`);\n        if (url) lines.push(`URL:${vcardEscapeText(url)}`);\n\n        if (adr) lines.push(`ADR;TYPE=WORK;CHARSET=UTF-8;ENCODING=QUOTED-PRINTABLE:;;${qpEncodeUtf8(adr)};;;;`);\n\n        lines.push(\"END:VCARD\");\n\n        return { ok: true, data: joinVcardLines(lines) };\n      }\n\n      if (type === \"mecard\") {\n        const name = ($(\"#lpQrMName\", root).value || \"\").trim();\n        const phone = ($(\"#lpQrMPhone\", root).value || \"\").trim();\n        const email = ($(\"#lpQrMEmail\", root).value || \"\").trim();\n        const url = ($(\"#lpQrMUrl\", root).value || \"\").trim();\n        const note = ($(\"#lpQrMNote\", root).value || \"\").trim();\n        if (!name && !phone && !email && !url) return err(\"Please enter at least one field (name\/phone\/email\/url).\");\n\n        const parts = [];\n        if (name) parts.push(`N:${name}`);\n        if (phone) parts.push(`TEL:${phone}`);\n        if (email) parts.push(`EMAIL:${email}`);\n        if (url) parts.push(`URL:${url}`);\n        if (note) parts.push(`NOTE:${note}`);\n        const payload = `MECARD:${parts.join(\";\")};;`;\n        return { ok: true, data: payload };\n      }\n\n      if (type === \"event\") {\n        const title = ($(\"#lpQrETitle\", root).value || \"\").trim();\n        const start = $(\"#lpQrEStart\", root).value;\n        const end = $(\"#lpQrEEnd\", root).value;\n        const loc = ($(\"#lpQrELoc\", root).value || \"\").trim();\n        const desc = ($(\"#lpQrEDesc\", root).value || \"\").trim();\n        if (!title) return err(\"Please enter event title.\");\n        if (!start) return err(\"Please set start time.\");\n\n        const dtStart = dateToICS(start);\n        const dtEnd = end ? dateToICS(end) : \"\";\n        const uid = \"lp-\" + Math.random().toString(16).slice(2) + \"@loongprt\";\n        const lines = [\n          \"BEGIN:VCALENDAR\",\n          \"VERSION:2.0\",\n          \"PRODID:-\/\/Loongprt\/\/QR Generator\/\/EN\",\n          \"BEGIN:VEVENT\",\n          `UID:${uid}`,\n          `SUMMARY:${title.replace(\/n\/g, \" \")}`,\n          dtStart ? `DTSTART:${dtStart}` : \"\",\n          dtEnd ? `DTEND:${dtEnd}` : \"\",\n          loc ? `LOCATION:${loc.replace(\/n\/g, \" \")}` : \"\",\n          desc ? `DESCRIPTION:${desc.replace(\/n\/g, \"\\n\")}` : \"\",\n          \"END:VEVENT\",\n          \"END:VCALENDAR\"\n        ].filter(Boolean);\n        return { ok: true, data: lines.join(\"n\") };\n      }\n\n      if (type === \"location\") {\n        const lat = ($(\"#lpQrLat\", root).value || \"\").trim();\n        const lng = ($(\"#lpQrLng\", root).value || \"\").trim();\n        if (!lat || !lng) return err(\"Please enter both latitude and longitude.\");\n        return { ok: true, data: `geo:${lat},${lng}` };\n      }\n\n      if (type === \"bitcoin\") {\n        const addr = ($(\"#lpQrBtcAddr\", root).value || \"\").trim();\n        const amount = ($(\"#lpQrBtcAmount\", root).value || \"\").trim();\n        const label = ($(\"#lpQrBtcLabel\", root).value || \"\").trim();\n        if (!addr) return err(\"Please enter wallet address.\");\n        const qs = new URLSearchParams();\n        if (amount) qs.set(\"amount\", amount);\n        if (label) qs.set(\"label\", label);\n        const payload = `bitcoin:${addr}${qs.toString() ? \"?\" + qs.toString() : \"\"}`;\n        return { ok: true, data: payload };\n      }\n\n      return err(\"Unsupported type.\");\n    }\n\n    \/\/ -------------------------\n    \/\/ Read UI settings\n    \/\/ -------------------------\n    function hasLogo() { return !!logoDataUrl; }\n\n    function readQRSettings() {\n      const size = clamp(parseInt($(\"#lpQrSize\", root).value || \"320\", 10), 128, 1024);\n      const margin = clamp(parseInt($(\"#lpQrMargin\", root).value || \"12\", 10), 0, 64);\n\n      const userEcc = $(\"#lpQrEcc\", root).value || \"M\";\n      const safeEcc = hasLogo() ? \"H\" : userEcc;\n\n      const fg = $(\"#lpQrFg\", root).value || \"#111827\";\n      const bg = $(\"#lpQrBg\", root).value || \"#ffffff\";\n      const transparent = $(\"#lpQrTransparent\", root).checked;\n\n      const useGrad = $(\"#lpQrUseGradient\", root).checked;\n      const gradType = $(\"#lpQrGradType\", root).value || \"linear\";\n      const gradC1 = $(\"#lpQrGradC1\", root).value || fg;\n      const gradC2 = $(\"#lpQrGradC2\", root).value || \"#2563eb\";\n      const gradRotDeg = clamp(parseInt($(\"#lpQrGradRot\", root).value || \"0\", 10), 0, 360);\n\n      const dotType = $(\"#lpQrDotType\", root).value || \"square\";\n      const cornerOuter = $(\"#lpQrCornerOuter\", root).value || \"square\";\n      const cornerInner = $(\"#lpQrCornerInner\", root).value || \"square\";\n      const forceStdFinder = $(\"#lpQrForceStandardFinder\", root).checked;\n\n      const exportScale = parseInt($(\"#lpQrExportScale\", root).value || \"1\", 10) || 1;\n\n      const logoPercent = clamp(parseInt($(\"#lpQrLogoSize\", root).value || \"20\", 10), 12, 30);\n      const logoShape = $(\"#lpQrLogoShape\", root).value || \"square\";\n      const logoRadius = clamp(parseInt($(\"#lpQrLogoRadius\", root).value || \"16\", 10), 0, 64);\n      const logoPad = clamp(parseInt($(\"#lpQrLogoPad\", root).value || \"8\", 10), 0, 40);\n      const logoBorderW = clamp(parseInt($(\"#lpQrLogoBorderW\", root).value || \"0\", 10), 0, 12);\n      const logoBorderC = $(\"#lpQrLogoBorderC\", root).value || \"#e5e7eb\";\n      const hideBgDots = $(\"#lpQrLogoHideBgDots\", root).checked;\n\n      const stickerType = $(\"#lpQrStickerType\", root).value || \"none\";\n      const stickerRadius = clamp(parseInt($(\"#lpQrStickerRadius\", root).value || \"18\", 10), 0, 48);\n      const stickerPad = clamp(parseInt($(\"#lpQrStickerPad\", root).value || \"18\", 10), 0, 80);\n      const stickerBorderW = clamp(parseInt($(\"#lpQrStickerBorderW\", root).value || \"0\", 10), 0, 20);\n      const stickerBg = $(\"#lpQrStickerBg\", root).value || \"#ffffff\";\n      const stickerBorderC = $(\"#lpQrStickerBorderC\", root).value || \"#e5e7eb\";\n      const stickerText = ($(\"#lpQrStickerText\", root).value || \"SCAN ME\").trim();\n      const stickerTextC = $(\"#lpQrStickerTextC\", root).value || \"#111827\";\n      const stickerTextS = clamp(parseInt($(\"#lpQrStickerTextS\", root).value || \"20\", 10), 10, 64);\n      const stickerBottomH = clamp(parseInt($(\"#lpQrStickerBottomH\", root).value || \"60\", 10), 0, 160);\n      const stickerShadow = $(\"#lpQrStickerShadow\", root).checked;\n\n      const hint = $(\"#lpQrEccHint\", root);\n      if (hint) {\n        if (hasLogo()) {\n          hint.textContent = \"Logo enabled \u2192 ECC forced to H (recommended).\";\n          hint.style.color = \"#0b5cff\";\n        } else {\n          hint.textContent = \"\";\n          hint.style.color = \"\";\n        }\n      }\n\n      return {\n        size, margin, ecc: safeEcc, fg, bg, transparent,\n        useGrad, gradType, gradC1, gradC2, gradRotDeg,\n        dotType, cornerOuter, cornerInner, forceStdFinder,\n        exportScale,\n        logoPercent, logoShape, logoRadius, logoPad, logoBorderW, logoBorderC, hideBgDots,\n        stickerType, stickerRadius, stickerPad, stickerBorderW, stickerBg, stickerBorderC, stickerText, stickerTextC, stickerTextS, stickerBottomH, stickerShadow\n      };\n    }\n\n    function applyPresetTheme() {\n      $(\"#lpQrUseGradient\", root).checked = true;\n      $(\"#lpQrGradType\", root).value = \"linear\";\n      $(\"#lpQrGradC1\", root).value = \"#111827\";\n      $(\"#lpQrGradC2\", root).value = \"#00a6ff\";\n      $(\"#lpQrGradRot\", root).value = \"0\";\n      $(\"#lpQrTransparent\", root).checked = false;\n      $(\"#lpQrBg\", root).value = \"#ffffff\";\n      $(\"#lpQrMargin\", root).value = String(Math.max(12, parseInt($(\"#lpQrMargin\", root).value || \"12\", 10)));\n    }\n\n    function applyPrintSafe() {\n      $(\"#lpQrUseGradient\", root).checked = false;\n      $(\"#lpQrTransparent\", root).checked = false;\n      $(\"#lpQrFg\", root).value = \"#111111\";\n      $(\"#lpQrBg\", root).value = \"#ffffff\";\n      $(\"#lpQrMargin\", root).value = \"16\";\n      $(\"#lpQrDotType\", root).value = \"square\";\n      $(\"#lpQrForceStandardFinder\", root).checked = true;\n      $(\"#lpQrStickerType\", root).value = \"none\";\n      if (!hasLogo()) $(\"#lpQrEcc\", root).value = \"Q\";\n    }\n\n    \/\/ -------------------------\n    \/\/ QR instance (preview)\n    \/\/ -------------------------\n    function makeQRCodeStyling(data) {\n      const s = readQRSettings();\n      const bgColor = s.transparent ? \"transparent\" : s.bg;\n      const rot = (s.gradRotDeg * Math.PI) \/ 180;\n\n      const dotsOptions = s.useGrad ? {\n        type: s.dotType,\n        gradient: {\n          type: s.gradType,\n          rotation: rot,\n          colorStops: [\n            { offset: 0, color: s.gradC1 },\n            { offset: 1, color: s.gradC2 }\n          ]\n        }\n      } : {\n        type: s.dotType,\n        color: s.fg\n      };\n\n      const cornerOuterType = s.forceStdFinder ? \"square\" : s.cornerOuter;\n      const cornerInnerType = s.forceStdFinder ? \"square\" : s.cornerInner;\n\n      const cfg = {\n        width: s.size,\n        height: s.size,\n        type: \"canvas\",\n        data,\n        margin: s.margin,\n        qrOptions: { errorCorrectionLevel: s.ecc },\n        dotsOptions,\n        cornersSquareOptions: { type: cornerOuterType, color: s.fg },\n        cornersDotOptions: { type: cornerInnerType, color: s.fg },\n        backgroundOptions: { color: bgColor }\n      };\n\n      if (hasLogo()) {\n        cfg.image = logoDataUrl;\n        cfg.imageOptions = {\n          crossOrigin: \"anonymous\",\n          margin: 2,\n          imageSize: (readQRSettings().logoPercent \/ 100),\n          hideBackgroundDots: !!readQRSettings().hideBgDots\n        };\n      }\n\n      return new window.QRCodeStyling(cfg);\n    }\n\n    async function renderPreview(data) {\n      showError(\"\");\n\n      const wrap = $(\"#lpQrCanvas\", root);\n      wrap.innerHTML = \"\";\n\n      qr = makeQRCodeStyling(data);\n      qr.append(wrap);\n\n      $(\"#lpQrDownloadPng\", root).disabled = false;\n      $(\"#lpQrDownloadSvg\", root).disabled = false;\n      $(\"#lpQrCopyEmbed\", root).disabled = false;\n\n      lastData = data;\n\n      updateStickerPreview();\n      await updateEmbed();\n    }\n\n    function updateStickerPreview() {\n      const s = readQRSettings();\n      const frame = $(\"#lpQrPreviewFrame\", root);\n      const textEl = $(\"#lpQrPreviewText\", root);\n\n      frame.style.background = \"transparent\";\n      frame.style.border = \"none\";\n      frame.style.borderRadius = \"16px\";\n      frame.style.padding = \"16px\";\n      frame.style.boxShadow = \"none\";\n      textEl.style.display = \"none\";\n      textEl.textContent = \"\";\n\n      if (s.stickerType === \"none\") return;\n\n      const pad = Math.max(10, Math.min(40, s.stickerPad));\n      frame.style.padding = pad + \"px\";\n      frame.style.borderRadius = s.stickerRadius + \"px\";\n      frame.style.background = s.stickerBg;\n      frame.style.border = s.stickerBorderW > 0 ? `${s.stickerBorderW}px solid ${s.stickerBorderC}` : \"none\";\n      frame.style.boxShadow = s.stickerShadow ? \"0 12px 30px rgba(17,24,39,.10)\" : \"none\";\n\n      if (s.stickerType === \"outline\") {\n        frame.style.background = \"transparent\";\n        frame.style.border = `${Math.max(2, s.stickerBorderW || 3)}px solid ${s.stickerBorderC}`;\n      }\n\n      const canvas = $(\"#lpQrCanvas\", root);\n\n      if (s.stickerType === \"topBadge\") {\n        textEl.style.display = \"block\";\n        textEl.textContent = s.stickerText || \"SCAN ME\";\n        textEl.style.color = s.stickerTextC;\n        textEl.style.fontSize = s.stickerTextS + \"px\";\n        textEl.style.marginBottom = \"8px\";\n        frame.style.display = \"grid\";\n        frame.style.gridAutoFlow = \"row\";\n        frame.style.placeItems = \"center\";\n        frame.prepend(textEl);\n        frame.appendChild(canvas);\n      } else if (s.stickerType === \"bottomLabel\" || s.stickerType === \"card\") {\n        textEl.style.display = \"block\";\n        textEl.textContent = s.stickerText || \"SCAN ME\";\n        textEl.style.color = s.stickerTextC;\n        textEl.style.fontSize = s.stickerTextS + \"px\";\n        textEl.style.marginTop = \"10px\";\n        frame.appendChild(canvas);\n        frame.appendChild(textEl);\n      } else {\n        frame.appendChild(canvas);\n      }\n    }\n\n    \/\/ -------------------------\n    \/\/ Export\n    \/\/ -------------------------\n    async function getQRBlobPng() {\n      if (!qr) throw new Error(\"QR not ready.\");\n      return await qr.getRawData(\"png\");\n    }\n\n    async function getQRBlobSvg() {\n      if (!qr) throw new Error(\"QR not ready.\");\n      return await qr.getRawData(\"svg\");\n    }\n\n    async function blobToDataUrl(blob) {\n      return await new Promise((resolve, reject) => {\n        const r = new FileReader();\n        r.onload = () => resolve(String(r.result || \"\"));\n        r.onerror = () => reject(new Error(\"FileReader failed\"));\n        r.readAsDataURL(blob);\n      });\n    }\n\n    async function composePngWithSticker() {\n      const s = readQRSettings();\n      const scale = s.exportScale;\n\n      const qrBlob = await getQRBlobPng();\n      const qrUrl = await blobToDataUrl(qrBlob);\n      const qrImg = await loadImage(qrUrl);\n\n      const qrSize = s.size * scale;\n      const stickerPad = s.stickerType === \"none\" ? 0 : s.stickerPad * scale;\n      const borderW = (s.stickerType === \"none\" ? 0 : s.stickerBorderW) * scale;\n      const radius = (s.stickerType === \"none\" ? 0 : s.stickerRadius) * scale;\n      const bottomH = (s.stickerType === \"bottomLabel\" || s.stickerType === \"card\") ? (s.stickerBottomH * scale) : 0;\n      const topTextH = (s.stickerType === \"topBadge\") ? Math.round((s.stickerTextS + 18) * scale) : 0;\n\n      const w = qrSize + stickerPad * 2 + borderW * 2;\n      const h = qrSize + stickerPad * 2 + borderW * 2 + bottomH + topTextH;\n\n      const canvas = document.createElement(\"canvas\");\n      canvas.width = w;\n      canvas.height = h;\n      const ctx = canvas.getContext(\"2d\");\n\n      const bgFill = (s.stickerType === \"outline\") ? \"rgba(0,0,0,0)\" :\n        (s.stickerType === \"none\") ? (s.transparent ? \"rgba(0,0,0,0)\" : s.bg) :\n          s.stickerBg;\n\n      const drawCard = (s.stickerType !== \"none\");\n\n      if (drawCard && s.stickerShadow) {\n        drawShadow(ctx, borderW, borderW, w - borderW * 2, h - borderW * 2, radius);\n      }\n\n      if (drawCard) {\n        ctx.save();\n        roundRectPath(ctx, borderW, borderW, w - borderW * 2, h - borderW * 2, radius);\n        ctx.fillStyle = bgFill;\n        ctx.fill();\n        ctx.restore();\n\n        if (borderW > 0) {\n          ctx.save();\n          roundRectPath(ctx, borderW \/ 2, borderW \/ 2, w - borderW, h - borderW, radius);\n          ctx.strokeStyle = s.stickerBorderC;\n          ctx.lineWidth = borderW;\n          ctx.stroke();\n          ctx.restore();\n        } else if (s.stickerType === \"outline\") {\n          ctx.save();\n          const ow = Math.max(3, Math.round(3 * scale));\n          roundRectPath(ctx, ow \/ 2, ow \/ 2, w - ow, h - ow, radius);\n          ctx.strokeStyle = s.stickerBorderC;\n          ctx.lineWidth = ow;\n          ctx.stroke();\n          ctx.restore();\n        }\n      } else {\n        if (!s.transparent) {\n          ctx.fillStyle = s.bg;\n          ctx.fillRect(0, 0, w, h);\n        } else {\n          ctx.clearRect(0, 0, w, h);\n        }\n      }\n\n      const drawText = (txt, x, y, maxW) => {\n        const t = (txt || \"\").trim();\n        if (!t) return;\n        ctx.save();\n        ctx.fillStyle = s.stickerTextC;\n        ctx.textAlign = \"center\";\n        ctx.textBaseline = \"middle\";\n        let fontSize = Math.round(s.stickerTextS * scale);\n        while (fontSize > 10) {\n          ctx.font = `${fontSize}px system-ui,-apple-system,Segoe UI,Roboto,Arial`;\n          if (ctx.measureText(t).width <= maxW) break;\n          fontSize -= 1;\n        }\n        ctx.fillText(t, x, y);\n        ctx.restore();\n      };\n\n      if (s.stickerType === \"topBadge\") {\n        drawText(s.stickerText || \"SCAN ME\", w \/ 2, borderW + Math.max(18 * scale, (s.stickerTextS * scale) \/ 2 + 10 * scale), w - 24 * scale);\n      }\n\n      if (s.stickerType === \"bottomLabel\" || s.stickerType === \"card\") {\n        drawText(s.stickerText || \"SCAN ME\", w \/ 2, h - borderW - Math.max(18 * scale, (s.stickerTextS * scale) \/ 2 + 10 * scale), w - 24 * scale);\n      }\n\n      const qrX = borderW + stickerPad;\n      const qrY = borderW + stickerPad + (s.stickerType === \"topBadge\" ? topTextH : 0);\n\n      ctx.imageSmoothingEnabled = false;\n      ctx.drawImage(qrImg, qrX, qrY, qrSize, qrSize);\n\n      if (hasLogo()) {\n        const logoImg = await loadImage(logoDataUrl);\n\n        const logoSize = Math.round(qrSize * (s.logoPercent \/ 100));\n        const cx = qrX + qrSize \/ 2;\n        const cy = qrY + qrSize \/ 2;\n\n        const platePad = Math.round(s.logoPad * scale);\n        const borderW2 = Math.round(s.logoBorderW * scale);\n        const plateSize = logoSize + platePad * 2 + borderW2 * 2;\n\n        const px = Math.round(cx - plateSize \/ 2);\n        const py = Math.round(cy - plateSize \/ 2);\n\n        let r = 0;\n        if (s.logoShape === \"circle\") r = plateSize \/ 2;\n        else if (s.logoShape === \"rounded\") r = Math.min(plateSize \/ 2, Math.round(s.logoRadius * scale));\n\n        ctx.save();\n        roundRectPath(ctx, px, py, plateSize, plateSize, r);\n        ctx.fillStyle = \"#ffffff\";\n        ctx.fill();\n\n        if (borderW2 > 0) {\n          ctx.strokeStyle = s.logoBorderC;\n          ctx.lineWidth = borderW2;\n          ctx.stroke();\n        }\n        ctx.restore();\n\n        const lx = Math.round(cx - logoSize \/ 2);\n        const ly = Math.round(cy - logoSize \/ 2);\n\n        let lr = 0;\n        if (s.logoShape === \"circle\") lr = logoSize \/ 2;\n        else if (s.logoShape === \"rounded\") lr = Math.min(logoSize \/ 2, Math.round(s.logoRadius * scale));\n\n        ctx.save();\n        roundRectPath(ctx, lx, ly, logoSize, logoSize, lr);\n        ctx.clip();\n        ctx.imageSmoothingEnabled = true;\n        ctx.drawImage(logoImg, lx, ly, logoSize, logoSize);\n        ctx.restore();\n      }\n\n      return canvas;\n    }\n\n    function downloadDataUrl(dataUrl, filename) {\n      const a = document.createElement(\"a\");\n      a.download = filename;\n      a.href = dataUrl;\n      a.click();\n    }\n\n    async function downloadPNG() {\n      try {\n        const canvas = await composePngWithSticker();\n        downloadDataUrl(canvas.toDataURL(\"image\/png\"), \"loongprt-qr.png\");\n      } catch (e) {\n        showError(\"PNG export failed. Try reducing size or disabling gradient\/logo.\");\n      }\n    }\n\n    async function downloadSVG() {\n      try {\n        const svgBlob = await getQRBlobSvg();\n        const url = URL.createObjectURL(svgBlob);\n        const a = document.createElement(\"a\");\n        a.download = \"loongprt-qr.svg\";\n        a.href = url;\n        a.click();\n        setTimeout(() => URL.revokeObjectURL(url), 2000);\n      } catch (e) {\n        showError(\"SVG export failed in this build. Try PNG export instead.\");\n      }\n    }\n\n    async function updateEmbed() {\n      try {\n        const canvas = await composePngWithSticker();\n        const dataUrl = canvas.toDataURL(\"image\/png\");\n        $(\"#lpQrEmbed\", root).value = `<img decoding=\"async\" src=\"${dataUrl}\" alt=\"QR Code\" \/>`;\n      } catch (e) {\n        $(\"#lpQrEmbed\", root).value = \"\";\n      }\n    }\n\n    async function copyEmbed() {\n      const val = $(\"#lpQrEmbed\", root).value || \"\";\n      if (!val) return;\n      try {\n        await navigator.clipboard.writeText(val);\n        const btn = $(\"#lpQrCopyEmbed\", root);\n        const old = btn.textContent;\n        btn.textContent = \"Copied!\";\n        setTimeout(() => btn.textContent = old, 1000);\n      } catch (e) {\n        const inp = $(\"#lpQrEmbed\", root);\n        inp.focus(); inp.select();\n        document.execCommand(\"copy\");\n      }\n    }\n\n    \/\/ -------------------------\n    \/\/ Type switching\n    \/\/ -------------------------\n    function setType(type) {\n      $$(\".lp-qr-tab\", root).forEach(b => {\n        b.classList.toggle(\"is-active\", b.getAttribute(\"data-type\") === type);\n      });\n      $$(\".lp-qr-formwrap .lp-qr-form\", root).forEach(f => {\n        f.classList.toggle(\"is-show\", f.getAttribute(\"data-form\") === type);\n      });\n      showError(\"\");\n    }\n\n    function getActiveType() {\n      const active = $(\".lp-qr-tab.is-active\", root);\n      return active ? active.getAttribute(\"data-type\") : \"text\";\n    }\n\n    \/\/ -------------------------\n    \/\/ Generate \/ Reset \/ Live rerender\n    \/\/ -------------------------\n    async function generate() {\n      const type = getActiveType();\n      const res = buildPayload(type);\n      if (!res.ok) {\n        showError(res.msg || \"Invalid input.\");\n        return;\n      }\n      await renderPreview(res.data);\n      lastData = res.data;\n    }\n\n    function resetAll() {\n      $$(\"#lp-qr-widget input.lp-qr-input, #lp-qr-widget textarea.lp-qr-input\").forEach(el => el.value = \"\");\n      $(\"#lpQrWifiAuth\", root).value = \"WPA\";\n      $(\"#lpQrWifiHidden\", root).checked = false;\n\n      $(\"#lpQrSize\", root).value = \"320\";\n      $(\"#lpQrMargin\", root).value = \"12\";\n      $(\"#lpQrEcc\", root).value = \"M\";\n\n      $(\"#lpQrFg\", root).value = \"#111827\";\n      $(\"#lpQrBg\", root).value = \"#ffffff\";\n      $(\"#lpQrTransparent\", root).checked = false;\n\n      $(\"#lpQrUseGradient\", root).checked = false;\n      $(\"#lpQrGradType\", root).value = \"linear\";\n      $(\"#lpQrGradC1\", root).value = \"#111827\";\n      $(\"#lpQrGradC2\", root).value = \"#2563eb\";\n      $(\"#lpQrGradRot\", root).value = \"0\";\n\n      $(\"#lpQrDotType\", root).value = \"square\";\n      $(\"#lpQrCornerOuter\", root).value = \"square\";\n      $(\"#lpQrCornerInner\", root).value = \"square\";\n      $(\"#lpQrForceStandardFinder\", root).checked = true;\n\n      $(\"#lpQrExportScale\", root).value = \"1\";\n      $(\"#lpQrLiveUpdate\", root).checked = true;\n\n      logoDataUrl = \"\";\n      $(\"#lpQrLogoFile\", root).value = \"\";\n      $(\"#lpQrLogoSize\", root).value = \"20\";\n      $(\"#lpQrLogoShape\", root).value = \"square\";\n      $(\"#lpQrLogoRadius\", root).value = \"16\";\n      $(\"#lpQrLogoPad\", root).value = \"8\";\n      $(\"#lpQrLogoBorderW\", root).value = \"0\";\n      $(\"#lpQrLogoBorderC\", root).value = \"#e5e7eb\";\n      $(\"#lpQrLogoHideBgDots\", root).checked = true;\n      $(\"#lpQrRemoveLogo\", root).disabled = true;\n\n      $(\"#lpQrStickerType\", root).value = \"none\";\n      $(\"#lpQrStickerRadius\", root).value = \"18\";\n      $(\"#lpQrStickerPad\", root).value = \"18\";\n      $(\"#lpQrStickerBorderW\", root).value = \"0\";\n      $(\"#lpQrStickerBg\", root).value = \"#ffffff\";\n      $(\"#lpQrStickerBorderC\", root).value = \"#e5e7eb\";\n      $(\"#lpQrStickerText\", root).value = \"SCAN ME\";\n      $(\"#lpQrStickerTextC\", root).value = \"#111827\";\n      $(\"#lpQrStickerTextS\", root).value = \"20\";\n      $(\"#lpQrStickerBottomH\", root).value = \"60\";\n      $(\"#lpQrStickerShadow\", root).checked = true;\n\n      $(\"#lpQrCanvas\", root).innerHTML = \"\";\n      $(\"#lpQrEmbed\", root).value = \"\";\n      $(\"#lpQrDownloadPng\", root).disabled = true;\n      $(\"#lpQrDownloadSvg\", root).disabled = true;\n      $(\"#lpQrCopyEmbed\", root).disabled = true;\n\n      qr = null;\n      lastData = \"\";\n      showError(\"\");\n      setType(\"text\");\n      setDesignTab(\"colors\");\n    }\n\n    async function rerenderIfHaveData() {\n      if (!lastData) return;\n      await renderPreview(lastData);\n    }\n\n    let liveTimer = null;\n    function scheduleLive() {\n      if (!$(\"#lpQrLiveUpdate\", root).checked) return;\n      if (!lastData) return;\n      clearTimeout(liveTimer);\n      liveTimer = setTimeout(() => rerenderIfHaveData(), 180);\n    }\n\n    function syncLastDataFromInputs() {\n      if (!lastData) return;\n      const res = buildPayload(getActiveType());\n      if (res.ok) lastData = res.data;\n    }\n\n    \/\/ -------------------------\n    \/\/ Logo handlers\n    \/\/ -------------------------\n    async function onLogoChange() {\n      const input = $(\"#lpQrLogoFile\", root);\n      const file = input.files && input.files[0];\n      if (!file) return;\n\n      const maxMB = 2;\n      if (file.size > maxMB * 1024 * 1024) {\n        showError(\"Logo file is too large. Please use an image under 2MB.\");\n        input.value = \"\";\n        return;\n      }\n\n      try {\n        logoDataUrl = await fileToDataUrl(file);\n        $(\"#lpQrRemoveLogo\", root).disabled = false;\n        $(\"#lpQrEcc\", root).value = \"H\";\n        if (parseInt($(\"#lpQrMargin\", root).value || \"12\", 10) < 12) $(\"#lpQrMargin\", root).value = \"12\";\n        await rerenderIfHaveData();\n      } catch (e) {\n        showError(\"Failed to load logo. Please try another image.\");\n        input.value = \"\";\n      }\n    }\n\n    async function removeLogo() {\n      logoDataUrl = \"\";\n      $(\"#lpQrLogoFile\", root).value = \"\";\n      $(\"#lpQrRemoveLogo\", root).disabled = true;\n      await rerenderIfHaveData();\n    }\n\n    \/\/ -------------------------\n    \/\/ Bind UI\n    \/\/ -------------------------\n    function bind() {\n      $$(\".lp-qr-tab\", root).forEach(btn => {\n        btn.addEventListener(\"click\", () => {\n          setType(btn.getAttribute(\"data-type\"));\n          syncLastDataFromInputs();\n          scheduleLive();\n        });\n      });\n\n      $$(\".lp-qr-dtab\", root).forEach(btn => {\n        btn.addEventListener(\"click\", () => setDesignTab(btn.getAttribute(\"data-design-tab\")));\n      });\n\n      $(\"#lpQrGenerate\", root).addEventListener(\"click\", generate);\n      $(\"#lpQrReset\", root).addEventListener(\"click\", resetAll);\n      $(\"#lpQrPrintSafe\", root).addEventListener(\"click\", async () => {\n        applyPrintSafe();\n        await rerenderIfHaveData();\n      });\n\n      $(\"#lpQrPreset\", root).addEventListener(\"click\", async () => {\n        applyPresetTheme();\n        await rerenderIfHaveData();\n      });\n\n      $(\"#lpQrDownloadPng\", root).addEventListener(\"click\", downloadPNG);\n      $(\"#lpQrDownloadSvg\", root).addEventListener(\"click\", downloadSVG);\n      $(\"#lpQrCopyEmbed\", root).addEventListener(\"click\", copyEmbed);\n\n      $(\"#lpQrLogoFile\", root).addEventListener(\"change\", onLogoChange);\n      $(\"#lpQrRemoveLogo\", root).addEventListener(\"click\", removeLogo);\n\n      const rerenderOn = [\n        \"lpQrSize\", \"lpQrMargin\", \"lpQrEcc\", \"lpQrFg\", \"lpQrBg\", \"lpQrTransparent\",\n        \"lpQrUseGradient\", \"lpQrGradType\", \"lpQrGradC1\", \"lpQrGradC2\", \"lpQrGradRot\",\n        \"lpQrDotType\", \"lpQrCornerOuter\", \"lpQrCornerInner\", \"lpQrForceStandardFinder\",\n        \"lpQrExportScale\", \"lpQrLiveUpdate\",\n        \"lpQrLogoSize\", \"lpQrLogoShape\", \"lpQrLogoRadius\", \"lpQrLogoPad\", \"lpQrLogoBorderW\", \"lpQrLogoBorderC\", \"lpQrLogoHideBgDots\",\n        \"lpQrStickerType\", \"lpQrStickerRadius\", \"lpQrStickerPad\", \"lpQrStickerBorderW\", \"lpQrStickerBg\", \"lpQrStickerBorderC\",\n        \"lpQrStickerText\", \"lpQrStickerTextC\", \"lpQrStickerTextS\", \"lpQrStickerBottomH\", \"lpQrStickerShadow\"\n      ];\n      rerenderOn.forEach(id => {\n        const el = $(\"#\" + id, root);\n        if (!el) return;\n        el.addEventListener(\"change\", rerenderIfHaveData);\n        el.addEventListener(\"input\", () => { scheduleLive(); });\n      });\n\n      const inputs = $$(\"textarea, input[type='text'], input[type='url'], input[type='email'], input[type='datetime-local']\", root);\n      inputs.forEach(el => el.addEventListener(\"input\", () => {\n        if (!$(\"#lpQrLiveUpdate\", root).checked) return;\n        if (!lastData) return;\n        syncLastDataFromInputs();\n        scheduleLive();\n      }));\n\n      setType(\"text\");\n      setDesignTab(\"colors\");\n      showError(\"\"); \/\/ clear \"loading\" message if any\n    }\n\n    bind();\n  });\n\n})();\n\n<\/script>\n\n\n","protected":false},"excerpt":{"rendered":"","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-1698","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/yuiyto.com\/ko\/wp-json\/wp\/v2\/pages\/1698","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/yuiyto.com\/ko\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/yuiyto.com\/ko\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/yuiyto.com\/ko\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/yuiyto.com\/ko\/wp-json\/wp\/v2\/comments?post=1698"}],"version-history":[{"count":0,"href":"https:\/\/yuiyto.com\/ko\/wp-json\/wp\/v2\/pages\/1698\/revisions"}],"wp:attachment":[{"href":"https:\/\/yuiyto.com\/ko\/wp-json\/wp\/v2\/media?parent=1698"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}