{"id":2221,"date":"2025-12-15T11:33:06","date_gmt":"2025-12-15T10:33:06","guid":{"rendered":"https:\/\/christlicher-webdesigner.net\/?page_id=2221"},"modified":"2025-12-15T11:34:21","modified_gmt":"2025-12-15T10:34:21","slug":"chrismas-karten-app","status":"publish","type":"page","link":"https:\/\/christlicher-webdesigner.net\/en\/chrismas-karten-app\/","title":{"rendered":"chrismas-karten-app"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-page\" data-elementor-id=\"2221\" class=\"elementor elementor-2221\" data-elementor-post-type=\"page\">\n\t\t\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-c8a120c elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-id=\"c8a120c\" data-element_type=\"section\" data-e-type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-aefc1e9\" data-id=\"aefc1e9\" data-element_type=\"column\" data-e-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-2ca1862 elementor-widget elementor-widget-html\" data-id=\"2ca1862\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<div id=\"ipsom-widget-root\">\r\n  <!-- Fonts: Poppins (Headings), Inter (Body), Great Vibes (Script) -->\r\n  <link href=\"https:\/\/fonts.googleapis.com\/css2?family=Poppins:wght@400;600;700&family=Inter:wght@400;500;600&family=Great+Vibes&display=swap\" rel=\"stylesheet\">\r\n  \r\n  <style>\r\n    \/* CSS SCOPING *\/\r\n    #ipsom-widget-root {\r\n      \/* CW DESIGN PALETTE (Dark Mode) *\/\r\n      --brand-bg-dark: #0B1120; \/* Deep Navy Background *\/\r\n      --brand-sidebar: #111827; \/* Slightly lighter for sidebar *\/\r\n      --brand-accent: #FFD60A; \/* Bright Yellow *\/\r\n      --brand-accent-hover: #E5C100;\r\n      \r\n      --text-main: #F3F4F6; \/* White\/Light Grey text *\/\r\n      --text-muted: #9CA3AF;\r\n      \r\n      --border-color: #1F2937;\r\n      \r\n      \/* DYNAMIC INK COLORS (Default contrast) *\/\r\n      --ink-main: #FFFFFF;   \r\n      --ink-accent: #FFD60A; \r\n      \r\n      --sidebar-w: 340px;\r\n\r\n      font-family: 'Inter', ui-sans-serif, system-ui, sans-serif;\r\n      color: var(--text-main);\r\n      background: var(--brand-bg-dark);\r\n      width: 100%;\r\n      height: 950px;\r\n      max-height: 95vh;\r\n      position: relative;\r\n      overflow: hidden;\r\n      display: flex;\r\n      border-radius: 12px; \r\n      box-shadow: 0 20px 50px rgba(0,0,0,0.5);\r\n      margin: 20px 0;\r\n      line-height: 1.6;\r\n      -webkit-font-smoothing: antialiased;\r\n      border: 1px solid var(--border-color);\r\n    }\r\n\r\n    #ipsom-widget-root * { box-sizing: border-box; }\r\n\r\n    \/* --- LAYOUT --- *\/\r\n    #ipsom-widget-root .app-container {\r\n      display: flex;\r\n      width: 100%;\r\n      height: 100%;\r\n      position: relative;\r\n      z-index: 2;\r\n    }\r\n\r\n    \/* SIDEBAR *\/\r\n    #ipsom-widget-root .sidebar {\r\n      width: var(--sidebar-w);\r\n      background: var(--brand-sidebar);\r\n      border-right: 1px solid var(--border-color);\r\n      display: flex;\r\n      flex-direction: column;\r\n      z-index: 10;\r\n      flex-shrink: 0;\r\n      overflow-y: auto;\r\n    }\r\n\r\n    #ipsom-widget-root .sidebar-header { padding: 30px 32px 20px; }\r\n\r\n    \/* LOGO AREA - Revised for 2 Logos *\/\r\n    #ipsom-widget-root .logo-wrapper {\r\n      display: flex;\r\n      align-items: center;\r\n      gap: 15px; \/* Space between logos *\/\r\n      margin-bottom: 30px;\r\n    }\r\n    #ipsom-widget-root .logo-img {\r\n        height: 60px; \/* Increased height *\/\r\n        width: auto;\r\n        object-fit: contain;\r\n    }\r\n\r\n    #ipsom-widget-root .headline-block h1 {\r\n      font-family: 'Poppins', sans-serif;\r\n      font-size: 28px;\r\n      line-height: 1.2;\r\n      margin: 0 0 10px 0;\r\n      color: #FFFFFF;\r\n      font-weight: 700;\r\n    }\r\n    #ipsom-widget-root .headline-block h1 span {\r\n      color: var(--brand-accent);\r\n    }\r\n    #ipsom-widget-root .headline-block p {\r\n      font-size: 13px; \r\n      color: var(--text-muted); \r\n      margin: 0;\r\n      font-weight: 500;\r\n    }\r\n\r\n    #ipsom-widget-root .sidebar-actions {\r\n      padding: 0 32px 30px;\r\n      display: flex;\r\n      flex-direction: column;\r\n      gap: 12px;\r\n    }\r\n\r\n    \/* Buttons - Dark Mode Style *\/\r\n    #ipsom-widget-root button { border: none; cursor: pointer; font-family: inherit; transition: all 0.2s ease; outline: none; }\r\n    \r\n    #ipsom-widget-root .btn-block {\r\n      display: flex; align-items: center; justify-content: center;\r\n      gap: 8px; width: 100%; padding: 12px;\r\n      border-radius: 8px;\r\n      font-weight: 600; font-size: 13px;\r\n      font-family: 'Poppins', sans-serif;\r\n    }\r\n    #ipsom-widget-root .btn-dark { \r\n      background: var(--brand-accent); \r\n      color: #000; \/* Black text on Yellow button for contrast *\/\r\n    }\r\n    #ipsom-widget-root .btn-dark:hover { background: var(--brand-accent-hover); transform: translateY(-1px); }\r\n    \r\n    #ipsom-widget-root .btn-outline { \r\n      background: transparent; \r\n      border: 1px solid var(--border-color); \r\n      color: var(--text-main); \r\n    }\r\n    #ipsom-widget-root .btn-outline:hover { \r\n        border-color: var(--brand-accent); \r\n        color: var(--brand-accent);\r\n        background: rgba(255, 214, 10, 0.05);\r\n    }\r\n\r\n    #ipsom-widget-root .text-tools { display: flex; gap: 10px; }\r\n    #ipsom-widget-root .text-tools button { flex: 1; }\r\n\r\n    \/* TABS *\/\r\n    #ipsom-widget-root .sticker-tabs {\r\n        display: flex;\r\n        padding: 4px;\r\n        gap: 4px; \r\n        margin: 0 32px 20px;\r\n        background: #1F2937; \/* Darker tab bg *\/\r\n        border-radius: 8px;\r\n    }\r\n    #ipsom-widget-root .tab-btn {\r\n        flex: 1;\r\n        padding: 8px;\r\n        border-radius: 6px;\r\n        background: transparent;\r\n        color: #9CA3AF;\r\n        font-size: 12px;\r\n        font-weight: 600;\r\n        text-align: center;\r\n        transition: all 0.2s;\r\n        font-family: 'Poppins', sans-serif;\r\n    }\r\n    #ipsom-widget-root .tab-btn.active {\r\n        background: #374151;\r\n        color: #FFFFFF;\r\n    }\r\n\r\n    \/* STICKER AREA *\/\r\n    #ipsom-widget-root .sticker-area {\r\n      flex: 1;\r\n      overflow-y: auto;\r\n      padding: 10px 32px 20px;\r\n      display: flex; flex-direction: column;\r\n    }\r\n    \r\n    #ipsom-widget-root .grid {\r\n      display: grid;\r\n      grid-template-columns: repeat(3, 1fr);\r\n      gap: 12px;\r\n      padding-bottom: 20px;\r\n    }\r\n    \r\n    #ipsom-widget-root .sticker-tile {\r\n      aspect-ratio: 1;\r\n      background: #1F2937; \/* Dark tiles *\/\r\n      border: 1px solid var(--border-color);\r\n      border-radius: 8px;\r\n      display: flex; flex-direction: column;\r\n      align-items: center; justify-content: center;\r\n      cursor: grab;\r\n      transition: all 0.2s;\r\n      user-select: none;\r\n      padding: 6px;\r\n    }\r\n    #ipsom-widget-root .sticker-tile:hover {\r\n      border-color: var(--brand-accent);\r\n      background: #374151;\r\n      transform: translateY(-2px);\r\n    }\r\n    #ipsom-widget-root .sticker-tile:active { cursor: grabbing; transform: scale(0.98); }\r\n    \r\n    #ipsom-widget-root .tile-emoji { font-size: 34px; margin-bottom: 4px; line-height: 1; }\r\n    \r\n    \/* In Sidebar: Force SVGs to be light\/white *\/\r\n    #ipsom-widget-root .tile-svg { width: 100%; height: 36px; display: flex; align-items: center; justify-content: center; margin-bottom: 4px; color: #fff; }\r\n    #ipsom-widget-root .tile-svg svg { width: auto; height: 100%; max-width: 80%; stroke: #E5E7EB; }\r\n    #ipsom-widget-root .tile-svg svg [stroke=\"#F4C430\"] { stroke: var(--brand-accent) !important; }\r\n\r\n    #ipsom-widget-root .tile-name { font-size: 10px; color: #9CA3AF; font-weight: 500; text-align: center; }\r\n\r\n    \/* MAIN STAGE *\/\r\n    #ipsom-widget-root .main-stage {\r\n      flex: 1;\r\n      position: relative;\r\n      background: var(--brand-bg-dark); \/* Dark BG *\/\r\n      display: flex;\r\n      flex-direction: column;\r\n      align-items: center;\r\n      justify-content: center;\r\n      overflow: hidden;\r\n      background-image: radial-gradient(#1F2937 1px, transparent 1px);\r\n      background-size: 30px 30px;\r\n    }\r\n\r\n    \/* TOP CONTROLS ROW *\/\r\n    #ipsom-widget-root .top-bar {\r\n      position: absolute;\r\n      top: 20px;\r\n      width: 100%;\r\n      padding: 0 20px;\r\n      display: flex;\r\n      flex-wrap: wrap; \r\n      align-items: center;\r\n      justify-content: center;\r\n      gap: 8px;\r\n      z-index: 20;\r\n      pointer-events: none;\r\n    }\r\n    #ipsom-widget-root .top-bar > * { pointer-events: auto; }\r\n\r\n    \/* Pill Buttons *\/\r\n    #ipsom-widget-root .pill {\r\n      height: 34px;\r\n      padding: 0 16px;\r\n      border-radius: 99px;\r\n      font-size: 12px;\r\n      font-weight: 600;\r\n      font-family: 'Poppins', sans-serif;\r\n      display: flex; align-items: center; gap: 6px;\r\n      white-space: nowrap;\r\n      transition: all 0.2s;\r\n    }\r\n    #ipsom-widget-root .pill-dark {\r\n      background: #1F2937; \r\n      color: #F3F4F6;\r\n      border: 1px solid #374151;\r\n    }\r\n    #ipsom-widget-root .pill-dark:hover { \r\n        border-color: var(--brand-accent); \r\n        color: var(--brand-accent);\r\n    }\r\n\r\n    #ipsom-widget-root .pill-yellow {\r\n      background: var(--brand-accent); \r\n      color: #000;\r\n      border: 1px solid var(--brand-accent);\r\n    }\r\n    #ipsom-widget-root .pill-yellow:hover { background: var(--brand-accent-hover); border-color: var(--brand-accent-hover); }\r\n    \r\n    #ipsom-widget-root .pill-yellow.off { \r\n        background: #374151; color: #9CA3AF; border-color: #374151; \r\n    }\r\n\r\n    #ipsom-widget-root .reset-link {\r\n      margin-left: 5px;\r\n      font-size: 11px; color: #6B7280;\r\n      text-decoration: none; background: none; border: none;\r\n      font-weight: 600; text-transform: uppercase;\r\n      letter-spacing: 0.05em;\r\n    }\r\n    #ipsom-widget-root .reset-link:hover { color: #EF4444; }\r\n\r\n    \/* CARD *\/\r\n    #ipsom-widget-root .card-container {\r\n      width: min(500px, 85%); \r\n      aspect-ratio: 5\/7; \r\n      max-height: 80%;\r\n      position: relative;\r\n      z-index: 5; \r\n      perspective: 1000px;\r\n      margin-top: 50px; \r\n      transition: all 0.3s ease;\r\n    }\r\n\r\n    #ipsom-widget-root .card {\r\n      width: 100%; height: 100%;\r\n      background: #0f172a; \/* Default to Dark *\/\r\n      border-radius: 8px;\r\n      box-shadow: 0 30px 60px -12px rgba(0,0,0,0.5); \r\n      position: relative;\r\n      overflow: hidden;\r\n      display: block; \r\n      transition: background 0.3s;\r\n      background-size: cover;\r\n      background-position: center;\r\n      border: 1px solid #1F2937;\r\n    }\r\n    \r\n    \/* Noise texture *\/\r\n    #ipsom-widget-root .card::after {\r\n      content: \"\"; position: absolute; inset: 0;\r\n      opacity: 0.05; pointer-events: none;\r\n      background-image: url(\"data:image\/svg+xml,%3Csvg viewBox='0 0 200 200' xmlns='http:\/\/www.w3.org\/2000\/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='3' stitchTiles='stitch'\/%3E%3C\/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'\/%3E%3C\/svg%3E\");\r\n      mix-blend-mode: overlay; z-index: 100;\r\n    }\r\n    \r\n    #ipsom-widget-root .card.exporting::after { display: none !important; }\r\n\r\n    \/* Sticker Items *\/\r\n    #ipsom-widget-root .sticker {\r\n      position: absolute;\r\n      left: var(--x); top: var(--y);\r\n      transform: translate(-50%, -50%) rotate(var(--r)) scale(var(--s));\r\n      cursor: grab; user-select: none; touch-action: none;\r\n      filter: drop-shadow(0 4px 6px rgba(0,0,0,0.3)); \r\n      z-index: var(--z);\r\n      display: flex; align-items: center; justify-content: center;\r\n      text-align: center; white-space: pre-wrap;\r\n    }\r\n    #ipsom-widget-root .sticker:active { cursor: grabbing; }\r\n    #ipsom-widget-root .sticker.selected { filter: drop-shadow(0 15px 30px rgba(0,0,0,0.4)); }\r\n    #ipsom-widget-root .sticker.selected::before {\r\n      content: \"\"; position: absolute; inset: -8px;\r\n      border: 1px dashed var(--brand-accent);\r\n      border-radius: 4px;\r\n      animation: none; pointer-events: none;\r\n    }\r\n    \r\n    #ipsom-widget-root .sticker.is-image img { width: 100px; height: auto; pointer-events: none; border-radius: 4px; }\r\n    #ipsom-widget-root .sticker.is-svg { width: 60px; height: 60px; }\r\n    \r\n    \/* DYNAMIC SVG COLORING ON CARD *\/\r\n    #ipsom-widget-root .sticker.is-svg svg { \r\n        width: 100%; height: 100%; vector-effect: non-scaling-stroke;\r\n        stroke: var(--ink-main); \r\n    }\r\n    #ipsom-widget-root .sticker.is-svg svg [stroke=\"#F4C430\"] { \r\n        stroke: var(--ink-accent) !important; \r\n    }\r\n    \r\n    #ipsom-widget-root .sticker.is-emoji { \r\n        font-size: 56px; line-height: 1; \r\n    }\r\n\r\n    \/* Text Styles *\/\r\n    #ipsom-widget-root .sticker.is-text { \r\n        min-width: 50px; padding: 4px; \r\n        font-family: 'Inter', sans-serif; font-size: 16px; \r\n        color: var(--ink-main);\r\n        font-weight: 500;\r\n    }\r\n    #ipsom-widget-root .sticker.is-heading {\r\n        font-family: 'Poppins', sans-serif; font-size: 42px; font-weight: 700;\r\n        color: var(--ink-accent); \r\n        line-height: 1.1;\r\n    }\r\n    #ipsom-widget-root .sticker.is-script {\r\n        font-family: 'Great Vibes', cursive; font-size: 36px; \r\n        color: var(--ink-accent); \r\n        transform: rotate(-5deg); text-shadow: 0 2px 4px rgba(0,0,0,0.2);\r\n    }\r\n\r\n    \/* Toolbar *\/\r\n    #ipsom-widget-root .mini-toolbar {\r\n      position: absolute; display: none;\r\n      align-items: center; background: #000;\r\n      border-radius: 6px; padding: 6px 10px; gap: 6px;\r\n      z-index: 9999; transform: translate(-50%, 0);\r\n      box-shadow: 0 10px 20px rgba(0,0,0,0.3);\r\n      border: 1px solid #374151;\r\n    }\r\n    #ipsom-widget-root .mini-btn {\r\n      width: 28px; height: 28px; background: rgba(255,255,255,0.1);\r\n      border: none; border-radius: 4px; color: #fff;\r\n      cursor: pointer; display: flex; align-items: center; justify-content: center;\r\n      font-size: 14px; transition: background 0.2s;\r\n    }\r\n    #ipsom-widget-root .mini-btn:hover { background: var(--brand-accent); color: #000; }\r\n    #ipsom-widget-root .mini-btn.btn-del:hover { background: #EF4444; color: #fff; }\r\n    \r\n    #ipsom-widget-root .mini-btn.btn-col {\r\n        font-size: 12px;\r\n    }\r\n\r\n    \/* Modal *\/\r\n    #ipsom-widget-root .ip-modal {\r\n      position: absolute; inset: 0; background: rgba(0,0,0, 0.7); \r\n      z-index: 9999; display: flex; align-items: center; justify-content: center;\r\n      opacity: 0; pointer-events: none; transition: opacity 0.2s; backdrop-filter: blur(5px);\r\n    }\r\n    #ipsom-widget-root .ip-modal.visible { opacity: 1; pointer-events: auto; }\r\n    #ipsom-widget-root .ip-modal-box {\r\n      background: #1F2937; width: 420px; max-width: 90%;\r\n      border-radius: 12px; padding: 30px;\r\n      box-shadow: 0 25px 50px rgba(0, 0, 0, 0.5);\r\n      border: 1px solid #374151;\r\n      color: #fff;\r\n    }\r\n    #ipsom-widget-root .bg-grid { \r\n        display: grid; grid-template-columns: repeat(4, 1fr); \r\n        gap: 12px; margin-top: 15px; margin-bottom: 25px;\r\n        max-height: 250px; overflow-y: auto; padding-right: 4px;\r\n    }\r\n    #ipsom-widget-root .bg-opt {\r\n      aspect-ratio: 1; border-radius: 6px; cursor: pointer;\r\n      border: 2px solid #374151; transition: transform 0.2s;\r\n    }\r\n    #ipsom-widget-root .bg-opt:hover { transform: scale(1.05); border-color: var(--brand-accent); }\r\n\r\n    \/* Custom Gradient Controls *\/\r\n    #ipsom-widget-root .custom-bg-section {\r\n        border-top: 1px solid #374151;\r\n        padding-top: 20px;\r\n    }\r\n    #ipsom-widget-root .color-inputs {\r\n        display: flex; align-items: center; gap: 10px; margin-top: 10px;\r\n    }\r\n    #ipsom-widget-root input[type=\"color\"] {\r\n        -webkit-appearance: none; border: none; width: 40px; height: 40px; \r\n        border-radius: 6px; cursor: pointer; padding: 0; background: none;\r\n    }\r\n    #ipsom-widget-root input[type=\"color\"]::-webkit-color-swatch-wrapper { padding: 0; }\r\n    #ipsom-widget-root input[type=\"color\"]::-webkit-color-swatch { border: 1px solid #4B5563; border-radius: 6px; }\r\n\r\n    \/* Utilities *\/\r\n    #ipsom-widget-root .shake { animation: ip-shake 0.5s cubic-bezier(.36,.07,.19,.97) both; }\r\n    @keyframes ip-shake { 10%,90%{transform:translateX(-1px)} 20%,80%{transform:translateX(2px)} 30%,50%,70%{transform:translateX(-4px)} 40%,60%{transform:translateX(4px)} }\r\n\r\n    #ip-snow { position: absolute; inset: 0; pointer-events: none; z-index: 20; width: 100%; height: 100%; }\r\n    #ip-ghost { position: fixed; pointer-events: none; z-index: 10000; opacity: 0.8; display: none; font-size: 32px; transform: translate(-50%, -50%); }\r\n    #ip-ghost svg { width: 48px; height: 48px; }\r\n\r\n    \/* --- RESPONSIVE MEDIA QUERIES --- *\/\r\n    @media (max-width: 900px) {\r\n      #ipsom-widget-root { \r\n          flex-direction: column; \r\n          height: auto; \r\n          min-height: 100vh;\r\n          border-radius: 0; \r\n          border: none; \r\n          margin: 0;\r\n      }\r\n      #ipsom-widget-root .sidebar { \r\n          width: 100%; \r\n          height: auto; \r\n          border-right: none; \r\n          border-bottom: 1px solid var(--border-color); \r\n      }\r\n      #ipsom-widget-root .sidebar-header {\r\n          padding: 20px;\r\n          display: flex;\r\n          align-items: center;\r\n          gap: 20px;\r\n      }\r\n      #ipsom-widget-root .logo-wrapper { margin-bottom: 0; }\r\n      #ipsom-widget-root .logo-img { height: 32px; }\r\n      #ipsom-widget-root .headline-block h1 { font-size: 20px; margin: 0; }\r\n      #ipsom-widget-root .headline-block p { display: none; }\r\n      \r\n      #ipsom-widget-root .sidebar-actions { padding: 10px 20px; }\r\n      #ipsom-widget-root .sticker-tabs { margin: 0 20px 10px; }\r\n      #ipsom-widget-root .sticker-area { max-height: 180px; padding: 0 20px 20px; }\r\n      \r\n      #ipsom-widget-root .main-stage { \r\n          padding: 60px 10px 40px;\r\n          min-height: 500px; \r\n      }\r\n      #ipsom-widget-root .top-bar { \r\n          top: 10px; \r\n          padding: 0 10px;\r\n          justify-content: flex-start;\r\n          overflow-x: auto; \r\n          flex-wrap: nowrap;\r\n          width: 100%;\r\n          -webkit-overflow-scrolling: touch;\r\n      }\r\n      #ipsom-widget-root .top-bar::-webkit-scrollbar { display: none; }\r\n      \r\n      #ipsom-widget-root .card-container {\r\n          margin-top: 10px;\r\n          width: 90%;\r\n      }\r\n    }\r\n  <\/style>\r\n\r\n  <div class=\"app-container\">\r\n    \r\n    <!-- SIDEBAR -->\r\n    <aside class=\"sidebar\">\r\n      <div class=\"sidebar-header\">\r\n        <div class=\"logo-wrapper\">\r\n          <!-- LOGO 1 -->\r\n          <img decoding=\"async\" class=\"logo-img\" src=\"https:\/\/christlicher-webdesigner.net\/wp-content\/uploads\/2023\/09\/Christlicher-Webdesigner-Thumbnail-Logo.png\" alt=\"CW Logo\">\r\n          <!-- LOGO 2 - UPDATED -->\r\n          <img decoding=\"async\" class=\"logo-img\" src=\"https:\/\/ipsom.at\/wp-content\/uploads\/2025\/05\/Ipsom-favicon.png\" alt=\"Ipsom Logo\">\r\n        <\/div>\r\n        <div class=\"headline-block\">\r\n          <h1>Gesegnete<br><span>WEIHNACHTEN<\/span><\/h1>\r\n          <p>Vom christlichen Webdesigner - Bernd<\/p>\r\n        <\/div>\r\n      <\/div>\r\n\r\n      <div class=\"sidebar-actions\">\r\n        <input type=\"file\" id=\"ip-imgUpload\" hidden accept=\"image\/*\">\r\n        <button class=\"btn-block btn-dark\" id=\"ip-btnUpload\">\r\n            \ud83d\udcf7 Eigenes Bild\r\n        <\/button>\r\n        \r\n        <div class=\"text-tools\">\r\n          <button class=\"btn-block btn-outline\" id=\"ip-btnAddHeading\"><b>+ Titel<\/b><\/button>\r\n          <button class=\"btn-block btn-outline\" id=\"ip-btnAddText\">Aa Text<\/button>\r\n        <\/div>\r\n      <\/div>\r\n\r\n      <div class=\"sticker-tabs\">\r\n          <button class=\"tab-btn active\" id=\"ip-tabElegant\">Motive<\/button>\r\n          <button class=\"tab-btn\" id=\"ip-tabEmoji\">Emojis<\/button>\r\n      <\/div>\r\n\r\n      <div class=\"sticker-area\">\r\n        <div class=\"grid\" id=\"ip-palette\">\r\n          <!-- Populated by JS -->\r\n        <\/div>\r\n      <\/div>\r\n    <\/aside>\r\n\r\n    <!-- MAIN STAGE -->\r\n    <main class=\"main-stage\">\r\n      \r\n      <!-- TOP CONTROL BAR -->\r\n      <div class=\"top-bar\">\r\n        <button class=\"pill pill-dark\" id=\"ip-btnBg\">Hintergrund<\/button>\r\n        <button class=\"pill pill-dark\" id=\"ip-btnJingle\">\u25b6 Jingle<\/button>\r\n        <button class=\"pill pill-dark\" id=\"ip-btnShake\">Wackeln<\/button>\r\n        <button class=\"pill pill-yellow\" id=\"ip-btnSnow\">\u2744\ufe0f Schnee<\/button>\r\n        <button class=\"pill pill-yellow\" id=\"ip-btnSave\">Karte herunterladen \ud83d\udce5<\/button>\r\n        <button class=\"reset-link\" id=\"ip-btnReset\">Reset<\/button>\r\n      <\/div>\r\n\r\n      <div class=\"card-container\">\r\n        <div class=\"card\" id=\"ip-card\">\r\n          <!-- Content -->\r\n          \r\n          <div class=\"mini-toolbar\" id=\"ip-miniToolbar\">\r\n             <button class=\"mini-btn\" id=\"ip-tbEdit\" title=\"Text bearbeiten\" style=\"display:none;\">\u270e<\/button>\r\n             <div id=\"ip-tbSep\" style=\"width:1px; height:16px; background:rgba(255,255,255,0.2); margin:0 4px; display:none;\"><\/div>\r\n             <button class=\"mini-btn btn-col\" id=\"ip-tbColor\" title=\"Farbe \u00e4ndern\">\ud83c\udfa8<\/button>\r\n             <div style=\"width:1px; height:16px; background:rgba(255,255,255,0.2); margin:0 4px;\"><\/div>\r\n             <button class=\"mini-btn\" id=\"ip-tbPlus\">\uff0b<\/button>\r\n             <button class=\"mini-btn\" id=\"ip-tbMinus\">\uff0d<\/button>\r\n             <button class=\"mini-btn\" id=\"ip-tbRotate\">\u27f2<\/button>\r\n             <button class=\"mini-btn btn-del\" id=\"ip-tbDelete\">\u2715<\/button>\r\n          <\/div>\r\n        <\/div>\r\n      <\/div>\r\n      \r\n    <\/main>\r\n  <\/div>\r\n\r\n  <!-- BG Modal -->\r\n  <div id=\"ip-bgModal\" class=\"ip-modal\">\r\n    <div class=\"ip-modal-box\">\r\n       <div style=\"display:flex; justify-content:space-between; margin-bottom:20px; align-items: center;\">\r\n         <h3 style=\"margin:0; font-family:'Poppins', sans-serif; font-size: 20px; color:#FFD60A;\">Hintergrund w\u00e4hlen<\/h3>\r\n         <button id=\"ip-closeBg\" style=\"background:none;border:none;font-size:28px;cursor:pointer; color:#999; line-height:1;\">&times;<\/button>\r\n       <\/div>\r\n       <div class=\"bg-grid\" id=\"ip-bgList\"><\/div>\r\n       \r\n       <!-- Custom Background Section -->\r\n       <div class=\"custom-bg-section\">\r\n           <h4 style=\"margin:0 0 10px; font-size:14px; font-weight:700; color:#F3F4F6; text-transform:uppercase;\">Eigene Farbe<\/h4>\r\n           \r\n           <!-- Gradient -->\r\n           <div style=\"margin-bottom:12px;\">\r\n               <div class=\"color-inputs\">\r\n                 <input type=\"color\" id=\"ip-col1\" value=\"#0B1120\">\r\n                 <span style=\"font-size:16px; color:#9CA3AF;\">\u27a1<\/span>\r\n                 <input type=\"color\" id=\"ip-col2\" value=\"#1E3A8A\">\r\n                 <button class=\"btn-block btn-dark\" id=\"ip-btnCustomBg\" style=\"padding:8px 20px; font-size:12px; margin-left:auto; width:auto;\">Anwenden<\/button>\r\n               <\/div>\r\n           <\/div>\r\n\r\n           <!-- Image Upload -->\r\n           <div style=\"border-top:1px dashed #4B5563; padding-top:12px;\">\r\n                <input type=\"file\" id=\"ip-bgUploadFile\" hidden accept=\"image\/*\">\r\n                <button class=\"btn-block btn-outline\" id=\"ip-btnBgUpload\" style=\"padding:8px; font-size:12px; width:100%; border-style:dashed;\">\r\n                   Eigenes Foto w\u00e4hlen\r\n                <\/button>\r\n           <\/div>\r\n       <\/div>\r\n    <\/div>\r\n  <\/div>\r\n\r\n  <!-- Confirm Modal -->\r\n  <div id=\"ip-confirmModal\" class=\"ip-modal\">\r\n    <div class=\"ip-modal-box\" style=\"text-align:center;\">\r\n       <h3 style=\"margin-top:0; font-family:'Poppins', sans-serif; color:#F3F4F6;\">Neu anfangen?<\/h3>\r\n       <p style=\"color:#9CA3AF; font-size: 16px;\">M\u00f6chtest du alle Elemente l\u00f6schen?<\/p>\r\n       <div style=\"display:flex; gap:10px; justify-content:center; margin-top:25px;\">\r\n         <button class=\"btn-block btn-outline\" id=\"ip-confirmNo\" style=\"width:auto; padding: 10px 30px;\">Nein<\/button>\r\n         <button class=\"btn-block btn-dark\" id=\"ip-confirmYes\" style=\"width:auto; padding: 10px 30px; background:#EF4444; color:#fff;\">Ja, l\u00f6schen<\/button>\r\n       <\/div>\r\n    <\/div>\r\n  <\/div>\r\n\r\n  <canvas id=\"ip-snow\"><\/canvas>\r\n  <div id=\"ip-ghost\"><\/div>\r\n\r\n  <script>\r\n  (() => {\r\n    const root = document.getElementById('ipsom-widget-root');\r\n    if(!root) return;\r\n\r\n    \/\/ --- ASSETS ---\r\n    \/\/ Colors updated for CW Design\r\n    const CW_NAVY = \"#0B1120\";\r\n    const CW_YELLOW = \"#FFD60A\";\r\n    const WHITE = \"#FFFFFF\";\r\n    \r\n    \/\/ SVGs modified to work well on dark bg (lighter strokes)\r\n    \/\/ Dynamic Ink logic handles final color, but default SVG definition helps preview\r\n    const svgs = {\r\n        tree: `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"${WHITE}\" stroke-width=\"1.2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M12 3l-6 10h4l-4 8h12l-4-8h4z\" \/><path d=\"M12 21v-3\" stroke=\"${CW_YELLOW}\"\/><\/svg>`,\r\n        bauble: `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"${WHITE}\" stroke-width=\"1.2\"><circle cx=\"12\" cy=\"14\" r=\"7\"\/><path d=\"M12 7v-4\" stroke=\"${WHITE}\"\/><rect x=\"10.5\" y=\"5\" width=\"3\" height=\"2\" fill=\"${CW_YELLOW}\" stroke=\"none\"\/><path d=\"M9 12s1.5 2 3 2 3-2 3-2\" stroke=\"${CW_YELLOW}\" opacity=\"0.8\"\/><\/svg>`,\r\n        star: `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"${CW_YELLOW}\" stroke-width=\"1.2\"><path d=\"M12 2l2.5 7.5L22 12l-7.5 2.5L12 22l-2.5-7.5L2 12l7.5-2.5z\"\/><circle cx=\"12\" cy=\"12\" r=\"1\" fill=\"${WHITE}\" stroke=\"none\"\/><\/svg>`,\r\n        snow: `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"${WHITE}\" stroke-width=\"1.2\"><path d=\"M12 2v20M2 12h20M17 7l-5 5-5-5M17 17l-5-5-5 5\"\/><\/svg>`,\r\n        wreath: `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"${WHITE}\" stroke-width=\"1.2\" stroke-linecap=\"round\"><path d=\"M12 4a8 8 0 1 0 0 16 8 8 0 0 0 0-16z\" stroke-dasharray=\"1 3\"\/><path d=\"M12 2v3M22 12h-3M12 22v-3M2 12h3\" stroke=\"${CW_YELLOW}\" opacity=\"0.5\"\/><circle cx=\"15\" cy=\"15\" r=\"1.5\" fill=\"${CW_YELLOW}\" stroke=\"none\"\/><circle cx=\"9\" cy=\"9\" r=\"1.5\" fill=\"${CW_YELLOW}\" stroke=\"none\"\/><\/svg>`,\r\n        gift: `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"${WHITE}\" stroke-width=\"1.2\"><rect x=\"5\" y=\"10\" width=\"14\" height=\"10\"\/><path d=\"M12 20V10\" stroke=\"${CW_YELLOW}\"\/><path d=\"M5 10h14\"\/><path d=\"M12 10V7c0-1.5 1.5-1.5 1.5 0s-1.5 3-1.5 3-1.5-3-1.5-3 1.5-1.5 1.5 0v3z\" stroke=\"${CW_YELLOW}\"\/><\/svg>`,\r\n        bell: `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"${WHITE}\" stroke-width=\"1.2\"><path d=\"M12 3a6 6 0 0 0-6 6v7h12V9a6 6 0 0 0-6-6z\"\/><path d=\"M10 16v1a2 2 0 0 0 4 0v-1\" stroke=\"${CW_YELLOW}\"\/><path d=\"M12 3v1\" stroke=\"${CW_YELLOW}\"\/><\/svg>`,\r\n        rein: `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"${WHITE}\" stroke-width=\"1.2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><path d=\"M12 9v5a3 3 0 0 0 6 0V9\" \/><path d=\"M12 14a3 3 0 0 0-6 0\"\/><path d=\"M9 6l3 3 3-3\" stroke=\"${CW_YELLOW}\"\/><path d=\"M7 4l2 2M17 4l-2 2\" stroke=\"${CW_YELLOW}\"\/><\/svg>`,\r\n        bow: `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"${CW_YELLOW}\" stroke-width=\"1.2\"><path d=\"M12 14c-2 0-3-2-3-4s2-3 3-3 3 1 3 3-1 4-3 4z\"\/><path d=\"M12 14l-3 5M12 14l3 5\" stroke=\"${WHITE}\"\/><\/svg>`,\r\n        cand: `<svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"${WHITE}\" stroke-width=\"1.2\"><rect x=\"9\" y=\"11\" width=\"6\" height=\"10\"\/><path d=\"M12 11V7\" stroke=\"${CW_YELLOW}\"\/><ellipse cx=\"12\" cy=\"4\" rx=\"1.5\" ry=\"2.5\" fill=\"${CW_YELLOW}\" stroke=\"none\"\/><\/svg>`\r\n    };\r\n\r\n    const ELEGANT = [\r\n      { id:\"tree\", name:\"Baum\", svg: svgs.tree },\r\n      { id:\"gift\", name:\"Geschenk\", svg: svgs.gift },\r\n      { id:\"star\", name:\"Stern\", svg: svgs.star },\r\n      { id:\"bow\", name:\"Schleife\", svg: svgs.bow },\r\n      { id:\"candle\", name:\"Licht\", svg: svgs.cand },\r\n      { id:\"ballgold\", name:\"Kugel\", svg: svgs.bauble },\r\n      { id:\"snow\", name:\"Schnee\", svg: svgs.snow },\r\n      { id:\"wreath\", name:\"Kranz\", svg: svgs.wreath },\r\n      { id:\"bell\", name:\"Glocke\", svg: svgs.bell }\r\n    ];\r\n\r\n    const EMOJIS = [\r\n      { id:\"angel\", name:\"Engel\", emoji:\"\ud83d\udc7c\" },\r\n      { id:\"church\", name:\"Kirche\", emoji:\"\u26ea\" },\r\n      { id:\"dove\", name:\"Taube\", emoji:\"\ud83d\udd4a\ufe0f\" },\r\n      { id:\"pray\", name:\"Gebet\", emoji:\"\ud83d\ude4f\" },\r\n      { id:\"baby\", name:\"Krippe\", emoji:\"\ud83d\udc76\" },\r\n      { id:\"bible\", name:\"Bibel\", emoji:\"\ud83d\udcd6\" },\r\n      { id:\"cross\", name:\"Kreuz\", emoji:\"\u271d\ufe0f\" },\r\n      { id:\"candle_e\", name:\"Kerze\", emoji:\"\ud83d\udd6f\ufe0f\" },\r\n      { id:\"star_e\", name:\"Stern\", emoji:\"\ud83c\udf1f\" },\r\n      { id:\"sheep\", name:\"Schaf\", emoji:\"\ud83d\udc11\" },\r\n      { id:\"heart\", name:\"Herz\", emoji:\"\ud83d\udc9b\" },\r\n      { id:\"pinetree\", name:\"Tanne\", emoji:\"\ud83c\udf32\" },\r\n      { id:\"gift_e\", name:\"Geschenk\", emoji:\"\ud83c\udf81\" },\r\n      { id:\"snowflake\", name:\"Flocke\", emoji:\"\u2744\ufe0f\" },\r\n      { id:\"snowman\", name:\"Schneemann\", emoji:\"\u26c4\" }\r\n    ];\r\n\r\n    const BGS = [\r\n      \/\/ DARK THEMES\r\n      { bg: \"#0B1120\", name: \"Deep Navy\", inkMain: \"#FFFFFF\", inkAccent: \"#FFD60A\" }, \r\n      { bg: \"#111827\", name: \"Charcoal\", inkMain: \"#FFFFFF\", inkAccent: \"#FFD60A\" },\r\n      { bg: \"linear-gradient(to bottom, #0B1120, #1E3A8A)\", name: \"Midnight\", inkMain: \"#FFFFFF\", inkAccent: \"#FFD60A\" },\r\n      \r\n      \/\/ LIGHT THEMES (For contrast)\r\n      { bg: \"#FFFFFF\", name: \"Wei\u00df\", inkMain: \"#0B1120\", inkAccent: \"#D97706\" },\r\n      { bg: \"#F3F4F6\", name: \"Hellgrau\", inkMain: \"#0B1120\", inkAccent: \"#D97706\" },\r\n      \r\n      \/\/ CHRISTMAS\r\n      { bg: \"#7F1D1D\", name: \"Weihnachtsrot\", inkMain: \"#FFFFFF\", inkAccent: \"#FFD60A\" },\r\n      { bg: \"#14532D\", name: \"Tannengr\u00fcn\", inkMain: \"#FFFFFF\", inkAccent: \"#FFD60A\" }\r\n    ];\r\n\r\n    \/\/ STATE\r\n    let items = new Map();\r\n    let nextId = 1;\r\n    let maxZ = 10;\r\n    let selectedId = null;\r\n    let activeTab = 'elegant'; \r\n    let snowOn = true;\r\n    let isPlaying = false;\r\n    let audioCtx = null;\r\n    let activeNodes = [];\r\n    let bgGainNode = null;\r\n    let timeouts = [];\r\n\r\n    const getEl = (id) => root.querySelector('#' + id);\r\n    const card = getEl('ip-card');\r\n    const ghost = getEl('ip-ghost');\r\n    const tb = getEl('ip-miniToolbar');\r\n    const btnCol = getEl('ip-tbColor');\r\n    const btnEdit = getEl('ip-tbEdit');\r\n    const sep = getEl('ip-tbSep');\r\n\r\n    \/\/ AUDIO SYSTEM\r\n    function initAudio() {\r\n        if(!audioCtx) {\r\n            audioCtx = new (window.AudioContext || window.webkitAudioContext)();\r\n            bgGainNode = audioCtx.createGain();\r\n            bgGainNode.connect(audioCtx.destination);\r\n            bgGainNode.gain.value = 0.3; \/\/ Master volume\r\n        }\r\n        if(audioCtx.state === 'suspended') {\r\n            audioCtx.resume();\r\n        }\r\n    }\r\n\r\n    function playTone(freq, time, duration, type='sine', vol=0.5) {\r\n        if(!audioCtx) return;\r\n        const osc = audioCtx.createOscillator();\r\n        const gain = audioCtx.createGain();\r\n        osc.type = type;\r\n        osc.frequency.value = freq;\r\n        osc.connect(gain);\r\n        gain.connect(bgGainNode);\r\n        \r\n        osc.start(time);\r\n        \r\n        \/\/ Envelope: Attack, Decay\r\n        gain.gain.setValueAtTime(0, time);\r\n        gain.gain.linearRampToValueAtTime(vol, time + 0.05);\r\n        gain.gain.exponentialRampToValueAtTime(0.001, time + duration);\r\n        \r\n        osc.stop(time + duration);\r\n        \r\n        activeNodes.push(osc);\r\n        osc.onended = () => {\r\n            const idx = activeNodes.indexOf(osc);\r\n            if(idx > -1) activeNodes.splice(idx, 1);\r\n        };\r\n    }\r\n    \r\n    function playKick(time) {\r\n        if(!audioCtx) return;\r\n        const osc = audioCtx.createOscillator();\r\n        const gain = audioCtx.createGain();\r\n        \r\n        osc.frequency.setValueAtTime(150, time);\r\n        osc.frequency.exponentialRampToValueAtTime(0.01, time + 0.5);\r\n        \r\n        gain.gain.setValueAtTime(0.8, time);\r\n        gain.gain.exponentialRampToValueAtTime(0.001, time + 0.5);\r\n        \r\n        osc.connect(gain);\r\n        gain.connect(bgGainNode);\r\n        \r\n        osc.start(time);\r\n        osc.stop(time + 0.5);\r\n        activeNodes.push(osc);\r\n        \r\n        osc.onended = () => {\r\n            const idx = activeNodes.indexOf(osc);\r\n            if(idx > -1) activeNodes.splice(idx, 1);\r\n        };\r\n    }\r\n\r\n    function playHat(time) {\r\n        if(!audioCtx) return;\r\n        const osc = audioCtx.createOscillator();\r\n        const gain = audioCtx.createGain();\r\n        osc.type = 'square';\r\n        osc.frequency.setValueAtTime(800 + Math.random()*200, time);\r\n        \r\n        gain.gain.setValueAtTime(0.1, time);\r\n        gain.gain.exponentialRampToValueAtTime(0.001, time + 0.1);\r\n        \r\n        osc.connect(gain);\r\n        gain.connect(bgGainNode);\r\n        \r\n        osc.start(time);\r\n        osc.stop(time + 0.1);\r\n        activeNodes.push(osc);\r\n        \r\n        osc.onended = () => {\r\n            const idx = activeNodes.indexOf(osc);\r\n            if(idx > -1) activeNodes.splice(idx, 1);\r\n        };\r\n    }\r\n    \r\n    \/\/ Play single click sound (feedback)\r\n    function play(freq) {\r\n        initAudio();\r\n        playTone(freq, audioCtx.currentTime, 0.1, 'sine', 0.1);\r\n    }\r\n\r\n    \/\/ Advanced Jingle Bells - INFINITE LOOP\r\n    function startJingle() {\r\n        initAudio();\r\n        stopJingle(); \/\/ Reset\r\n        \r\n        isPlaying = true;\r\n        const btn = getEl('ip-btnJingle');\r\n        btn.innerHTML = \"\u23f9 Stop\";\r\n        btn.classList.remove('pill-dark');\r\n        btn.classList.add('pill-yellow');\r\n\r\n        \/\/ Initial setup for the loop\r\n        const beat = 0.18; \/\/ Slightly faster tempo\r\n        \r\n        \/\/ Notes\r\n        const N = { \r\n            C3: 130.8, G3: 196.0, \r\n            C4: 261.6, D4: 293.7, E4: 329.6, F4: 349.2, G4: 392.0, A4: 440.0\r\n        };\r\n\r\n        \/\/ Melody Pattern (Note, Duration in beats)\r\n        const melody = [\r\n            {n:N.E4, d:2}, {n:N.E4, d:2}, {n:N.E4, d:4},\r\n            {n:N.E4, d:2}, {n:N.E4, d:2}, {n:N.E4, d:4},\r\n            {n:N.E4, d:2}, {n:N.G4, d:2}, {n:N.C4, d:3}, {n:N.D4, d:1}, {n:N.E4, d:8},\r\n            \r\n            {n:N.F4, d:2}, {n:N.F4, d:2}, {n:N.F4, d:3}, {n:N.F4, d:1},\r\n            {n:N.F4, d:2}, {n:N.E4, d:2}, {n:N.E4, d:2}, {n:N.E4, d:1}, {n:N.E4, d:1},\r\n            {n:N.E4, d:2}, {n:N.D4, d:2}, {n:N.D4, d:2}, {n:N.E4, d:2}, {n:N.D4, d:4}, {n:N.G4, d:4}\r\n        ];\r\n\r\n        \/\/ Bass Line (Root notes)\r\n        const bass = [\r\n            {n:N.C3, d:8}, {n:N.C3, d:8}, {n:N.C3, d:8}, {n:N.C3, d:8},\r\n            {n:N.F4, d:8}, {n:N.C3, d:8}, {n:N.G3, d:8}, {n:N.G3, d:8} \r\n        ];\r\n\r\n        let nextNoteTime = audioCtx.currentTime + 0.1;\r\n        const cycleDuration = 64 * beat; \r\n\r\n        \/\/ Recursive scheduler function\r\n        function scheduleNextBatch() {\r\n            if (!isPlaying) return;\r\n\r\n            \/\/ Schedule Melody (64 units)\r\n            let t = nextNoteTime;\r\n            melody.forEach(m => {\r\n                if (m.n) playTone(m.n, t, m.d * beat * 0.85, 'triangle', 0.3);\r\n                t += m.d * beat;\r\n            });\r\n\r\n            \/\/ Schedule Bass (8 units x 8 times = 64 units)\r\n            t = nextNoteTime;\r\n            for(let i=0; i<8; i++) {\r\n                bass.forEach(b => {\r\n                    if (b.n) playTone(b.n, t, b.d * beat * 0.8, 'sine', 0.25);\r\n                    t += b.d * beat;\r\n                });\r\n            }\r\n\r\n            \/\/ Schedule Drums (4 units x 16 times = 64 units)\r\n            t = nextNoteTime;\r\n            for(let i=0; i<16; i++) {\r\n                playKick(t);\r\n                playHat(t + 2*beat); \/\/ Offbeat hat\r\n                t += 4 * beat;\r\n            }\r\n\r\n            \/\/ Advance time for next cycle\r\n            nextNoteTime += cycleDuration;\r\n\r\n            \/\/ Schedule next call slightly before current batch ends\r\n            const timeUntilNextBatch = nextNoteTime - audioCtx.currentTime;\r\n            \/\/ Wake up 200ms before current batch ends to schedule next one\r\n            const timeoutDuration = (timeUntilNextBatch * 1000) - 200; \r\n            \r\n            const timerId = setTimeout(scheduleNextBatch, Math.max(0, timeoutDuration));\r\n            timeouts.push(timerId);\r\n        }\r\n\r\n        \/\/ Start the loop\r\n        scheduleNextBatch();\r\n    }\r\n\r\n    function stopJingle() {\r\n        isPlaying = false;\r\n        timeouts.forEach(t => clearTimeout(t));\r\n        timeouts = [];\r\n        \r\n        \/\/ Stop all oscillators immediately\r\n        activeNodes.forEach(node => {\r\n            try { node.stop(); } catch(e){}\r\n        });\r\n        activeNodes = [];\r\n        \r\n        const btn = getEl('ip-btnJingle');\r\n        btn.innerHTML = \"\u25b6 Jingle\";\r\n        btn.classList.add('pill-dark');\r\n        btn.classList.remove('pill-yellow');\r\n    }\r\n\r\n    \/\/ INIT\r\n    function init() {\r\n        renderPalette();\r\n        \r\n        getEl('ip-tabElegant').onclick = () => setTab('elegant');\r\n        getEl('ip-tabEmoji').onclick = () => setTab('emoji');\r\n\r\n        \/\/ Backgrounds\r\n        const bgList = getEl('ip-bgList');\r\n        BGS.forEach(b => {\r\n            const d = document.createElement('div'); d.className='bg-opt';\r\n            d.style.background = b.bg;\r\n            d.title = b.name;\r\n            d.onclick = () => { \r\n                card.style.background = b.bg;\r\n                \r\n                \/\/ Adjust background-size for patterns vs gradients\r\n                if(b.isPattern) {\r\n                    card.style.backgroundSize = \"auto\";\r\n                    card.style.backgroundColor = \"#0B1120\"; \r\n                } else {\r\n                    card.style.backgroundSize = \"cover\";\r\n                    if(!b.bg.includes('gradient') && !b.bg.includes('url')) {\r\n                         card.style.backgroundColor = b.bg;\r\n                    }\r\n                }\r\n\r\n                \/\/ Update CSS Variables for Dynamic Contrast\r\n                if (b.inkMain) {\r\n                    root.style.setProperty('--ink-main', b.inkMain);\r\n                    root.style.setProperty('--ink-accent', b.inkAccent);\r\n                }\r\n\r\n                getEl('ip-bgModal').classList.remove('visible'); \r\n            };\r\n            bgList.appendChild(d);\r\n        });\r\n        \r\n        \/\/ Custom Gradient Logic\r\n        getEl('ip-btnCustomBg').onclick = () => {\r\n            const c1 = getEl('ip-col1').value;\r\n            const c2 = getEl('ip-col2').value;\r\n            card.style.background = `linear-gradient(135deg, ${c1}, ${c2})`;\r\n            card.style.backgroundSize = \"cover\";\r\n            getEl('ip-bgModal').classList.remove('visible');\r\n        };\r\n\r\n        \/\/ Custom Background Image Upload\r\n        getEl('ip-btnBgUpload').onclick = () => getEl('ip-bgUploadFile').click();\r\n        getEl('ip-bgUploadFile').onchange = (e) => {\r\n            if(e.target.files[0]) {\r\n                const r = new FileReader();\r\n                r.onload = ev => {\r\n                    \/\/ Set background image and ensure it covers correctly\r\n                    card.style.background = `url(${ev.target.result}) no-repeat center center \/ cover`;\r\n                    card.style.backgroundSize = \"cover\";\r\n                    getEl('ip-bgModal').classList.remove('visible');\r\n                };\r\n                r.readAsDataURL(e.target.files[0]);\r\n            }\r\n        };\r\n\r\n        \/\/ DEFAULT CONTENT & BG (Deep Navy)\r\n        const defaultBg = BGS[0]; \r\n        card.style.background = defaultBg.bg;\r\n        card.style.backgroundColor = defaultBg.bg;\r\n        card.style.backgroundSize = \"cover\"; \r\n        \r\n        \/\/ Set initial contrast colors\r\n        root.style.setProperty('--ink-main', defaultBg.inkMain);\r\n        root.style.setProperty('--ink-accent', defaultBg.inkAccent);\r\n        \r\n        \/\/ Updated Layout\r\n        addItem('text', {t:'GESEGNETE\\nWEIHNACHTEN', y:'30%', head:true});\r\n        addItem('text', {t:'M\u00f6ge dein Herz erf\u00fcllt sein\\nvon Frieden und Freude \u00fcber unseren Herrn Jesus Christus.', y:'50%'});\r\n        addItem('text', {t:'Bernd & Team', y:'75%', script:true}); \r\n        \r\n        \/\/ Symbols in 4 corners\r\n        addItem('tree', {x:'10%', y:'15%', r:-10}); \/\/ Top Left\r\n        addItem('star', {x:'90%', y:'15%', r:15});  \/\/ Top Right\r\n        addItem('gift', {x:'10%', y:'85%', r:-15}); \/\/ Bottom Left\r\n        addItem('candle', {x:'90%', y:'85%', r:0}); \/\/ Bottom Right\r\n        \r\n        resizeSnow(); loopSnow();\r\n    }\r\n\r\n    function setTab(t) {\r\n        activeTab = t;\r\n        getEl('ip-tabElegant').className = `tab-btn ${t==='elegant'?'active':''}`;\r\n        getEl('ip-tabEmoji').className = `tab-btn ${t==='emoji'?'active':''}`;\r\n        renderPalette();\r\n    }\r\n\r\n    function renderPalette() {\r\n        const p = getEl('ip-palette'); p.innerHTML='';\r\n        const list = activeTab === 'elegant' ? ELEGANT : EMOJIS;\r\n        \r\n        list.forEach(s => {\r\n            const el = document.createElement('div'); el.className='sticker-tile';\r\n            if(s.svg) el.innerHTML = `<div class=\"tile-svg\">${s.svg}<\/div><div class=\"tile-name\">${s.name}<\/div>`;\r\n            else el.innerHTML = `<div class=\"tile-emoji\">${s.emoji}<\/div><div class=\"tile-name\">${s.name}<\/div>`;\r\n            \r\n            el.onpointerdown = (e) => startDragPalette(e, s);\r\n            el.onclick = () => { addItem(s.id); play(600); };\r\n            p.appendChild(el);\r\n        });\r\n    }\r\n\r\n    \/\/ ACTIONS\r\n    function addItem(type, opts={}) {\r\n        const id = 'item-'+(nextId++);\r\n        let def = ELEGANT.find(s=>s.id===type) || EMOJIS.find(s=>s.id===type);\r\n        \r\n        let content = '';\r\n        let isImg=false, isSvg=false, isText=false, isHead=false, isScript=false, isEmoji=false;\r\n\r\n        if(type==='image') { isImg=true; content=`<img decoding=\"async\" src=\"${opts.src}\">`; }\r\n        else if(type==='text') { \r\n            isText=true; \r\n            isHead=opts.head;\r\n            isScript=opts.script;\r\n            content = opts.t || 'Dein Text';\r\n        }\r\n        else {\r\n            \/\/ If dragging from palette\r\n            if(def) {\r\n                if(def.svg) { isSvg=true; content=def.svg; }\r\n                else {\r\n                    isEmoji = true;\r\n                    content = def.emoji;\r\n                }\r\n            }\r\n        }\r\n\r\n        const item = {\r\n            id, type, \r\n            x: opts.x||'50%', y: opts.y||'50%', \r\n            r: opts.r||0, s: opts.s||1, z: maxZ++,\r\n            isText, isImg, isSvg, isEmoji\r\n        };\r\n        items.set(id, item);\r\n\r\n        const el = document.createElement('div');\r\n        el.className = 'sticker'; el.id = id;\r\n        if(isImg) el.classList.add('is-image');\r\n        if(isSvg) el.classList.add('is-svg');\r\n        if(isEmoji) el.classList.add('is-emoji');\r\n        \r\n        if(isText) {\r\n            el.classList.add('is-text');\r\n            if(isHead) el.classList.add('is-heading');\r\n            if(isScript) el.classList.add('is-script');\r\n            \r\n            \/\/ Initial color set, but handled by CSS var for robustness\r\n            el.style.color = 'var(--ink-main)';\r\n            if(isScript || isHead) {\r\n                 el.style.color = 'var(--ink-accent)'; \r\n            }\r\n\r\n            el.textContent = content;\r\n            el.ondblclick = (e) => {\r\n                e.stopPropagation();\r\n                enableEditing(el);\r\n                select(null);\r\n            };\r\n            el.onblur = () => {\r\n                el.contentEditable = false;\r\n                el.style.userSelect = \"none\";\r\n                el.style.webkitUserSelect = \"none\";\r\n            };\r\n        } else {\r\n            el.innerHTML = content;\r\n        }\r\n\r\n        updateEl(el, item);\r\n        el.onpointerdown = (e) => {\r\n            if(el.isContentEditable) return;\r\n            startDragCard(e, id);\r\n        };\r\n        card.appendChild(el);\r\n        return id;\r\n    }\r\n\r\n    function enableEditing(el) {\r\n        el.contentEditable = true;\r\n        el.style.userSelect = \"text\"; \r\n        el.style.webkitUserSelect = \"text\";\r\n        el.focus();\r\n        \r\n        if (document.createRange && window.getSelection) {\r\n            const range = document.createRange();\r\n            range.selectNodeContents(el);\r\n            range.collapse(false);\r\n            const sel = window.getSelection();\r\n            sel.removeAllRanges();\r\n            sel.addRange(range);\r\n        }\r\n    }\r\n\r\n    function updateEl(el, item) {\r\n        el.style.setProperty('--x', item.x);\r\n        el.style.setProperty('--y', item.y);\r\n        el.style.setProperty('--r', item.r+'deg');\r\n        el.style.setProperty('--s', item.s);\r\n        el.style.setProperty('--z', item.z);\r\n    }\r\n\r\n    function select(id) {\r\n        if(selectedId) {\r\n            const old = card.querySelector('#'+selectedId);\r\n            if(old) old.classList.remove('selected');\r\n        }\r\n        selectedId = id;\r\n        if(id) {\r\n            const el = card.querySelector('#'+id);\r\n            el.classList.add('selected');\r\n            showTb(el);\r\n        } else {\r\n            tb.style.display = 'none';\r\n        }\r\n    }\r\n\r\n    function showTb(el) {\r\n        const item = items.get(el.id);\r\n        const rect = card.getBoundingClientRect();\r\n        const pxX = (parseFloat(item.x)\/100)*rect.width;\r\n        const pxY = (parseFloat(item.y)\/100)*rect.height;\r\n        let off = 50 * item.s;\r\n        if(item.isText) off += 20;\r\n\r\n        tb.style.display = 'flex';\r\n        tb.style.left = pxX + 'px';\r\n        tb.style.top = (pxY + off) + 'px';\r\n        \r\n        \/\/ Show\/Hide Edit Button only for text\r\n        btnEdit.style.display = item.isText ? 'flex' : 'none';\r\n        sep.style.display = item.isText ? 'block' : 'none';\r\n        \r\n        \/\/ Show\/Hide Color Button\r\n        btnCol.style.display = item.isText ? 'flex' : 'none';\r\n    }\r\n\r\n    \/\/ BUTTONS\r\n    getEl('ip-btnUpload').onclick = () => getEl('ip-imgUpload').click();\r\n    getEl('ip-imgUpload').onchange = (e) => {\r\n        if(e.target.files[0]) {\r\n            const r = new FileReader();\r\n            r.onload = ev => { addItem('image', {src:ev.target.result}); };\r\n            r.readAsDataURL(e.target.files[0]);\r\n        }\r\n    };\r\n    getEl('ip-btnAddHeading').onclick = () => { addItem('text', {head:true, t:'\u00dcberschrift', y:'30%'}); play(500); };\r\n    getEl('ip-btnAddText').onclick = () => { addItem('text', {t:'Dein Text hier...', y:'60%'}); play(500); };\r\n    \r\n    \/\/ Top Bar\r\n    getEl('ip-btnBg').onclick = () => getEl('ip-bgModal').classList.add('visible');\r\n    getEl('ip-closeBg').onclick = () => getEl('ip-bgModal').classList.remove('visible');\r\n    \r\n    getEl('ip-btnShake').onclick = () => {\r\n        card.classList.remove('shake'); void card.offsetWidth; card.classList.add('shake');\r\n        play(150); burstSnow();\r\n    };\r\n\r\n    getEl('ip-btnSnow').onclick = () => {\r\n        snowOn = !snowOn;\r\n        getEl('ip-btnSnow').classList.toggle('off', !snowOn);\r\n    };\r\n\r\n    \/\/ Jingle Button Logic\r\n    getEl('ip-btnJingle').onclick = () => {\r\n        if(isPlaying) stopJingle(); else startJingle();\r\n    };\r\n\r\n    getEl('ip-btnReset').onclick = () => {\r\n        getEl('ip-confirmModal').classList.add('visible');\r\n    };\r\n\r\n    getEl('ip-confirmNo').onclick = () => {\r\n        getEl('ip-confirmModal').classList.remove('visible');\r\n    };\r\n\r\n    getEl('ip-confirmYes').onclick = () => {\r\n        getEl('ip-confirmModal').classList.remove('visible');\r\n        \r\n        \/\/ Correct deletion logic: remove only sticker elements\r\n        items.forEach((_, id) => {\r\n            const el = document.getElementById(id);\r\n            if(el) el.remove();\r\n        });\r\n        items.clear();\r\n        select(null);\r\n\r\n        \/\/ Reset BG\r\n        const def = BGS[0]; \r\n        card.style.background = def.bg;\r\n        card.style.backgroundColor = def.bg;\r\n        card.style.backgroundSize = \"cover\";\r\n        root.style.setProperty('--ink-main', def.inkMain);\r\n        root.style.setProperty('--ink-accent', def.inkAccent);\r\n    };\r\n\r\n    \/\/ Modified Save function to handle mix-blend-mode texture issue\r\n    getEl('ip-btnSave').onclick = () => {\r\n        select(null);\r\n        \/\/ Add class to hide texture during capture\r\n        card.classList.add('exporting');\r\n        \r\n        import('https:\/\/html2canvas.hertzen.com\/dist\/html2canvas.min.js').then(() => {\r\n            html2canvas(card, {\r\n                scale: 2, \r\n                backgroundColor: null, \/\/ Allow transparent\/gradient bg\r\n                useCORS: true \r\n            }).then(c => {\r\n                \/\/ Remove class to restore texture\r\n                card.classList.remove('exporting');\r\n                const a = document.createElement('a');\r\n                a.download = 'CW-Weihnachtskarte.jpg'; \r\n                a.href = c.toDataURL('image\/jpeg', 1.0); \r\n                a.click();\r\n            }).catch(e => {\r\n                card.classList.remove('exporting');\r\n                console.error(e);\r\n            });\r\n        });\r\n    };\r\n\r\n    \/\/ Toolbar Logic\r\n    getEl('ip-tbPlus').onclick = (e) => { e.stopPropagation(); modItem(i => i.s += 0.1); };\r\n    getEl('ip-tbMinus').onclick = (e) => { e.stopPropagation(); modItem(i => i.s = Math.max(0.2, i.s-0.1)); };\r\n    getEl('ip-tbRotate').onclick = (e) => { e.stopPropagation(); modItem(i => i.r += 15); };\r\n    getEl('ip-tbDelete').onclick = (e) => { \r\n        e.stopPropagation(); \r\n        if(selectedId) { card.querySelector('#'+selectedId).remove(); items.delete(selectedId); select(null); }\r\n    };\r\n    \r\n    \/\/ Edit Button Logic\r\n    getEl('ip-tbEdit').onclick = (e) => {\r\n        e.stopPropagation();\r\n        if(selectedId) {\r\n            const el = card.querySelector('#'+selectedId);\r\n            if(items.get(selectedId).isText) {\r\n                enableEditing(el);\r\n            }\r\n        }\r\n    };\r\n    \r\n    \/\/ Toggle Text Color\r\n    const textColors = ['#FFFFFF', '#FFD60A', '#0B1120', '#EF4444']; \/\/ White, Yellow, Navy, Red\r\n    getEl('ip-tbColor').onclick = (e) => {\r\n        e.stopPropagation();\r\n        if(selectedId) {\r\n            const el = card.querySelector('#'+selectedId);\r\n            if(items.get(selectedId).isText) {\r\n                let idx = parseInt(el.dataset.colIdx || 0);\r\n                idx = (idx + 1) % textColors.length;\r\n                el.dataset.colIdx = idx;\r\n                el.style.color = textColors[idx];\r\n            }\r\n        }\r\n    };\r\n\r\n    function modItem(fn) {\r\n        if(selectedId) {\r\n            const i = items.get(selectedId); fn(i);\r\n            updateEl(card.querySelector('#'+selectedId), i);\r\n            showTb(card.querySelector('#'+selectedId));\r\n        }\r\n    }\r\n\r\n    \/\/ DRAG\r\n    let drag = null;\r\n    function startDragCard(e, id) {\r\n        e.stopPropagation(); e.preventDefault();\r\n        const item = items.get(id);\r\n        item.z = ++maxZ; updateEl(card.querySelector('#'+id), item);\r\n        select(id);\r\n        drag = { id, type:'card', sx:e.clientX, sy:e.clientY, px:parseFloat(item.x), py:parseFloat(item.y) };\r\n        window.addEventListener('pointermove', onMove);\r\n        window.addEventListener('pointerup', onUp);\r\n    }\r\n    function startDragPalette(e, def) {\r\n        drag = { type:'palette', def, sx:e.clientX, sy:e.clientY, moved:false };\r\n        window.addEventListener('pointermove', onMove);\r\n        window.addEventListener('pointerup', onUp);\r\n    }\r\n\r\n    function onMove(e) {\r\n        if(!drag) return;\r\n        if(drag.type === 'palette') {\r\n            if(Math.hypot(e.clientX-drag.sx, e.clientY-drag.sy) > 5) {\r\n                drag.moved = true;\r\n                ghost.style.display = 'block';\r\n                ghost.style.left = e.clientX+'px'; ghost.style.top = e.clientY+'px';\r\n                if(drag.def.svg) ghost.innerHTML = drag.def.svg; else ghost.textContent = drag.def.emoji;\r\n            }\r\n        } else if(drag.type === 'card') {\r\n            const r = card.getBoundingClientRect();\r\n            const nx = drag.px + ((e.clientX - drag.sx)\/r.width)*100;\r\n            const ny = drag.py + ((e.clientY - drag.sy)\/r.height)*100;\r\n            const i = items.get(drag.id);\r\n            i.x = Math.max(0,Math.min(100,nx))+'%';\r\n            i.y = Math.max(0,Math.min(100,ny))+'%';\r\n            updateEl(card.querySelector('#'+drag.id), i);\r\n            showTb(card.querySelector('#'+drag.id));\r\n        }\r\n    }\r\n\r\n    function onUp(e) {\r\n        window.removeEventListener('pointermove', onMove);\r\n        window.removeEventListener('pointerup', onUp);\r\n        ghost.style.display = 'none';\r\n        \r\n        if(drag && drag.type==='palette' && drag.moved) {\r\n            const r = card.getBoundingClientRect();\r\n            if(e.clientX > r.left && e.clientX < r.right && e.clientY > r.top && e.clientY < r.bottom) {\r\n                const x = ((e.clientX - r.left)\/r.width)*100 + '%';\r\n                const y = ((e.clientY - r.top)\/r.height)*100 + '%';\r\n                const id = addItem(drag.def.id, {x, y});\r\n                select(id); play(600);\r\n            }\r\n        }\r\n        drag = null;\r\n    }\r\n    \r\n    card.onpointerdown = (e) => { if(e.target===card) select(null); };\r\n\r\n    \/\/ SNOW\r\n    const cvs = getEl('ip-snow'), cx = cvs.getContext('2d');\r\n    let flakes = [];\r\n    function resizeSnow() { cvs.width = root.offsetWidth; cvs.height = root.offsetHeight; }\r\n    window.onresize = resizeSnow;\r\n    function loopSnow() {\r\n        cx.clearRect(0,0,cvs.width,cvs.height);\r\n        if(snowOn && flakes.length < 80) flakes.push({x:Math.random()*cvs.width, y:-10, v:Math.random()*2+1, s:Math.random()*3+2});\r\n        flakes.forEach((f, i) => {\r\n            f.y += f.v; f.x += Math.sin(f.y*0.02)*0.5;\r\n            cx.fillStyle = 'rgba(255,255,255,0.7)'; \r\n            cx.beginPath(); cx.arc(f.x,f.y,f.s,0,Math.PI*2); cx.fill();\r\n            if(f.y > cvs.height) { if(snowOn) {f.y=-10; f.x=Math.random()*cvs.width;} else flakes.splice(i,1); }\r\n        });\r\n        requestAnimationFrame(loopSnow);\r\n    }\r\n    function burstSnow() {\r\n        for(let i=0; i<30; i++) flakes.push({x:Math.random()*cvs.width, y:Math.random()*-50, v:Math.random()*4+2, s:Math.random()*4+2});\r\n    }\r\n\r\n    init();\r\n  })();\r\n  <\/script>\r\n<\/div>\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>\n\t\t","protected":false},"excerpt":{"rendered":"<p>GesegneteWEIHNACHTEN Vom christlichen Webdesigner &#8211; Bernd \ud83d\udcf7 Eigenes Bild + Titel Aa Text Motive Emojis Hintergrund \u25b6 Jingle Wackeln \u2744\ufe0f Schnee Karte herunterladen \ud83d\udce5 Reset \u270e \ud83c\udfa8 \uff0b \uff0d \u27f2 \u2715 Hintergrund w\u00e4hlen &times; Eigene Farbe \u27a1 Anwenden Eigenes Foto w\u00e4hlen Neu anfangen? M\u00f6chtest du alle Elemente l\u00f6schen? Nein Ja, l\u00f6schen<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"iawp_total_views":14,"footnotes":""},"class_list":["post-2221","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/christlicher-webdesigner.net\/en\/wp-json\/wp\/v2\/pages\/2221","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/christlicher-webdesigner.net\/en\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/christlicher-webdesigner.net\/en\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/christlicher-webdesigner.net\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/christlicher-webdesigner.net\/en\/wp-json\/wp\/v2\/comments?post=2221"}],"version-history":[{"count":7,"href":"https:\/\/christlicher-webdesigner.net\/en\/wp-json\/wp\/v2\/pages\/2221\/revisions"}],"predecessor-version":[{"id":2228,"href":"https:\/\/christlicher-webdesigner.net\/en\/wp-json\/wp\/v2\/pages\/2221\/revisions\/2228"}],"wp:attachment":[{"href":"https:\/\/christlicher-webdesigner.net\/en\/wp-json\/wp\/v2\/media?parent=2221"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}