{"id":8114,"date":"2026-01-25T07:54:15","date_gmt":"2026-01-24T23:54:15","guid":{"rendered":"https:\/\/louisthai.com\/?page_id=8114"},"modified":"2026-01-25T20:12:22","modified_gmt":"2026-01-25T12:12:22","slug":"orchid-2","status":"publish","type":"page","link":"https:\/\/louisthai.com\/hk\/orchid-2\/","title":{"rendered":"Orchid"},"content":{"rendered":"<div data-elementor-type=\"wp-page\" data-elementor-id=\"8114\" class=\"elementor elementor-8114\" data-elementor-post-type=\"page\">\n\t\t\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-91e529d elementor-section-full_width elementor-section-stretched elementor-section-height-default elementor-section-height-default\" data-id=\"91e529d\" data-element_type=\"section\" data-settings=\"{&quot;stretch_section&quot;:&quot;section-stretched&quot;}\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-no\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-7c7aa58\" data-id=\"7c7aa58\" data-element_type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-9fe6099 elementor-widget elementor-widget-html\" data-id=\"9fe6099\" data-element_type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<!doctype html>\n<html lang=\"en\">\n\n<head>\n  <meta charset=\"utf-8\" \/>\n  <meta name=\"viewport\" content=\"width=device-width,initial-scale=1\" \/>\n  <title>LOUIS THAI \u2014 Orchid Greeting Card<\/title>\n\n  <style>\n    \/* =========================\n       LOUIS THAI \u2014 Apple-style Print Card\n       White primary theme (per requirement)\n       ========================= *\/\n\n    :root {\n      --bg: #ffffff;\n      --ink: #0b0b0f;\n      --muted: #5b5f6a;\n      --hairline: rgba(15, 23, 42, .12);\n      --soft: rgba(15, 23, 42, .06);\n      --shadow: 0 10px 30px rgba(15, 23, 42, .10);\n      --radius: 22px;\n\n      \/* Default print size: A6 (portrait) *\/\n      --page-w: 105mm;\n      --page-h: 148mm;\n\n      \/* Safe margins inside card *\/\n      --pad: 12mm;\n\n      \/* Orchid accent (subtle, not loud) *\/\n      --orchid: #4d16b8;\n      \/* deeper orchid *\/\n      --orchid2: #8a1bd6;\n      \/* deeper orchid *\/\n    }\n\n    \/* Optional size switch:\n       Add class \"size-a5\" on <body> for A5\n    *\/\n    body.size-a5 {\n      --page-w: 148mm;\n      --page-h: 210mm;\n      --pad: 14mm;\n      --radius: 26px;\n    }\n\n    * {\n      box-sizing: border-box;\n    }\n\n    html,\n    body {\n      min-height: 100vh;\n      background: var(--bg);\n      color: var(--ink);\n      margin: 0;\n    }\n\n    body {\n      font-family: ui-sans-serif, -apple-system, BlinkMacSystemFont, \"SF Pro Display\", \"SF Pro Text\",\n        \"Helvetica Neue\", Arial, \"Noto Sans\", \"Apple Color Emoji\", \"Segoe UI Emoji\";\n      letter-spacing: .1px;\n    }\n\n\n    \/* =========================\n       Tools + Delivery Form (screen only)\n       ========================= *\/\n    .wrap {\n      display: flex;\n      flex-direction: column;\n      gap: 14px;\n      align-items: center;\n      width: min(760px, 96vw);\n    }\n\n    .toolbar {\n      width: 100%;\n      display: flex;\n      flex-wrap: wrap;\n      gap: 10px;\n      align-items: center;\n      justify-content: space-between;\n      padding: 12px 12px;\n      border: 1px solid var(--hairline);\n      border-radius: 18px;\n      background: rgba(255, 255, 255, .85);\n      backdrop-filter: blur(10px);\n      -webkit-backdrop-filter: blur(10px);\n      box-shadow: 0 10px 24px rgba(15, 23, 42, .06);\n    }\n\n    .toolbar .left,\n    .toolbar .right {\n      display: flex;\n      flex-wrap: wrap;\n      gap: 10px;\n      align-items: center;\n    }\n\n    .btn {\n      appearance: none;\n      border: 1px solid var(--hairline);\n      background: #fff;\n      color: var(--ink);\n      padding: 10px 12px;\n      border-radius: 14px;\n      font-weight: 650;\n      font-size: 12px;\n      letter-spacing: .01em;\n      cursor: pointer;\n      transition: transform .12s ease, box-shadow .12s ease, border-color .12s ease;\n      box-shadow: 0 6px 18px rgba(15, 23, 42, .06);\n      user-select: none;\n    }\n\n    .btn:hover {\n      transform: translateY(-1px);\n      border-color: rgba(77, 22, 184, .35);\n    }\n\n    .btn:active {\n      transform: translateY(0px);\n      box-shadow: 0 4px 12px rgba(15, 23, 42, .08);\n    }\n\n    .btn.primary {\n      border-color: rgba(77, 22, 184, .30);\n      background: linear-gradient(135deg, rgba(77, 22, 184, .10), rgba(138, 27, 214, .08));\n    }\n\n    .hint {\n      font-size: 12px;\n      color: var(--muted);\n      line-height: 1.4;\n      max-width: 44ch;\n    }\n\n    details.panel {\n      width: 100%;\n      border: 1px solid var(--hairline);\n      border-radius: 18px;\n      background: #fff;\n      box-shadow: 0 10px 24px rgba(15, 23, 42, .06);\n      overflow: hidden;\n    }\n\n    details.panel>summary {\n      list-style: none;\n      cursor: pointer;\n      padding: 14px 14px;\n      display: flex;\n      align-items: center;\n      justify-content: space-between;\n      gap: 10px;\n      user-select: none;\n    }\n\n    details.panel>summary::-webkit-details-marker {\n      display: none;\n    }\n\n    .summaryTitle {\n      display: flex;\n      align-items: center;\n      gap: 10px;\n      font-weight: 750;\n      letter-spacing: -0.01em;\n    }\n\n    .badge {\n      display: inline-flex;\n      align-items: center;\n      gap: 8px;\n      padding: 6px 10px;\n      border-radius: 999px;\n      border: 1px solid var(--hairline);\n      color: var(--muted);\n      font-size: 12px;\n      background: rgba(255, 255, 255, .8);\n    }\n\n    .panelBody {\n      padding: 0 14px 14px 14px;\n      display: grid;\n      gap: 12px;\n    }\n\n    .grid {\n      display: grid;\n      grid-template-columns: 1fr 1fr 1fr;\n      gap: 12px;\n    }\n\n    @media (max-width: 560px) {\n      .grid {\n        grid-template-columns: 1fr;\n      }\n\n      .hint {\n        max-width: 100%;\n      }\n    }\n\n    label.field {\n      display: flex;\n      flex-direction: column;\n      gap: 6px;\n      font-size: 12px;\n      color: var(--muted);\n    }\n\n    input.text,\n    textarea.text {\n      width: 100%;\n      border: 1px solid var(--hairline);\n      border-radius: 14px;\n      padding: 12px 12px;\n      font-size: 13px;\n      color: var(--ink);\n      outline: none;\n      background: #fff;\n      transition: border-color .12s ease, box-shadow .12s ease;\n    }\n\n    textarea.text {\n      min-height: 86px;\n      resize: vertical;\n    }\n\n    input.text:focus,\n    textarea.text:focus {\n      border-color: rgba(77, 22, 184, .40);\n      box-shadow: 0 0 0 4px rgba(77, 22, 184, .10);\n    }\n\n    .row {\n      display: flex;\n      flex-wrap: wrap;\n      gap: 10px;\n      align-items: center;\n      justify-content: space-between;\n    }\n\n    .toggle {\n      display: flex;\n      gap: 10px;\n      align-items: center;\n      font-size: 12px;\n      color: var(--muted);\n      user-select: none;\n    }\n\n    .toggle input {\n      width: 16px;\n      height: 16px;\n      accent-color: var(--orchid);\n    }\n\n    \/* Delivery block printed on card *\/\n    .deliverBlock {\n      margin-top: 10px;\n      padding: 10px 12px;\n      border-radius: 16px;\n      border: 1px solid var(--soft);\n      background: rgba(255, 255, 255, .75);\n      backdrop-filter: blur(8px);\n      -webkit-backdrop-filter: blur(8px);\n      display: none;\n      max-width: 92%;\n    }\n\n    body.size-a5 .deliverBlock {\n      max-width: 88%;\n    }\n\n    .deliverTitle {\n      font-size: 11px;\n      color: var(--muted);\n      letter-spacing: .02em;\n      margin: 0 0 6px 0;\n      display: flex;\n      align-items: center;\n      gap: 8px;\n    }\n\n    .deliverLines {\n      margin: 0;\n      font-size: 12px;\n      line-height: 1.45;\n      color: var(--ink);\n      white-space: pre-line;\n    }\n\n    @media print {\n\n      .toolbar,\n      details.panel {\n        display: none !important;\n      }\n\n      .wrap {\n        width: auto;\n        gap: 0;\n      }\n    }\n\n\n    \/* Screen preview wrapper *\/\n    .stage {\n      min-height: 100vh;\n      display: flex;\n      flex-direction: column;\n      align-items: center;\n      justify-content: flex-start;\n      padding: 24px 12px;\n      background:\n        radial-gradient(1200px 600px at 50% 0%, rgba(77, 22, 184, .10), transparent 55%),\n        radial-gradient(900px 500px at 10% 90%, rgba(138, 27, 214, .08), transparent 60%),\n        #fff;\n    }\n\n    \/* Card *\/\n    \/* Card *\/\n    .card {\n      width: 100%;\n      aspect-ratio: 105 \/ 148;\n      \/* A6 portrait preview ratio *\/\n      background: #fff;\n      border: 1px solid var(--hairline);\n      border-radius: var(--radius);\n      box-shadow: var(--shadow);\n      position: relative;\n      overflow: hidden;\n\n      \/* Prepare for 3D Tilt *\/\n      -webkit-transform-style: preserve-3d !important;\n      transform-style: preserve-3d !important;\n      perspective: 2000px !important;\n      -webkit-perspective: 2000px !important;\n      transition: transform 0.15s ease-out;\n      will-change: transform;\n      z-index: 1;\n    }\n\n    body.size-a5 .card {\n      aspect-ratio: 148 \/ 210;\n      \/* A5 portrait ratio *\/\n      width: 100%;\n    }\n\n    \/* Dynamic Card Shine\/Glare *\/\n    .cardGlare {\n      position: absolute;\n      inset: 0;\n      background: radial-gradient(circle at var(--shine-x, 50%) var(--shine-y, 50%),\n          rgba(255, 255, 255, 0.45) 0%,\n          rgba(255, 255, 255, 0) 60%);\n      pointer-events: none;\n      z-index: 10;\n      opacity: 0;\n      transition: opacity 0.4s ease;\n      mix-blend-mode: overlay;\n    }\n\n    .card:hover .cardGlare {\n      opacity: 1;\n    }\n\n    \/* Subtle \u201corchid light\u201d *\/\n    .glow {\n      position: absolute;\n      inset: -40% -30% auto -30%;\n      height: 70%;\n      background:\n        radial-gradient(circle at 30% 40%, rgba(77, 22, 184, .22), transparent 55%),\n        radial-gradient(circle at 70% 30%, rgba(138, 27, 214, .16), transparent 60%);\n      filter: blur(6px);\n      pointer-events: none;\n    }\n\n    \/* =========================\n       Orchid 3D Depth Map Scene\n       ========================= *\/\n    .orchidScene {\n      position: absolute !important;\n      inset: 0 !important;\n      pointer-events: none !important;\n      z-index: 5 !important;\n      display: flex;\n      align-items: center;\n      justify-content: center;\n      overflow: visible !important;\n    }\n\n    #orchidCanvas {\n      position: absolute;\n      bottom: 0;\n      left: 50%;\n      transform: translateX(-50%);\n      max-width: none !important;\n      height: auto;\n      width: 100%;\n      display: block;\n      will-change: transform;\n    }\n\n    @media (max-width: 560px) {\n      #orchidCanvas {\n        width: 120%;\n        \/* Slightly larger on mobile *\/\n      }\n\n      .card {\n        height: 680px !important;\n        min-height: 680px !important;\n        aspect-ratio: auto !important;\n      }\n    }\n\n    \/* Inner layout *\/\n    .inner {\n      position: absolute;\n      inset: 0;\n      padding: var(--pad);\n      display: flex;\n      flex-direction: column;\n      justify-content: space-between;\n      gap: 16px;\n\n      \/* Elevate text onto a 3D plane *\/\n      transform: translateZ(120px) !important;\n      -webkit-transform: translateZ(120px) !important;\n      transform-style: preserve-3d !important;\n      -webkit-transform-style: preserve-3d !important;\n      pointer-events: none;\n      z-index: 20 !important;\n    }\n\n    .inner>* {\n      pointer-events: auto;\n    }\n\n    .top {\n      display: flex;\n      align-items: flex-start;\n      justify-content: space-between;\n      gap: 12px;\n    }\n\n    .brand {\n      display: flex;\n      flex-direction: column;\n      gap: 6px;\n    }\n\n    .brand .name {\n      font-weight: 700;\n      letter-spacing: .28em;\n      font-size: 12px;\n    }\n\n    .brand .tag {\n      font-size: 12px;\n      color: var(--muted);\n    }\n\n    \/* \u201cPill\u201d *\/\n    .pill {\n      display: inline-flex;\n      align-items: center;\n      gap: 8px;\n      padding: 8px 12px;\n      border-radius: 999px;\n      border: 1px solid var(--hairline);\n      background: rgba(255, 255, 255, .7);\n      backdrop-filter: blur(8px);\n      -webkit-backdrop-filter: blur(8px);\n      font-size: 12px;\n      color: var(--muted);\n      white-space: nowrap;\n    }\n\n    .dot {\n      width: 8px;\n      height: 8px;\n      border-radius: 999px;\n      background: linear-gradient(135deg, var(--orchid), var(--orchid2));\n      box-shadow: 0 0 0 4px rgba(77, 22, 184, .14);\n      flex: 0 0 auto;\n    }\n\n    \/* Main message *\/\n    .content {\n      display: flex;\n      flex-direction: column;\n      gap: 12px;\n      padding: 8px 2px 0 2px;\n    }\n\n    @media (max-width: 560px) {\n      .content {\n        min-height: 380px;\n        \/* Ensure space for the orchid *\/\n        margin-bottom: 20px;\n      }\n\n      .deliverBlock {\n        margin-bottom: 60px;\n        \/* Extra room if delivery is shown *\/\n      }\n    }\n\n    .headline {\n      font-size: 30px;\n      line-height: 1.15;\n      font-weight: 750;\n      letter-spacing: -0.02em;\n      margin: 0;\n    }\n\n    body.size-a5 .headline {\n      font-size: 36px;\n    }\n\n    @media (max-width: 560px) {\n      .headline {\n        font-size: 24px;\n      }\n    }\n\n    .sub {\n      margin: 0;\n      font-size: 15px;\n      line-height: 1.65;\n      color: var(--muted);\n      max-width: 92%;\n    }\n\n    body.size-a5 .sub {\n      font-size: 16px;\n      max-width: 88%;\n    }\n\n    .divider {\n      height: 1px;\n      background: linear-gradient(90deg, transparent, var(--soft), transparent);\n      margin: 10px 0 2px;\n    }\n\n    \/* Footer *\/\n    .footer {\n      display: flex;\n      align-items: flex-end;\n      justify-content: space-between;\n      gap: 12px;\n      padding-top: 10px;\n    }\n\n    .sig {\n      display: flex;\n      flex-direction: column;\n      gap: 4px;\n    }\n\n    .sig .line1 {\n      font-size: 12px;\n      color: var(--muted);\n    }\n\n    .sig .line2 {\n      font-size: 12px;\n      font-weight: 650;\n      letter-spacing: .02em;\n    }\n\n    .meta {\n      text-align: right;\n      font-size: 11px;\n      color: var(--muted);\n      line-height: 1.35;\n      white-space: nowrap;\n    }\n\n    \/* Micro-print note (optional) *\/\n    .note {\n      position: absolute;\n      left: var(--pad);\n      bottom: calc(var(--pad) * 0.8);\n      font-size: 9px;\n      color: rgba(91, 95, 106, .72);\n      letter-spacing: .02em;\n      display: none;\n      \/* show only in print *\/\n      transform: translateZ(100px);\n    }\n\n    \/* =========================\n       PRINT\n       ========================= *\/\n    @page {\n      size: var(--page-w) var(--page-h);\n      margin: 0;\n    }\n\n    @media print {\n\n      html,\n      body {\n        background: #fff;\n      }\n\n      .stage {\n        padding: 0;\n        min-height: auto;\n        background: #fff;\n      }\n\n      .card {\n        width: var(--page-w);\n        height: var(--page-h);\n        aspect-ratio: auto;\n        border-radius: 0;\n        \/* full-bleed page *\/\n        box-shadow: none;\n        border: none;\n      }\n\n      .inner {\n        padding: var(--pad);\n      }\n\n      .note {\n        display: block;\n      }\n\n      \/* Ensure colors print nicely *\/\n      * {\n        -webkit-print-color-adjust: exact;\n        print-color-adjust: exact;\n      }\n    }\n  <\/style>\n<\/head>\n\n<!-- Change to: <body class=\"size-a5\"> for A5 -->\n\n<body>\n  <div class=\"stage\">\n    <div class=\"wrap\">\n      <div class=\"toolbar\" role=\"region\" aria-label=\"Card Tools\">\n        <div class=\"left\">\n          <button class=\"btn primary\" id=\"btnDownload8k\" type=\"button\">Download UHD PNG (8K)<\/button>\n        <\/div>\n        <div class=\"right\">\n          <div class=\"hint\">Fill delivery details below. The card updates instantly; download a UHD PNG for saving.\n          <\/div>\n        <\/div>\n      <\/div>\n\n      <details class=\"panel\" open>\n        <summary>\n          <div class=\"summaryTitle\">\n            <span class=\"dot\" aria-hidden=\"true\"><\/span>\n            <span>Delivery Details<\/span>\n          <\/div>\n          <span class=\"badge\">Client-filled \u2022 Saved on device<\/span>\n        <\/summary>\n\n        <div class=\"panelBody\">\n          <div class=\"grid\">\n            <label class=\"field\">\n              Recipient Name\n              <input class=\"text\" id=\"inName\" autocomplete=\"name\" placeholder=\"e.g., Mr. Tan Wei\" \/>\n            <\/label>\n\n            <label class=\"field\">\n              Phone Number\n              <input class=\"text\" id=\"inPhone\" autocomplete=\"tel\" placeholder=\"e.g., +60 12-345 6789\" \/>\n            <\/label>\n\n            <label class=\"field\">\n              Postcode \/ Zipcode\n              <input class=\"text\" id=\"inZip\" autocomplete=\"postal-code\" placeholder=\"e.g., 47500\" \/>\n            <\/label>\n          <\/div>\n\n          <label class=\"field\">\n            Delivery Address\n            <textarea class=\"text\" id=\"inAddress\" autocomplete=\"street-address\"\n              placeholder=\"Street, building, unit no., postcode, city, state\"><\/textarea>\n          <\/label>\n\n          <div class=\"row\">\n            <label class=\"toggle\">\n              <input type=\"checkbox\" id=\"chkShowOnCard\" checked \/>\n              Show delivery details on card (will appear in print\/export)\n            <\/label>\n\n            <div style=\"display:flex; gap:10px; align-items:center;\">\n              <button class=\"btn\" id=\"btnClear\" type=\"button\">Clear<\/button>\n            <\/div>\n          <\/div>\n        <\/div>\n      <\/details>\n\n      <section class=\"card\" id=\"card\" aria-label=\"LOUIS THAI Orchid Greeting Card\">\n        <div class=\"glow\" id=\"cardGlow\" aria-hidden=\"true\"><\/div>\n        <div class=\"cardGlare\" id=\"cardGlare\" aria-hidden=\"true\"><\/div>\n\n        <div class=\"orchidScene\" aria-hidden=\"true\">\n          <canvas id=\"orchidCanvas\"><\/canvas>\n        <\/div>\n        <div class=\"inner\">\n          <!-- Top -->\n          <header class=\"top\">\n            <div class=\"brand\">\n              <div class=\"name\">LOUIS THAI<\/div>\n              <div class=\"tag\">New Year Orchid Greeting \u2022 Client Appreciation<\/div>\n            <\/div>\n\n            <div class=\"pill\" title=\"Orchid Blessing\">\n              <span class=\"dot\" aria-hidden=\"true\"><\/span>\n              <span>Orchid \u2022 Enduring Trust<\/span>\n            <\/div>\n          <\/header>\n\n          <!-- Center content -->\n          <main class=\"content\">\n            <h1 class=\"headline\">May the new year bloom with clarity, stability, and meaningful growth.<\/h1>\n            <p class=\"sub\">\n              This orchid is a small symbol of our appreciation\u2014quiet strength, refined beauty,\n              and a long-lasting partnership. Thank you for choosing <b>LOUIS THAI<\/b>.\n            <\/p>\n\n            <div class=\"divider\" aria-hidden=\"true\"><\/div>\n\n            <!-- Chinese add-on (optional but recommended for MY clients) -->\n            <p class=\"sub\" lang=\"zh-Hans\" style=\"margin-top:6px;\">\n              \u5170\u82b1\u8c61\u5f81\u9ad8\u96c5\u3001\u7a33\u56fa\u4e0e\u957f\u4e45\u5173\u7cfb\u3002\u613f\u65b0\u7684\u4e00\u5e74\uff0c\u4e3a\u60a8\u5e26\u6765\u6e05\u6670\u3001\u7a33\u5b9a\u4e0e\u6301\u7eed\u6210\u957f\u3002\n              \u611f\u8c22\u60a8\u5bf9 <b>LOUIS THAI<\/b> \u7684\u4fe1\u4efb\u4e0e\u652f\u6301\u3002\n            <\/p>\n\n            <section class=\"deliverBlock\" id=\"deliverBlock\" aria-label=\"Delivery details on card\">\n              <p class=\"deliverTitle\"><span class=\"dot\" aria-hidden=\"true\"><\/span><span>Delivery Details<\/span><\/p>\n              <p class=\"deliverLines\" id=\"deliverLines\"><\/p>\n            <\/section>\n          <\/main>\n\n          <!-- Footer -->\n          <footer class=\"footer\">\n            <div class=\"sig\">\n              <div class=\"line1\">With respect,<\/div>\n              <div class=\"line2\">LOUIS THAI Client Care Team<\/div>\n            <\/div>\n\n            <div class=\"meta\">\n              <div>New Year Gift<\/div>\n              <div id=\"yearLabel\">2026<\/div>\n            <\/div>\n          <\/footer>\n        <\/div>\n\n        <div class=\"note\">Tip: Print \u2192 \u201cSave as PDF\u201d \u2192 choose A6 (or add class size-a5 for A5).<\/div>\n      <\/section>\n    <\/div>\n  <\/div>\n\n  <script>\n    const $ = (id) => document.getElementById(id);\n\n    \/\/ ========= Delivery details state (saved locally) =========\n    const state = { name: \"\", phone: \"\", zip: \"\", address: \"\", showOnCard: true };\n\n    function loadState() {\n      try {\n        const raw = localStorage.getItem(\"LT_orchid_delivery_v2\");\n        if (!raw) return;\n        const s = JSON.parse(raw);\n        if (s && typeof s === \"object\") {\n          state.name = String(s.name ?? \"\");\n          state.phone = String(s.phone ?? \"\");\n          state.zip = String(s.zip ?? \"\");\n          state.address = String(s.address ?? \"\");\n          state.showOnCard = Boolean(s.showOnCard ?? true);\n        }\n      } catch (e) { }\n    }\n\n    function saveState() {\n      try { localStorage.setItem(\"LT_orchid_delivery_v2\", JSON.stringify(state)); } catch (e) { }\n    }\n\n    function renderDelivery() {\n      const block = $(\"deliverBlock\");\n      const lines = $(\"deliverLines\");\n      if (!block || !lines) return;\n\n      const hasAny = (state.name.trim() || state.phone.trim() || state.zip.trim() || state.address.trim());\n      const shouldShow = state.showOnCard && hasAny;\n      block.style.display = shouldShow ? \"block\" : \"none\";\n\n      const parts = [];\n      if (state.name.trim()) parts.push(`Name: ${state.name.trim()}`);\n      if (state.phone.trim()) parts.push(`Phone: ${state.phone.trim()}`);\n      if (state.zip.trim()) parts.push(`Postcode: ${state.zip.trim()}`);\n      if (state.address.trim()) parts.push(`Address: ${state.address.trim()}`);\n      lines.textContent = parts.join(\"\\n\");\n    }\n\n    function bindForm() {\n      const inName = $(\"inName\");\n      const inPhone = $(\"inPhone\");\n      const inZip = $(\"inZip\");\n      const inAddress = $(\"inAddress\");\n      const chk = $(\"chkShowOnCard\");\n\n      if (inName) inName.value = state.name;\n      if (inPhone) inPhone.value = state.phone;\n      if (inZip) inZip.value = state.zip;\n      if (inAddress) inAddress.value = state.address;\n      if (chk) chk.checked = state.showOnCard;\n\n      const onChange = () => {\n        state.name = inName?.value ?? \"\";\n        state.phone = inPhone?.value ?? \"\";\n        state.zip = inZip?.value ?? \"\";\n        state.address = inAddress?.value ?? \"\";\n        state.showOnCard = chk?.checked ?? true;\n        saveState();\n        renderDelivery();\n      };\n\n      inName?.addEventListener(\"input\", onChange);\n      inPhone?.addEventListener(\"input\", onChange);\n      inZip?.addEventListener(\"input\", onChange);\n      inAddress?.addEventListener(\"input\", onChange);\n      chk?.addEventListener(\"change\", onChange);\n\n      $(\"btnClear\")?.addEventListener(\"click\", () => {\n        state.name = \"\"; state.phone = \"\"; state.zip = \"\"; state.address = \"\"; state.showOnCard = true;\n        if (inName) inName.value = \"\";\n        if (inPhone) inPhone.value = \"\";\n        if (inZip) inZip.value = \"\";\n        if (inAddress) inAddress.value = \"\";\n        if (chk) chk.checked = true;\n        saveState();\n        renderDelivery();\n      });\n    }\n\n    \/\/ ========= UHD PNG export (no external libs) =========\n    async function exportCardPNG(targetHeightPx) {\n      const card = document.querySelector(\".card\");\n      if (!card) return;\n\n      const rect = card.getBoundingClientRect();\n      const ratio = rect.width \/ rect.height; \/\/ width\/height\n      const targetWidthPx = Math.round(targetHeightPx * ratio);\n\n      \/\/ Collect styles (single-file export)\n      const styleText = Array.from(document.querySelectorAll(\"style\"))\n        .map(s => s.textContent || \"\")\n        .join(\"\\n\");\n\n      const cardHTML = card.outerHTML;\n\n      const svg =\n        `<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"${targetWidthPx}\" height=\"${targetHeightPx}\">\n  <defs>\n    <style><![CDATA[\n${styleText}\n    ]]><\/style>\n  <\/defs>\n  <foreignObject x=\"0\" y=\"0\" width=\"100%\" height=\"100%\">\n    <div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\" style=\"width:${targetWidthPx}px;height:${targetHeightPx}px;\">\n      ${cardHTML}\n    <\/div>\n  <\/foreignObject>\n<\/svg>`;\n\n      const svgBlob = new Blob([svg], { type: \"image\/svg+xml;charset=utf-8\" });\n      const url = URL.createObjectURL(svgBlob);\n\n      const img = new Image();\n      img.decoding = \"async\";\n      img.loading = \"eager\";\n\n      await new Promise((resolve, reject) => {\n        img.onload = resolve;\n        img.onerror = reject;\n        img.src = url;\n      });\n\n      const canvas = document.createElement(\"canvas\");\n      canvas.width = targetWidthPx;\n      canvas.height = targetHeightPx;\n\n      const ctx = canvas.getContext(\"2d\");\n      ctx.drawImage(img, 0, 0, targetWidthPx, targetHeightPx);\n\n      URL.revokeObjectURL(url);\n\n      const blob = await new Promise(resolve => canvas.toBlob(resolve, \"image\/png\", 1.0));\n      if (!blob) return;\n\n      const a = document.createElement(\"a\");\n      a.href = URL.createObjectURL(blob);\n\n      const y = new Date().getFullYear();\n      a.download = `LOUIS_THAI_Orchid_Greeting_Card_UHD_8K_${y}.png`;\n\n      document.body.appendChild(a);\n      a.click();\n      a.remove();\n\n      setTimeout(() => URL.revokeObjectURL(a.href), 2000);\n    }\n\n    function bindTools() {\n      $(\"btnDownload8k\")?.addEventListener(\"click\", () => exportCardPNG(7680));\n    }\n    \/\/ ========= Orchid Advanced 3D Depth Map =========\n    function initOrchidParallax() {\n      const card = $(\"card\");\n      const canvas = $(\"orchidCanvas\");\n      if (!card || !canvas) return;\n\n      const ctx = canvas.getContext('2d', { alpha: true });\n      let sourcePixels = null;\n      let depthPixels = null;\n      let width = 0, height = 0;\n\n      let mouseX = 0.5, mouseY = 0.5;\n      let targetX = 0.5, targetY = 0.5;\n\n      const config = {\n        intensity: 28,\n        smoothing: 12,\n        breathing: 0.003,\n        source: 'https:\/\/louisthai.com\/wp-content\/uploads\/2026\/01\/orchid_flower_layer.png',\n        depth: 'https:\/\/louisthai.com\/wp-content\/uploads\/2026\/01\/depth_map.png'\n      };\n\n      function loadImage(src) {\n        return new Promise((resolve, reject) => {\n          const img = new Image();\n          img.crossOrigin = \"anonymous\";\n          img.onload = () => resolve(img);\n          img.onerror = reject;\n          img.src = src;\n        });\n      }\n\n      async function loadLayers() {\n        try {\n          const [img, depth] = await Promise.all([\n            loadImage(config.source),\n            loadImage(config.depth)\n          ]);\n\n          width = img.width;\n          height = img.height;\n          canvas.width = width;\n          canvas.height = height;\n\n          const tC = document.createElement('canvas');\n          tC.width = width; tC.height = height;\n          const tCtx = tC.getContext('2d');\n\n          tCtx.drawImage(img, 0, 0);\n          sourcePixels = tCtx.getImageData(0, 0, width, height).data;\n\n          tCtx.drawImage(depth, 0, 0);\n          depthPixels = tCtx.getImageData(0, 0, width, height).data;\n\n          tick();\n        } catch (e) {\n          console.error(\"3D Load Failed:\", e);\n        }\n      }\n\n      function tick() {\n        \/\/ Idle breathing\n        const t = Date.now() * 0.0012;\n        const bx = Math.sin(t * 0.7) * config.breathing;\n        const by = Math.cos(t * 0.5) * config.breathing;\n\n        mouseX += (targetX + bx - mouseX) \/ config.smoothing;\n        mouseY += (targetY + by - mouseY) \/ config.smoothing;\n\n        const offsetX = (mouseX - 0.5) * 2;\n        const offsetY = (mouseY - 0.5) * 2;\n\n        const output = ctx.createImageData(width, height);\n        const out = output.data;\n\n        for (let i = 0; i < out.length; i += 4) {\n          const x = (i \/ 4) % width;\n          const y = Math.floor((i \/ 4) \/ width);\n\n          const depthVal = depthPixels[i] \/ 255;\n          const disp = (depthVal - 0.5) * config.intensity;\n\n          let sx = Math.round(x - offsetX * disp);\n          let sy = Math.round(y - offsetY * disp);\n\n          sx = Math.max(0, Math.min(width - 1, sx));\n          sy = Math.max(0, Math.min(height - 1, sy));\n\n          const sIdx = (sy * width + sx) * 4;\n\n          out[i] = sourcePixels[sIdx];\n          out[i + 1] = sourcePixels[sIdx + 1];\n          out[i + 2] = sourcePixels[sIdx + 2];\n          out[i + 3] = sourcePixels[sIdx + 3];\n        }\n\n        ctx.putImageData(output, 0, 0);\n\n        \/\/ Whole card tilt (premium touch)\n        const rotX = -(mouseY - 0.5) * 8;\n        const rotY = (mouseX - 0.5) * 8;\n        card.style.transform = `rotateX(${rotX.toFixed(2)}deg) rotateY(${rotY.toFixed(2)}deg)`;\n\n        requestAnimationFrame(tick);\n      }\n\n      card.addEventListener('mousemove', (e) => {\n        const r = card.getBoundingClientRect();\n        targetX = (e.clientX - r.left) \/ r.width;\n        targetY = (e.clientY - r.top) \/ r.height;\n      });\n\n      card.addEventListener('mouseleave', () => {\n        targetX = 0.5; targetY = 0.5;\n      });\n\n      window.addEventListener('deviceorientation', (e) => {\n        if (e.gamma !== null) {\n          targetX = 0.5 + Math.max(-1, Math.min(1, e.gamma \/ 45)) * 0.5;\n          targetY = 0.5 + Math.max(-1, Math.min(1, (e.beta - 45) \/ 45)) * 0.5;\n        }\n      }, { passive: true });\n\n      loadLayers();\n    }\n\n\n\n    \/\/ ========= Init =========\n    (function init() {\n      const y = new Date().getFullYear();\n      const yearEl = document.getElementById(\"yearLabel\");\n      if (yearEl) yearEl.textContent = String(y);\n\n      loadState();\n      bindForm();\n      renderDelivery();\n      initOrchidParallax();\n      bindTools();\n    })();\n  <\/script>\n<\/body>\n\n<\/html>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<\/div>","protected":false},"excerpt":{"rendered":"<p>LOUIS THAI \u2014 Orchid Greeting Card Download UHD PNG (8K) Fill delivery details below. The card updates instantly; download a UHD PNG for saving. Delivery Details Client-filled \u2022 Saved on device Recipient Name Phone Number Postcode \/ Zipcode Delivery Address Show delivery details on card (will appear in print\/export) Clear LOUIS THAI New Year Orchid [&hellip;]<\/p>","protected":false},"author":3,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"elementor_canvas","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"ocean_post_layout":"","ocean_both_sidebars_style":"","ocean_both_sidebars_content_width":0,"ocean_both_sidebars_sidebars_width":0,"ocean_sidebar":"","ocean_second_sidebar":"","ocean_disable_margins":"enable","ocean_add_body_class":"","ocean_shortcode_before_top_bar":"","ocean_shortcode_after_top_bar":"","ocean_shortcode_before_header":"","ocean_shortcode_after_header":"","ocean_has_shortcode":"","ocean_shortcode_after_title":"","ocean_shortcode_before_footer_widgets":"","ocean_shortcode_after_footer_widgets":"","ocean_shortcode_before_footer_bottom":"","ocean_shortcode_after_footer_bottom":"","ocean_display_top_bar":"default","ocean_display_header":"default","ocean_header_style":"","ocean_center_header_left_menu":"","ocean_custom_header_template":"","ocean_custom_logo":0,"ocean_custom_retina_logo":0,"ocean_custom_logo_max_width":0,"ocean_custom_logo_tablet_max_width":0,"ocean_custom_logo_mobile_max_width":0,"ocean_custom_logo_max_height":0,"ocean_custom_logo_tablet_max_height":0,"ocean_custom_logo_mobile_max_height":0,"ocean_header_custom_menu":"","ocean_menu_typo_font_family":"","ocean_menu_typo_font_subset":"","ocean_menu_typo_font_size":0,"ocean_menu_typo_font_size_tablet":0,"ocean_menu_typo_font_size_mobile":0,"ocean_menu_typo_font_size_unit":"px","ocean_menu_typo_font_weight":"","ocean_menu_typo_font_weight_tablet":"","ocean_menu_typo_font_weight_mobile":"","ocean_menu_typo_transform":"","ocean_menu_typo_transform_tablet":"","ocean_menu_typo_transform_mobile":"","ocean_menu_typo_line_height":0,"ocean_menu_typo_line_height_tablet":0,"ocean_menu_typo_line_height_mobile":0,"ocean_menu_typo_line_height_unit":"","ocean_menu_typo_spacing":0,"ocean_menu_typo_spacing_tablet":0,"ocean_menu_typo_spacing_mobile":0,"ocean_menu_typo_spacing_unit":"","ocean_menu_link_color":"","ocean_menu_link_color_hover":"","ocean_menu_link_color_active":"","ocean_menu_link_background":"","ocean_menu_link_hover_background":"","ocean_menu_link_active_background":"","ocean_menu_social_links_bg":"","ocean_menu_social_hover_links_bg":"","ocean_menu_social_links_color":"","ocean_menu_social_hover_links_color":"","ocean_disable_title":"default","ocean_disable_heading":"default","ocean_post_title":"","ocean_post_subheading":"","ocean_post_title_style":"","ocean_post_title_background_color":"","ocean_post_title_background":0,"ocean_post_title_bg_image_position":"","ocean_post_title_bg_image_attachment":"","ocean_post_title_bg_image_repeat":"","ocean_post_title_bg_image_size":"","ocean_post_title_height":0,"ocean_post_title_bg_overlay":0.5,"ocean_post_title_bg_overlay_color":"","ocean_disable_breadcrumbs":"default","ocean_breadcrumbs_color":"","ocean_breadcrumbs_separator_color":"","ocean_breadcrumbs_links_color":"","ocean_breadcrumbs_links_hover_color":"","ocean_display_footer_widgets":"default","ocean_display_footer_bottom":"default","ocean_custom_footer_template":"","_joinchat":[],"footnotes":""},"class_list":["post-8114","page","type-page","status-publish","hentry","entry"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/louisthai.com\/hk\/wp-json\/wp\/v2\/pages\/8114","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/louisthai.com\/hk\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/louisthai.com\/hk\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/louisthai.com\/hk\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/louisthai.com\/hk\/wp-json\/wp\/v2\/comments?post=8114"}],"version-history":[{"count":55,"href":"https:\/\/louisthai.com\/hk\/wp-json\/wp\/v2\/pages\/8114\/revisions"}],"predecessor-version":[{"id":8179,"href":"https:\/\/louisthai.com\/hk\/wp-json\/wp\/v2\/pages\/8114\/revisions\/8179"}],"wp:attachment":[{"href":"https:\/\/louisthai.com\/hk\/wp-json\/wp\/v2\/media?parent=8114"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}