{"id":10,"date":"2025-01-09T10:31:46","date_gmt":"2025-01-09T10:31:46","guid":{"rendered":"https:\/\/outmazedtourism.com\/business-card\/?page_id=10"},"modified":"2026-03-12T20:04:23","modified_gmt":"2026-03-12T20:04:23","slug":"aftab","status":"publish","type":"page","link":"https:\/\/outmazedtourism.com\/business-card\/aftab\/","title":{"rendered":""},"content":{"rendered":"\n<p class=\"is-style-text-annotation is-style-text-annotation--1\">Aftab N. | Founder &amp; Group CEO | OutMazed\u00ae Tourism<\/p>\n\n\n\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta property=\"og:title\" content=\"Aftab N. - Business Card\" \/>\n  <meta property=\"og:description\" content=\"Founder &#038; Group CEO - OutMazed\u00ae\" \/>\n  <meta property=\"og:image\" content=\"https:\/\/outmazedtourism.com\/business-card\/wp-content\/uploads\/2025\/02\/Untitled-design-40.png\" \/>\n  <meta property=\"og:type\" content=\"website\" \/>\n\n  <meta charset=\"UTF-8\" \/>\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" \/>\n  <title>Business Card Flipbook<\/title>\n\n  <script src=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/pdf.js\/2.14.305\/pdf.min.js\"><\/script>\n  <script src=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/pdf.js\/2.14.305\/pdf.worker.min.js\"><\/script>\n\n  <audio id=\"flipSound\" src=\"https:\/\/www.soundjay.com\/paper\/sounds\/page-flip-01a.mp3\" preload=\"auto\"><\/audio>\n\n  <style>\n    @import url('https:\/\/fonts.googleapis.com\/css2?family=Poppins:wght@300;400;600&display=swap');\n\n    body {\n      font-family: 'Poppins', sans-serif;\n      background: #f5f5f5;\n      display: flex;\n      flex-direction: column;\n      align-items: center;\n      justify-content: center;\n      min-height: 100svh;\n      margin: 0;\n    }\n\n    .flipbook-wrapper {\n      display: flex;\n      flex-direction: column;\n      align-items: center;\n      justify-content: center;\n      width: 100%;\n    }\n\n    \/* Stable sizing: height derived from width (no vw timing issues) *\/\n    .flipbook-container {\n      position: relative;\n      width: 90vw;\n      max-width: 600px;\n\n      \/* tweak if you want: 1.75 ~ 16:9-ish\n         card itself is ~1.6\u20131.65; we will use COVER anyway *\/\n      aspect-ratio: 1.78;\n      max-height: 350px;\n\n      background: url('https:\/\/www.toptal.com\/designers\/subtlepatterns\/uploads\/marble.png') no-repeat center center;\n      background-size: cover;\n\n      overflow: hidden;\n      box-shadow: 0px 8px 20px rgba(0, 0, 0, 0.2);\n      display: flex;\n      align-items: center;\n      justify-content: center;\n      border-radius: 20px;\n      border: none;\n    }\n\n    .preloader {\n      position: absolute;\n      inset: 0;\n      background: rgba(0, 0, 0, 0.5);\n      display: flex;\n      align-items: center;\n      justify-content: center;\n      border-radius: 20px;\n      z-index: 10;\n    }\n    .preloader.hidden { display: none; }\n\n    .loader {\n      border: 3px solid rgba(255, 255, 255, 0.3);\n      border-radius: 50%;\n      border-top: 3px solid white;\n      width: 30px;\n      height: 30px;\n      animation: spin 1s linear infinite;\n    }\n    @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }\n\n    .arrow {\n      position: absolute;\n      top: 50%;\n      transform: translateY(-50%);\n      background: rgba(255, 255, 255, 0.9);\n      border: none;\n      font-size: 18px;\n      cursor: pointer;\n      padding: 14px;\n      border-radius: 50%;\n      box-shadow: 0px 3px 10px rgba(0, 0, 0, 0.3);\n      transition: all 0.3s ease;\n      color: #333;\n      z-index: 5;\n    }\n    .arrow:hover {\n      background: #0073e6;\n      color: white;\n      transform: translateY(-50%) scale(1.1);\n    }\n    .arrow-left { left: 10px; }\n    .arrow-right { right: 10px; }\n\n    .toolbar {\n      display: flex;\n      gap: 10px;\n      margin-top: 15px;\n      background: rgba(255, 255, 255, 0.95);\n      padding: 12px 18px;\n      border-radius: 20px;\n      box-shadow: 0px 5px 16px rgba(0, 0, 0, 0.15);\n    }\n\n    .toolbar button {\n      background: rgba(0, 0, 0, 0.1);\n      border: none;\n      font-size: 16px;\n      cursor: pointer;\n      padding: 10px 14px;\n      color: #333;\n      border-radius: 12px;\n      transition: all 0.3s ease;\n      display: flex;\n      align-items: center;\n      justify-content: center;\n    }\n    .toolbar button:hover {\n      background: #0073e6;\n      color: white;\n      transform: scale(1.1);\n    }\n\n    canvas { display: block; }\n  <\/style>\n<\/head>\n\n<body>\n  <div class=\"flipbook-wrapper\">\n    <div class=\"flipbook-container\" id=\"flipContainer\">\n      <div class=\"preloader\" id=\"preloader\">\n        <div class=\"loader\"><\/div>\n      <\/div>\n\n      <button class=\"arrow arrow-left\" id=\"btnPrev\">&#9665;<\/button>\n      <canvas id=\"pdf-render\"><\/canvas>\n      <button class=\"arrow arrow-right\" id=\"btnNext\">&#9655;<\/button>\n    <\/div>\n\n    <div class=\"toolbar\">\n      <button id=\"tbPrev\">&#9665;<\/button>\n      <button id=\"tbDownload\">&#8681;<\/button>\n      <button id=\"tbZoomIn\">&#43;<\/button>\n      <button id=\"tbZoomOut\">&#8722;<\/button>\n      <button id=\"tbFullscreen\">&#x26F6;<\/button>\n      <button id=\"tbNext\">&#9655;<\/button>\n    <\/div>\n  <\/div>\n\n  <script>\n    const pdfUrl = \"https:\/\/outmazedtourism.com\/business-card\/wp-content\/uploads\/2026\/03\/Aftab-N.-OutMazed-Tourism-Business-Card.pdf\";\n\n    let pdfDoc = null;\n    let pageNum = 1;\n\n    \/\/ Visual zoom (user)\n    let zoom = 1;\n    const ZOOM_STEP = 0.15;\n    const ZOOM_MIN  = 0.8;\n    const ZOOM_MAX  = 3;\n\n    \/\/ Sharpness multiplier (internal render only)\n    const QUALITY = 2.5;\n\n    const canvas = document.getElementById(\"pdf-render\");\n    const ctx = canvas.getContext(\"2d\", { alpha: true });\n    const preloader = document.getElementById(\"preloader\");\n    const container = document.getElementById(\"flipContainer\");\n\n    let isRendering = false;\n    let pendingPage = null;\n\n    pdfjsLib.GlobalWorkerOptions.workerSrc =\n      \"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/pdf.js\/2.14.305\/pdf.worker.min.js\";\n\n    function queueRender(num) {\n      if (!pdfDoc) return;\n      if (isRendering) { pendingPage = num; return; }\n      renderPage(num);\n    }\n\n    function renderPage(num) {\n      isRendering = true;\n      preloader.classList.remove(\"hidden\");\n\n      pdfDoc.getPage(num).then(page => {\n        const dpr = window.devicePixelRatio || 1;\n\n        const base = page.getViewport({ scale: 1 });\n        const cw = container.clientWidth;\n        const ch = container.clientHeight;\n\n        if (cw < 50 || ch < 50) {\n          isRendering = false;\n          preloader.classList.add(\"hidden\");\n          requestAnimationFrame(() => queueRender(num));\n          return;\n        }\n\n        \/\/ \u2705 COVER fit = fill container (no side gaps), crop if needed\n        const fitCover = Math.max(cw \/ base.width, ch \/ base.height);\n\n        \/\/ Visual scale\n        const displayScale = fitCover * zoom;\n\n        \/\/ Render scale (sharp)\n        const renderScale = displayScale * QUALITY;\n\n        \/\/ Display viewport controls CSS size\n        const displayVp = page.getViewport({ scale: displayScale });\n        canvas.style.width  = Math.floor(displayVp.width) + \"px\";\n        canvas.style.height = Math.floor(displayVp.height) + \"px\";\n\n        \/\/ Center it so cropping is equal on both sides\n        \/\/ (since canvas may be larger than container in cover mode)\n        \/\/ Use translate via flex? container is already flex centered.\n        \/\/ So just ensure canvas is treated as block and centered (done).\n\n        \/\/ Internal pixel buffer for sharpness\n        const renderVp = page.getViewport({ scale: renderScale });\n        canvas.width  = Math.floor(renderVp.width  * dpr);\n        canvas.height = Math.floor(renderVp.height * dpr);\n\n        ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n\n        return page.render({ canvasContext: ctx, viewport: renderVp }).promise;\n      }).then(() => {\n        preloader.classList.add(\"hidden\");\n        isRendering = false;\n\n        if (pendingPage !== null) {\n          const p = pendingPage;\n          pendingPage = null;\n          renderPage(p);\n        }\n      }).catch(err => {\n        console.error(err);\n        preloader.classList.add(\"hidden\");\n        isRendering = false;\n      });\n    }\n\n    function prevPage() {\n      if (!pdfDoc || pageNum <= 1) return;\n      pageNum--;\n      queueRender(pageNum);\n      \/\/ document.getElementById(\"flipSound\").play().catch(()=>{});\n    }\n\n    function nextPage() {\n      if (!pdfDoc || pageNum >= pdfDoc.numPages) return;\n      pageNum++;\n      queueRender(pageNum);\n      \/\/ document.getElementById(\"flipSound\").play().catch(()=>{});\n    }\n\n    function downloadPDF() { window.open(pdfUrl, \"_blank\"); }\n\n    function fullscreen() {\n      const el = document.documentElement;\n      const req = el.requestFullscreen || el.webkitRequestFullscreen || el.mozRequestFullScreen || el.msRequestFullscreen;\n      if (req) req.call(el);\n    }\n\n    function zoomIn()  { zoom = Math.min(ZOOM_MAX, +(zoom + ZOOM_STEP).toFixed(2)); queueRender(pageNum); }\n    function zoomOut() { zoom = Math.max(ZOOM_MIN,  +(zoom - ZOOM_STEP).toFixed(2)); queueRender(pageNum); }\n\n    \/\/ Buttons\n    document.getElementById(\"btnPrev\").addEventListener(\"click\", prevPage);\n    document.getElementById(\"btnNext\").addEventListener(\"click\", nextPage);\n    document.getElementById(\"tbPrev\").addEventListener(\"click\", prevPage);\n    document.getElementById(\"tbNext\").addEventListener(\"click\", nextPage);\n    document.getElementById(\"tbDownload\").addEventListener(\"click\", downloadPDF);\n    document.getElementById(\"tbFullscreen\").addEventListener(\"click\", fullscreen);\n    document.getElementById(\"tbZoomIn\").addEventListener(\"click\", zoomIn);\n    document.getElementById(\"tbZoomOut\").addEventListener(\"click\", zoomOut);\n\n    \/\/ Rerender when container settles (mobile bars \/ first paint)\n    const ro = new ResizeObserver(() => { if (pdfDoc) queueRender(pageNum); });\n    ro.observe(container);\n\n    \/\/ Load PDF\n    pdfjsLib.getDocument(pdfUrl).promise.then(pdf => {\n      pdfDoc = pdf;\n\n      \/\/ First render immediately\n      queueRender(pageNum);\n\n      \/\/ Second render after layout settles (kills first-load mismatch)\n      setTimeout(() => queueRender(pageNum), 200);\n    }).catch(err => console.error(\"PDF load error:\", err));\n  <\/script>\n<\/body>\n<\/html>\n\n\n\n<div id=\"contact-buttons\" style=\"text-align:center\"><\/div>\n\n<script>\n  \/\/ Function to create a vCard URL from a contact object\n  function createVCard(contact) {\n    const vCardData = [\n      \"BEGIN:VCARD\",\n      \"VERSION:3.0\",\n      `N:${contact.lastName || ''};${contact.firstName || ''}`,\n      `FN:${contact.firstName || ''} ${contact.lastName || ''}`,\n      `TITLE:${contact.title || ''}`,\n      `ORG:${contact.organization || ''}`,\n      `ADR:;;${contact.officeAddress || ''}`,\n      ...(contact.phones ? contact.phones.map(p => `TEL;TYPE=${p.type.toUpperCase()}:${p.number}`) : []),\n      ...(contact.email ? [`EMAIL;TYPE=WORK:${contact.email}`] : []),\n      ...(contact.url ? [`URL:${contact.url}`] : []),\n      \"END:VCARD\"\n    ].join(\"\\n\");\n\n    return \"data:text\/vcard;charset=utf-8,\" + encodeURIComponent(vCardData);\n  }\n\n  \/\/ Function to create a save contact button dynamically\n  function createSaveContactButton(contact) {\n    const a = document.createElement(\"a\");\n    a.href = createVCard(contact);\n    a.download = `${contact.firstName}_${contact.lastName}.vcf`;\n    a.innerText = \"Save Contact\";\n\n    \/\/ Inline styles (mobile-friendly)\n    a.style.display = \"inline-block\";\n    a.style.padding = \"12px 20px\";\n    a.style.backgroundColor = \"rgb(58 68 79)\";\n    a.style.color = \"#fff\";\n    a.style.borderRadius = \"8px\";\n    a.style.textDecoration = \"none\";\n    a.style.fontSize = \"16px\";\n    a.style.margin = \"10px 0\";\n\n    return a;\n  }\n\n  \/\/ Example contact\n  const contact = {\n    firstName: \"Aftab\",\n    lastName: \"N.\",\n    title: \"Founder & Group CEO\",\n    organization: \"OutMazed\u00ae Tourism LLC\",\n    officeAddress: \"Office # 2212, 22nd Floor, SIT Tower, Dubai Silicon Oasis, Dubai, United Arab Emirates\",\n    phones: [\n      { type: \"work,voice\", number: \"+97143363259\" },\n    ],\n    email: \"aftab@outmazedtourism.com\",\n    url: \"www.outmazedtourism.com\"\n  };\n\n  \/\/ Append button to the div\n  document.getElementById(\"contact-buttons\").appendChild(createSaveContactButton(contact));\n<\/script>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Aftab N. | Founder &amp; Group CEO | OutMazed\u00ae Tourism Business Card Flipbook &#9665; &#9655; &#9665; &#8681; &#43; &#8722; &#x26F6; &#9655;<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-10","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/outmazedtourism.com\/business-card\/wp-json\/wp\/v2\/pages\/10","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/outmazedtourism.com\/business-card\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/outmazedtourism.com\/business-card\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/outmazedtourism.com\/business-card\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/outmazedtourism.com\/business-card\/wp-json\/wp\/v2\/comments?post=10"}],"version-history":[{"count":112,"href":"https:\/\/outmazedtourism.com\/business-card\/wp-json\/wp\/v2\/pages\/10\/revisions"}],"predecessor-version":[{"id":269,"href":"https:\/\/outmazedtourism.com\/business-card\/wp-json\/wp\/v2\/pages\/10\/revisions\/269"}],"wp:attachment":[{"href":"https:\/\/outmazedtourism.com\/business-card\/wp-json\/wp\/v2\/media?parent=10"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}