{"id":10,"date":"2025-11-06T22:45:36","date_gmt":"2025-11-06T22:45:36","guid":{"rendered":"http:\/\/samirmoustakim.com\/?page_id=10"},"modified":"2026-05-15T20:54:39","modified_gmt":"2026-05-15T20:54:39","slug":"free-digital-tools","status":"publish","type":"page","link":"https:\/\/samirmoustakim.com\/ar\/free-digital-tools\/","title":{"rendered":"\u0623\u062f\u0648\u0627\u062a \u0645\u062c\u0627\u0646\u064a\u0629"},"content":{"rendered":"<style>.kb-row-layout-id10_2fb35c-96 > .kt-row-column-wrap{align-content:start;}:where(.kb-row-layout-id10_2fb35c-96 > .kt-row-column-wrap) > .wp-block-kadence-column{justify-content:start;}.kb-row-layout-id10_2fb35c-96 > .kt-row-column-wrap{column-gap:var(--global-kb-gap-md, 2rem);row-gap:var(--global-kb-gap-md, 2rem);padding-top:var(--global-kb-spacing-sm, 1.5rem);padding-bottom:var(--global-kb-spacing-sm, 1.5rem);grid-template-columns:minmax(0, 1fr);}.kb-row-layout-id10_2fb35c-96 > .kt-row-layout-overlay{opacity:0.30;}@media all and (max-width: 1024px){.kb-row-layout-id10_2fb35c-96 > .kt-row-column-wrap{grid-template-columns:minmax(0, 1fr);}}@media all and (max-width: 767px){.kb-row-layout-id10_2fb35c-96 > .kt-row-column-wrap{grid-template-columns:minmax(0, 1fr);}}<\/style><div class=\"kb-row-layout-wrap kb-row-layout-id10_2fb35c-96 alignnone wp-block-kadence-rowlayout\"><div class=\"kt-row-column-wrap kt-has-1-columns kt-row-layout-equal kt-tab-layout-inherit kt-mobile-layout-row kt-row-valign-top\">\n<style>.kadence-column10_15f71d-a2 > .kt-inside-inner-col,.kadence-column10_15f71d-a2 > .kt-inside-inner-col:before{border-top-left-radius:0px;border-top-right-radius:0px;border-bottom-right-radius:0px;border-bottom-left-radius:0px;}.kadence-column10_15f71d-a2 > .kt-inside-inner-col{column-gap:var(--global-kb-gap-sm, 1rem);}.kadence-column10_15f71d-a2 > .kt-inside-inner-col{flex-direction:column;}.kadence-column10_15f71d-a2 > .kt-inside-inner-col > .aligncenter{width:100%;}.kadence-column10_15f71d-a2 > .kt-inside-inner-col:before{opacity:0.3;}.kadence-column10_15f71d-a2{position:relative;}@media all and (max-width: 1024px){.kadence-column10_15f71d-a2 > .kt-inside-inner-col{flex-direction:column;justify-content:center;}}@media all and (max-width: 767px){.kadence-column10_15f71d-a2 > .kt-inside-inner-col{flex-direction:column;justify-content:center;}}<\/style>\n<div class=\"wp-block-kadence-column kadence-column10_15f71d-a2\"><div class=\"kt-inside-inner-col\"><style>.wp-block-kadence-advancedheading.kt-adv-heading10_1500fd-df, .wp-block-kadence-advancedheading.kt-adv-heading10_1500fd-df[data-kb-block=\"kb-adv-heading10_1500fd-df\"]{text-align:center;font-style:normal;}.wp-block-kadence-advancedheading.kt-adv-heading10_1500fd-df mark.kt-highlight, .wp-block-kadence-advancedheading.kt-adv-heading10_1500fd-df[data-kb-block=\"kb-adv-heading10_1500fd-df\"] mark.kt-highlight{font-style:normal;color:#f76a0c;-webkit-box-decoration-break:clone;box-decoration-break:clone;padding-top:0px;padding-right:0px;padding-bottom:0px;padding-left:0px;}.wp-block-kadence-advancedheading.kt-adv-heading10_1500fd-df img.kb-inline-image, .wp-block-kadence-advancedheading.kt-adv-heading10_1500fd-df[data-kb-block=\"kb-adv-heading10_1500fd-df\"] img.kb-inline-image{width:150px;vertical-align:baseline;}<\/style>\n<h2 class=\"kt-adv-heading10_1500fd-df wp-block-kadence-advancedheading has-theme-palette-1-color has-text-color\" data-kb-block=\"kb-adv-heading10_1500fd-df\">Outils digitaux gratuits pour les professionnels et la productivit\u00e9 quotidienne<\/h2>\n\n\n<style>.wp-block-kadence-advancedheading.kt-adv-heading10_010def-64, .wp-block-kadence-advancedheading.kt-adv-heading10_010def-64[data-kb-block=\"kb-adv-heading10_010def-64\"]{max-width:800px;margin-right:auto;margin-left:auto;text-align:center;font-style:normal;}.wp-block-kadence-advancedheading.kt-adv-heading10_010def-64 mark.kt-highlight, .wp-block-kadence-advancedheading.kt-adv-heading10_010def-64[data-kb-block=\"kb-adv-heading10_010def-64\"] mark.kt-highlight{font-style:normal;color:#f76a0c;-webkit-box-decoration-break:clone;box-decoration-break:clone;padding-top:0px;padding-right:0px;padding-bottom:0px;padding-left:0px;}.wp-block-kadence-advancedheading.kt-adv-heading10_010def-64 img.kb-inline-image, .wp-block-kadence-advancedheading.kt-adv-heading10_010def-64[data-kb-block=\"kb-adv-heading10_010def-64\"] img.kb-inline-image{width:150px;vertical-align:baseline;}<\/style>\n<h5 class=\"kt-adv-heading10_010def-64 wp-block-kadence-advancedheading\" data-kb-block=\"kb-adv-heading10_010def-64\"><strong>Des outils simples, rapides et respectueux de la confidentialit\u00e9, con\u00e7us pour aider les professionnels, entreprises et utilisateurs \u00e0 accomplir leurs t\u00e2ches digitales plus efficacement \u2014 sans complexit\u00e9 inutile ni installation de logiciel.<\/strong><\/h5>\n<\/div><\/div>\n\n<\/div><\/div>\n\n<style>.kb-row-layout-id10_71d919-88 > .kt-row-column-wrap{align-content:start;}:where(.kb-row-layout-id10_71d919-88 > .kt-row-column-wrap) > .wp-block-kadence-column{justify-content:start;}.kb-row-layout-id10_71d919-88 > .kt-row-column-wrap{column-gap:var(--global-kb-gap-md, 2rem);row-gap:var(--global-kb-gap-md, 2rem);padding-top:var(--global-kb-spacing-sm, 1.5rem);padding-bottom:var(--global-kb-spacing-sm, 1.5rem);grid-template-columns:minmax(0, 1fr);}.kb-row-layout-id10_71d919-88 > .kt-row-layout-overlay{opacity:0.30;}@media all and (max-width: 1024px){.kb-row-layout-id10_71d919-88 > .kt-row-column-wrap{grid-template-columns:minmax(0, 1fr);}}@media all and (max-width: 767px){.kb-row-layout-id10_71d919-88 > .kt-row-column-wrap{grid-template-columns:minmax(0, 1fr);}}<\/style><div class=\"kb-row-layout-wrap kb-row-layout-id10_71d919-88 alignnone wp-block-kadence-rowlayout\"><div class=\"kt-row-column-wrap kt-has-1-columns kt-row-layout-equal kt-tab-layout-inherit kt-mobile-layout-row kt-row-valign-top\">\n<style>.kadence-column10_a76299-1c > .kt-inside-inner-col{padding-top:20px;padding-bottom:20px;}.kadence-column10_a76299-1c > .kt-inside-inner-col,.kadence-column10_a76299-1c > .kt-inside-inner-col:before{border-top-left-radius:0px;border-top-right-radius:0px;border-bottom-right-radius:0px;border-bottom-left-radius:0px;}.kadence-column10_a76299-1c > .kt-inside-inner-col{column-gap:var(--global-kb-gap-sm, 1rem);}.kadence-column10_a76299-1c > .kt-inside-inner-col{flex-direction:column;}.kadence-column10_a76299-1c > .kt-inside-inner-col > .aligncenter{width:100%;}.kadence-column10_a76299-1c > .kt-inside-inner-col{background-image:linear-gradient(135deg,rgb(218,235,245) 0%,rgb(154,174,246) 100%);}.kadence-column10_a76299-1c > .kt-inside-inner-col:before{opacity:0.3;}.kadence-column10_a76299-1c{position:relative;}@media all and (max-width: 1024px){.kadence-column10_a76299-1c > .kt-inside-inner-col{flex-direction:column;justify-content:center;}}@media all and (max-width: 767px){.kadence-column10_a76299-1c > .kt-inside-inner-col{flex-direction:column;justify-content:center;}}<\/style>\n<div class=\"wp-block-kadence-column kadence-column10_a76299-1c\"><div class=\"kt-inside-inner-col\">\n<style>\n:root{\n  --sm-primary:#2563EB;\n  --sm-primary-dark:#1D4ED8;\n  --sm-dark:#0F172A;\n  --sm-bg:#F8FAFC;\n  --sm-border:#E2E8F0;\n  --sm-text:#1E293B;\n  --sm-muted:#64748B;\n  --sm-success:#10B981;\n  --sm-radius:18px;\n}\n\n*{\n  box-sizing:border-box;\n}\n\n.sm-vat-tool{\n  max-width:1100px;\n  margin:auto;\n  padding:28px;\n  background:#fff;\n  border:1px solid var(--sm-border);\n  border-radius:24px;\n  box-shadow:0 4px 24px rgba(15,23,42,.05);\n  font-family:Inter,sans-serif;\n}\n\n.sm-vat-header{\n  text-align:center;\n  margin-bottom:32px;\n}\n\n.sm-vat-title{\n  font-size:34px;\n  font-weight:800;\n  color:var(--sm-dark);\n  margin-bottom:12px;\n}\n\n.sm-vat-desc{\n  color:var(--sm-muted);\n  line-height:1.7;\n  max-width:720px;\n  margin:auto;\n}\n\n.sm-vat-grid{\n  display:grid;\n  grid-template-columns:repeat(auto-fit,minmax(300px,1fr));\n  gap:24px;\n}\n\n.sm-card{\n  background:var(--sm-bg);\n  border:1px solid var(--sm-border);\n  border-radius:20px;\n  padding:24px;\n}\n\n.sm-label{\n  display:block;\n  margin-bottom:10px;\n  font-size:14px;\n  font-weight:700;\n  color:var(--sm-dark);\n}\n\n.sm-input,\n.sm-select{\n  width:100%;\n  padding:14px 16px;\n  border-radius:14px;\n  border:1px solid var(--sm-border);\n  font-size:16px;\n  outline:none;\n  transition:.2s ease;\n  background:#fff;\n  color:var(--sm-text);\n}\n\n.sm-input:focus,\n.sm-select:focus{\n  border-color:var(--sm-primary);\n  box-shadow:0 0 0 4px rgba(37,99,235,.1);\n}\n\n.sm-row{\n  margin-bottom:20px;\n}\n\n.sm-buttons{\n  display:flex;\n  gap:12px;\n  flex-wrap:wrap;\n}\n\n.sm-btn{\n  flex:1;\n  min-width:140px;\n  border:none;\n  border-radius:14px;\n  padding:14px 18px;\n  font-weight:700;\n  cursor:pointer;\n  transition:.2s ease;\n  font-size:15px;\n}\n\n.sm-btn-primary{\n  background:var(--sm-primary);\n  color:#fff;\n}\n\n.sm-btn-primary:hover{\n  background:var(--sm-primary-dark);\n}\n\n.sm-btn-secondary{\n  background:#E2E8F0;\n  color:var(--sm-dark);\n}\n\n.sm-btn-secondary:hover{\n  background:#CBD5E1;\n}\n\n.sm-results{\n  display:grid;\n  gap:18px;\n}\n\n.sm-result-box{\n  background:#fff;\n  border:1px solid var(--sm-border);\n  border-radius:18px;\n  padding:20px;\n}\n\n.sm-result-title{\n  font-size:14px;\n  color:var(--sm-muted);\n  margin-bottom:10px;\n}\n\n.sm-result-value{\n  font-size:28px;\n  font-weight:800;\n  color:var(--sm-dark);\n  word-break:break-word;\n}\n\n.sm-highlight{\n  background:#EFF6FF;\n  border-color:#BFDBFE;\n}\n\n.sm-highlight .sm-result-value{\n  color:var(--sm-primary);\n}\n\n.sm-note{\n  margin-top:26px;\n  background:#F8FAFC;\n  border:1px solid var(--sm-border);\n  border-radius:16px;\n  padding:18px;\n  color:var(--sm-muted);\n  font-size:14px;\n  line-height:1.7;\n}\n\n@media(max-width:768px){\n\n  .sm-vat-tool{\n    padding:20px;\n  }\n\n  .sm-vat-title{\n    font-size:28px;\n  }\n\n  .sm-result-value{\n    font-size:24px;\n  }\n\n}\n<\/style>\n\n<div class=\"sm-vat-tool\">\n\n  <div class=\"sm-vat-header\">\n\n    <div class=\"sm-vat-title\">\n      Calculateur TVA\n    <\/div>\n\n    <div class=\"sm-vat-desc\">\n      Calculez instantan\u00e9ment la TVA pour le Maroc, la France et les factures internationales. Convertissez entre HT et TTC avec une pr\u00e9cision professionnelle.\n    <\/div>\n\n  <\/div>\n\n  <div class=\"sm-vat-grid\">\n\n    <div class=\"sm-card\">\n\n      <div class=\"sm-row\">\n\n        <label class=\"sm-label\">\n          Type de calcul\n        <\/label>\n\n        <select\n          id=\"smVatType\"\n          class=\"sm-select\"\n        >\n          <option value=\"ht-to-ttc\">\n            HT \u2192 TTC\n          <\/option>\n\n          <option value=\"ttc-to-ht\">\n            TTC \u2192 HT\n          <\/option>\n\n        <\/select>\n\n      <\/div>\n\n      <div class=\"sm-row\">\n\n        <label class=\"sm-label\">\n          Montant\n        <\/label>\n\n        <input\n          type=\"number\"\n          id=\"smVatAmount\"\n          class=\"sm-input\"\n          placeholder=\"Entrez un montant\"\n          step=\"0.01\"\n        >\n\n      <\/div>\n\n      <div class=\"sm-row\">\n\n        <label class=\"sm-label\">\n          Taux de TVA\n        <\/label>\n\n        <select\n          id=\"smVatRate\"\n          class=\"sm-select\"\n        >\n\n          <option value=\"20\">\n            20%\n          <\/option>\n\n          <option value=\"14\">\n            14%\n          <\/option>\n\n          <option value=\"10\">\n            10%\n          <\/option>\n\n          <option value=\"7\">\n            7%\n          <\/option>\n\n          <option value=\"5.5\">\n            5.5%\n          <\/option>\n\n          <option value=\"2.1\">\n            2.1%\n          <\/option>\n\n        <\/select>\n\n      <\/div>\n\n      <div class=\"sm-row\">\n\n        <label class=\"sm-label\">\n          Devise\n        <\/label>\n\n        <select\n          id=\"smCurrency\"\n          class=\"sm-select\"\n        >\n\n          <option value=\"MAD\">\n            Dirham marocain (MAD)\n          <\/option>\n\n          <option value=\"EUR\">\n            Euro (EUR)\n          <\/option>\n\n          <option value=\"USD\">\n            Dollar am\u00e9ricain (USD)\n          <\/option>\n\n        <\/select>\n\n      <\/div>\n\n      <div class=\"sm-buttons\">\n\n        <button\n          class=\"sm-btn sm-btn-primary\"\n          id=\"smCalculateBtn\"\n        >\n          Calculer la TVA\n        <\/button>\n\n        <button\n          class=\"sm-btn sm-btn-secondary\"\n          id=\"smResetBtn\"\n        >\n          R\u00e9initialiser\n        <\/button>\n\n      <\/div>\n\n    <\/div>\n\n    <div class=\"sm-results\">\n\n      <div class=\"sm-result-box\">\n\n        <div class=\"sm-result-title\">\n          Montant Hors Taxes (HT)\n        <\/div>\n\n        <div\n          class=\"sm-result-value\"\n          id=\"smHT\"\n        >\n          0.00\n        <\/div>\n\n      <\/div>\n\n      <div class=\"sm-result-box sm-highlight\">\n\n        <div class=\"sm-result-title\">\n          Montant de la TVA\n        <\/div>\n\n        <div\n          class=\"sm-result-value\"\n          id=\"smVAT\"\n        >\n          0.00\n        <\/div>\n\n      <\/div>\n\n      <div class=\"sm-result-box\">\n\n        <div class=\"sm-result-title\">\n          Montant Total (TTC)\n        <\/div>\n\n        <div\n          class=\"sm-result-value\"\n          id=\"smTTC\"\n        >\n          0.00\n        <\/div>\n\n      <\/div>\n\n    <\/div>\n\n  <\/div>\n\n  <div class=\"sm-note\">\n    Ce calculateur de TVA prend en charge les taux de TVA les plus courants utilis\u00e9s au Maroc et en France. Id\u00e9al pour les freelances, agences, consultants et entreprises.\n  <\/div>\n\n<\/div>\n\n<script>\n(() => {\n\n  const vatType =\n    document.getElementById('smVatType');\n\n  const amountInput =\n    document.getElementById('smVatAmount');\n\n  const vatRate =\n    document.getElementById('smVatRate');\n\n  const currency =\n    document.getElementById('smCurrency');\n\n  const calculateBtn =\n    document.getElementById('smCalculateBtn');\n\n  const resetBtn =\n    document.getElementById('smResetBtn');\n\n  const htResult =\n    document.getElementById('smHT');\n\n  const vatResult =\n    document.getElementById('smVAT');\n\n  const ttcResult =\n    document.getElementById('smTTC');\n\n  const formatCurrency = value => {\n\n    const selected =\n      currency.value;\n\n    return new Intl.NumberFormat(\n      'fr-FR',\n      {\n        style:'currency',\n        currency:selected,\n        minimumFractionDigits:2\n      }\n    ).format(value);\n\n  };\n\n  const calculateVAT = () => {\n\n    const amount =\n      parseFloat(amountInput.value);\n\n    const rate =\n      parseFloat(vatRate.value);\n\n    if(\n      isNaN(amount) ||\n      amount <= 0\n    ){\n\n      htResult.textContent = '0.00';\n\n      vatResult.textContent = '0.00';\n\n      ttcResult.textContent = '0.00';\n\n      return;\n\n    }\n\n    let ht = 0;\n    let vat = 0;\n    let ttc = 0;\n\n    if(vatType.value === 'ht-to-ttc'){\n\n      ht = amount;\n\n      vat = ht * (rate \/ 100);\n\n      ttc = ht + vat;\n\n    }else{\n\n      ttc = amount;\n\n      ht = ttc \/ (1 + rate \/ 100);\n\n      vat = ttc - ht;\n\n    }\n\n    htResult.textContent =\n      formatCurrency(ht);\n\n    vatResult.textContent =\n      formatCurrency(vat);\n\n    ttcResult.textContent =\n      formatCurrency(ttc);\n\n  };\n\n  const resetCalculator = () => {\n\n    amountInput.value = '';\n\n    vatType.value = 'ht-to-ttc';\n\n    vatRate.value = '20';\n\n    currency.value = 'MAD';\n\n    htResult.textContent = '0.00';\n\n    vatResult.textContent = '0.00';\n\n    ttcResult.textContent = '0.00';\n\n  };\n\n  calculateBtn.addEventListener(\n    'click',\n    calculateVAT\n  );\n\n  resetBtn.addEventListener(\n    'click',\n    resetCalculator\n  );\n\n  amountInput.addEventListener(\n    'input',\n    calculateVAT\n  );\n\n  vatRate.addEventListener(\n    'change',\n    calculateVAT\n  );\n\n  vatType.addEventListener(\n    'change',\n    calculateVAT\n  );\n\n  currency.addEventListener(\n    'change',\n    calculateVAT\n  );\n\n})();\n<\/script>\n<\/div><\/div>\n\n\n<style>.kadence-column10_0e8ae1-e1 > .kt-inside-inner-col,.kadence-column10_0e8ae1-e1 > .kt-inside-inner-col:before{border-top-left-radius:0px;border-top-right-radius:0px;border-bottom-right-radius:0px;border-bottom-left-radius:0px;}.kadence-column10_0e8ae1-e1 > .kt-inside-inner-col{column-gap:var(--global-kb-gap-sm, 1rem);}.kadence-column10_0e8ae1-e1 > .kt-inside-inner-col{flex-direction:column;}.kadence-column10_0e8ae1-e1 > .kt-inside-inner-col > .aligncenter{width:100%;}.kadence-column10_0e8ae1-e1 > .kt-inside-inner-col{background-image:linear-gradient(135deg,rgb(255,248,237) 0%,rgb(245,222,194) 100%);}.kadence-column10_0e8ae1-e1 > .kt-inside-inner-col:before{opacity:0.3;}.kadence-column10_0e8ae1-e1{position:relative;}@media all and (max-width: 1024px){.kadence-column10_0e8ae1-e1 > .kt-inside-inner-col{flex-direction:column;justify-content:center;}}@media all and (max-width: 767px){.kadence-column10_0e8ae1-e1 > .kt-inside-inner-col{flex-direction:column;justify-content:center;}}<\/style>\n<div class=\"wp-block-kadence-column kadence-column10_0e8ae1-e1\"><div class=\"kt-inside-inner-col\">\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n\n<title>Professional Invoice Generator<\/title>\n\n<style>\n\n:root{\n  --primary:#2563EB;\n  --bg:#F8FAFC;\n  --border:#E2E8F0;\n  --text:#0F172A;\n  --muted:#64748B;\n}\n\n*{\n  box-sizing:border-box;\n}\n\nbody{\n  margin:0;\n  font-family:Arial,sans-serif;\n  background:var(--bg);\n  color:var(--text);\n}\n\n.container{\n  max-width:1600px;\n  margin:auto;\n  padding:24px;\n}\n\n.title{\n  text-align:center;\n  margin-bottom:30px;\n}\n\n.title h1{\n  margin:0;\n  font-size:42px;\n}\n\n.title p{\n  color:var(--muted);\n}\n\n.layout{\n  display:grid;\n  grid-template-columns:450px 1fr;\n  gap:24px;\n}\n\n.panel,\n.preview{\n  background:#fff;\n  border:1px solid var(--border);\n  border-radius:24px;\n  padding:24px;\n}\n\n.section{\n  margin-bottom:28px;\n}\n\n.section h3{\n  margin-bottom:16px;\n}\n\n.field{\n  margin-bottom:14px;\n}\n\nlabel{\n  display:block;\n  margin-bottom:8px;\n  font-size:13px;\n  font-weight:bold;\n}\n\ninput,\ntextarea,\nselect{\n  width:100%;\n  padding:14px;\n  border:1px solid var(--border);\n  border-radius:12px;\n  font-size:14px;\n}\n\ntextarea{\n  min-height:80px;\n  resize:vertical;\n}\n\n.grid{\n  display:grid;\n  grid-template-columns:1fr 1fr;\n  gap:12px;\n}\n\n.items{\n  display:flex;\n  flex-direction:column;\n  gap:12px;\n}\n\n.item{\n  border:1px solid var(--border);\n  background:#F8FAFC;\n  border-radius:16px;\n  padding:12px;\n}\n\n.item-grid{\n  display:grid;\n  grid-template-columns:\n    minmax(200px,1fr)\n    70px\n    100px\n    70px;\n  gap:10px;\n  align-items:center;\n}\n\n.remove-btn{\n  background:#FEE2E2;\n  color:#B91C1C;\n  border:none;\n  border-radius:10px;\n  padding:5px;\n  cursor:pointer;\n  font-weight:bold;\n}\n\n.btn{\n  border:none;\n  border-radius:12px;\n  padding:14px;\n  font-weight:bold;\n  cursor:pointer;\n}\n\n.btn-primary{\n  background:var(--primary);\n  color:#fff;\n}\n\n.btn-secondary{\n  background:#E2E8F0;\n}\n\n.actions{\n  display:flex;\n  gap:12px;\n}\n\n.actions .btn{\n  flex:1;\n}\n\n.invoice{\n  max-width:900px;\n  margin:auto;\n}\n\n.invoice-top{\n  display:flex;\n  justify-content:space-between;\n  gap:30px;\n  border-bottom:2px solid var(--border);\n  padding-bottom:24px;\n}\n\n.logo-box{\n  width:120px;\n  height:120px;\n  border:1px dashed var(--border);\n  border-radius:16px;\n  overflow:hidden;\n  display:flex;\n  align-items:center;\n  justify-content:center;\n  background:#F8FAFC;\n}\n\n.logo-box img{\n  width:100%;\n  height:100%;\n  object-fit:contain;\n}\n\n.company h1{\n  margin:14px 0 10px;\n  font-size:36px;\n}\n\n.company p{\n  margin:5px 0;\n  color:var(--muted);\n}\n\n.invoice-meta{\n  text-align:right;\n}\n\n.invoice-meta h2{\n  margin:0;\n  color:var(--primary);\n  font-size:52px;\n}\n\n.status{\n  display:inline-block;\n  margin-top:14px;\n  padding:8px 14px;\n  border-radius:999px;\n  font-size:12px;\n  font-weight:bold;\n}\n\n.paid{\n  background:#DCFCE7;\n  color:#166534;\n}\n\n.pending{\n  background:#FEF3C7;\n  color:#92400E;\n}\n\n.overdue{\n  background:#FEE2E2;\n  color:#991B1B;\n}\n\n.client-box{\n  margin:24px 0;\n  padding:20px;\n  border-radius:16px;\n  background:#F8FAFC;\n  border:1px solid var(--border);\n}\n\n.invoice-table{\n  width:100%;\n  border-collapse:collapse;\n}\n\n.invoice-table th{\n  background:var(--primary);\n  color:#fff;\n  padding:12px;\n  text-align:left;\n}\n\n.invoice-table td{\n  padding:12px;\n  border-bottom:1px solid var(--border);\n}\n\n.totals{\n  width:320px;\n  margin-left:auto;\n  margin-top:20px;\n  background:#F8FAFC;\n  border:1px solid var(--border);\n  border-radius:16px;\n  padding:20px;\n}\n\n.total-line{\n  display:flex;\n  justify-content:space-between;\n  margin-bottom:12px;\n}\n\n.final-total{\n  border-top:2px solid var(--border);\n  padding-top:12px;\n  font-size:24px;\n  font-weight:bold;\n}\n\n.footer{\n  margin-top:30px;\n  text-align:center;\n  color:var(--muted);\n  border-top:1px solid var(--border);\n  padding-top:14px;\n}\n\n@media(max-width:1200px){\n\n  .layout{\n    grid-template-columns:1fr;\n  }\n\n}\n\n<\/style>\n<\/head>\n<body>\n\n<div class=\"container\">\n\n<div class=\"title\">\n<h1>G\u00e9n\u00e9rateur de Facture Professionnelle<\/h1>\n<p>Cr\u00e9ez des factures premium instantan\u00e9ment<\/p>\n<\/div>\n\n<div class=\"layout\">\n\n<div class=\"panel\">\n\n<div class=\"section\">\n\n<h3>Informations de l&rsquo;entreprise<\/h3>\n\n<div class=\"field\">\n<label>Logo de l&rsquo;entreprise<\/label>\n<input type=\"file\" id=\"logoInput\" accept=\"image\/*\">\n<\/div>\n\n<div class=\"field\">\n<label>Nom de l&rsquo;entreprise<\/label>\n<input type=\"text\" id=\"companyName\" value=\"BusinessFes\">\n<\/div>\n\n<div class=\"grid\">\n\n<div class=\"field\">\n<label>Email<\/label>\n<input type=\"email\" id=\"companyEmail\" value=\"samir.mstkm@gmail.com\">\n<\/div>\n\n<div class=\"field\">\n<label>Phone<\/label>\n<input type=\"text\" id=\"companyPhone\" value=\"+212600000000\">\n<\/div>\n\n<\/div>\n\n<div class=\"field\">\n<label>Address<\/label>\n<textarea id=\"companyAddress\">Fes, Morocco<\/textarea>\n<\/div>\n\n<\/div>\n\n<div class=\"section\">\n\n<h3>Informations du client<\/h3>\n\n<div class=\"field\">\n<label>Nom du client<\/label>\n<input type=\"text\" id=\"clientName\" value=\"Client Company\">\n<\/div>\n\n<div class=\"field\">\n<label>Client Address<\/label>\n<textarea id=\"clientAddress\">Casablanca, Morocco<\/textarea>\n<\/div>\n\n<\/div>\n\n<div class=\"section\">\n\n<h3>D\u00e9tails de la facture<\/h3>\n\n<div class=\"grid\">\n\n<div class=\"field\">\n<label>Num\u00e9ro de facture<\/label>\n<input type=\"text\" id=\"invoiceNumber\" value=\"#INV-1001\">\n<\/div>\n\n<div class=\"field\">\n<label>Devise<\/label>\n\n<select id=\"currency\">\n<option>MAD<\/option>\n<option>USD<\/option>\n<option>EUR<\/option>\n<\/select>\n\n<\/div>\n\n<\/div>\n\n<div class=\"field\">\n<label>Statut<\/label>\n\n<select id=\"statusSelect\">\n<option value=\"paid\">PAY\u00c9E<\/option>\n<option value=\"pending\">EN ATTENTE<\/option>\n<option value=\"overdue\">EN RETARD<\/option>\n<\/select>\n\n<\/div>\n\n<\/div>\n\n<div class=\"section\">\n\n<h3>Articles de la facture<\/h3>\n\n<div id=\"itemsContainer\" class=\"items\"><\/div>\n\n<button id=\"addItemBtn\" class=\"btn btn-secondary\" style=\"width:100%;\">\n+ Ajouter un article\n<\/button>\n\n<\/div>\n\n<div class=\"actions\">\n\n<button id=\"downloadBtn\" class=\"btn btn-primary\">\nImprimer \/ PDF\n<\/button>\n\n<button id=\"resetBtn\" class=\"btn btn-secondary\">\nR\u00e9initialiser\n<\/button>\n\n<\/div>\n\n<\/div>\n\n<div class=\"preview\">\n\n<div class=\"invoice\" id=\"invoicePreview\">\n\n<div class=\"invoice-top\">\n\n<div>\n\n<div class=\"logo-box\" id=\"logoPreview\">\nLOGO\n<\/div>\n\n<div class=\"company\">\n\n<h1 id=\"previewCompanyName\">\nBusinessFes\n<\/h1>\n\n<p id=\"previewCompanyEmail\">\nsamir.mstkm@gmail.com\n<\/p>\n\n<p id=\"previewCompanyPhone\">\n+212600000000\n<\/p>\n\n<p id=\"previewCompanyAddress\">\nFes, Morocco\n<\/p>\n\n<\/div>\n\n<\/div>\n\n<div class=\"invoice-meta\">\n\n<h2>FACTURE<\/h2>\n\n<p id=\"previewInvoiceNumber\">\n#INV-1001\n<\/p>\n\n<div id=\"statusBadge\" class=\"status paid\">\nPAY\u00c9E\n<\/div>\n\n<\/div>\n\n<\/div>\n\n<div class=\"client-box\">\n\n<h3>Facturer \u00e0<\/h3>\n\n<p id=\"previewClientName\">\nEntreprise Client\n<\/p>\n\n<p id=\"previewClientAddress\">\nCasablanca, Maroc\n<\/p>\n\n<\/div>\n\n<table class=\"invoice-table\">\n\n<thead>\n<tr>\n<th>Description<\/th>\n<th>Qt\u00e9<\/th>\n<th>Prix<\/th>\n<th>Total<\/th>\n<\/tr>\n<\/thead>\n\n<tbody id=\"invoiceItems\"><\/tbody>\n\n<\/table>\n\n<div class=\"totals\">\n\n<div class=\"total-line\">\n<span>Subtotal<\/span>\n<strong id=\"subtotal\">\n0.00 MAD\n<\/strong>\n<\/div>\n\n<div class=\"total-line\">\n<span>TVA (20%)<\/span>\n<strong id=\"vatAmount\">\n0.00 MAD\n<\/strong>\n<\/div>\n\n<div class=\"total-line final-total\">\n<span>Total<\/span>\n<span id=\"totalAmount\">\n0.00 MAD\n<\/span>\n<\/div>\n\n<\/div>\n\n<div class=\"footer\">\nMerci pour votre confiance.\n<\/div>\n\n<\/div>\n\n<\/div>\n\n<\/div>\n\n<\/div>\n\n<script>\n\nconst itemsContainer =\ndocument.getElementById(\n  'itemsContainer'\n);\n\nconst invoiceItems =\ndocument.getElementById(\n  'invoiceItems'\n);\n\nconst currency =\ndocument.getElementById(\n  'currency'\n);\n\nfunction bindText(\n  inputId,\n  previewId\n){\n\n  const input =\n  document.getElementById(\n    inputId\n  );\n\n  const preview =\n  document.getElementById(\n    previewId\n  );\n\n  input.addEventListener(\n    'input',\n    () => {\n\n      preview.textContent =\n      input.value;\n\n    }\n  );\n\n}\n\nbindText(\n  'companyName',\n  'previewCompanyName'\n);\n\nbindText(\n  'companyEmail',\n  'previewCompanyEmail'\n);\n\nbindText(\n  'companyPhone',\n  'previewCompanyPhone'\n);\n\nbindText(\n  'companyAddress',\n  'previewCompanyAddress'\n);\n\nbindText(\n  'clientName',\n  'previewClientName'\n);\n\nbindText(\n  'clientAddress',\n  'previewClientAddress'\n);\n\nbindText(\n  'invoiceNumber',\n  'previewInvoiceNumber'\n);\n\nfunction money(v){\n\n  return `\n    ${Number(v).toFixed(2)}\n    ${currency.value}\n  `;\n\n}\n\nfunction createItem(\n  desc='',\n  qty=1,\n  price=0\n){\n\n  const item =\n  document.createElement('div');\n\n  item.className='item';\n\n  item.innerHTML=`\n\n  <div class=\"item-grid\">\n\n    <input\n      type=\"text\"\n      class=\"desc\"\n      value=\"${desc}\"\n      placeholder=\"Product\"\n    >\n\n    <input\n      type=\"number\"\n      class=\"qty\"\n      value=\"${qty}\"\n    >\n\n    <input\n      type=\"number\"\n      class=\"price\"\n      value=\"${price}\"\n    >\n\n    <button class=\"remove-btn\">\n      Remove\n    <\/button>\n\n  <\/div>\n\n  `;\n\n  item.querySelectorAll('input')\n  .forEach(input => {\n\n    input.addEventListener(\n      'input',\n      updateInvoice\n    );\n\n  });\n\n  item.querySelector('.remove-btn')\n  .addEventListener(\n    'click',\n    () => {\n\n      item.remove();\n\n      updateInvoice();\n\n    }\n  );\n\n  itemsContainer.appendChild(item);\n\n  updateInvoice();\n\n}\n\nfunction updateInvoice(){\n\n  invoiceItems.innerHTML='';\n\n  let subtotal = 0;\n\n  document.querySelectorAll('.item')\n  .forEach(item => {\n\n    const desc =\n    item.querySelector('.desc').value;\n\n    const qty =\n    Number(\n      item.querySelector('.qty').value\n    );\n\n    const price =\n    Number(\n      item.querySelector('.price').value\n    );\n\n    const total =\n    qty * price;\n\n    subtotal += total;\n\n    const row =\n    document.createElement('tr');\n\n    row.innerHTML=`\n\n    <td>${desc}<\/td>\n    <td>${qty}<\/td>\n    <td>${money(price)}<\/td>\n    <td>${money(total)}<\/td>\n\n    `;\n\n    invoiceItems.appendChild(row);\n\n  });\n\n  const vat =\n  subtotal * 0.2;\n\n  const final =\n  subtotal + vat;\n\n  document.getElementById(\n    'subtotal'\n  ).textContent =\n  money(subtotal);\n\n  document.getElementById(\n    'vatAmount'\n  ).textContent =\n  money(vat);\n\n  document.getElementById(\n    'totalAmount'\n  ).textContent =\n  money(final);\n\n}\n\ncreateItem(\n  'Cr\u00e9ation de site web',\n  1,\n  2500\n);\n\ndocument.getElementById(\n  'addItemBtn'\n).addEventListener(\n  'click',\n  () => {\n\n    createItem();\n\n  }\n);\n\ndocument.getElementById(\n  'logoInput'\n).addEventListener(\n  'change',\n  e => {\n\n    const file =\n    e.target.files[0];\n\n    if(!file) return;\n\n    const reader =\n    new FileReader();\n\n    reader.onload =\n    function(ev){\n\n      document.getElementById(\n        'logoPreview'\n      ).innerHTML = `\n      <img decoding=\"async\" src=\"${ev.target.result}\">\n      `;\n\n    };\n\n    reader.readAsDataURL(file);\n\n  }\n);\n\ndocument.getElementById(\n  'statusSelect'\n).addEventListener(\n  'change',\n  e => {\n\n    const badge =\n    document.getElementById(\n      'statusBadge'\n    );\n\n    badge.className='status';\n\n    if(e.target.value==='paid'){\n\n      badge.classList.add('paid');\n      badge.textContent='PAY\u00c9E';\n\n    }\n\n    if(e.target.value==='pending'){\n\n      badge.classList.add('pending');\n      badge.textContent='EN ATTENTE';\n\n    }\n\n    if(e.target.value==='overdue'){\n\n      badge.classList.add('overdue');\n      badge.textContent='EN RETARD';\n\n    }\n\n  }\n);\n\ndocument.getElementById(\n  'resetBtn'\n).addEventListener(\n  'click',\n  () => {\n\n    location.reload();\n\n  }\n);\n\ndocument.getElementById(\n  'downloadBtn'\n).addEventListener(\n  'click',\n  () => {\n\n    const invoice =\n    document.getElementById(\n      'invoicePreview'\n    ).innerHTML;\n\n    const printWindow =\n    window.open(\n      '',\n      '_blank'\n    );\n\n    printWindow.document.write(`\n\n<!DOCTYPE html>\n\n<html>\n\n<head>\n\n<title>\nInvoice\n<\/title>\n\n<style>\n\nbody{\n  font-family:Arial,sans-serif;\n  padding:40px;\n  color:#111827;\n}\n\n.invoice-top{\n  display:flex;\n  justify-content:space-between;\n  border-bottom:2px solid #E5E7EB;\n  padding-bottom:24px;\n}\n\n.logo-box{\n  width:120px;\n  height:120px;\n}\n\n.logo-box img{\n  width:100%;\n  height:100%;\n  object-fit:contain;\n}\n\n.company h1{\n  margin:16px 0 10px;\n  font-size:36px;\n}\n\n.company p{\n  margin:4px 0;\n  color:#64748B;\n}\n\n.invoice-meta{\n  text-align:right;\n}\n\n.invoice-meta h2{\n  color:#2563EB;\n  font-size:48px;\n}\n\n.client-box{\n  margin:24px 0;\n  padding:20px;\n  background:#F8FAFC;\n  border:1px solid #E2E8F0;\n  border-radius:16px;\n}\n\n.invoice-table{\n  width:100%;\n  border-collapse:collapse;\n}\n\n.invoice-table th{\n  background:#2563EB;\n  color:#fff;\n  padding:12px;\n  text-align:left;\n}\n\n.invoice-table td{\n  padding:12px;\n  border-bottom:1px solid #E5E7EB;\n}\n\n.totals{\n  width:320px;\n  margin-left:auto;\n  margin-top:20px;\n  border:1px solid #E5E7EB;\n  border-radius:16px;\n  padding:20px;\n}\n\n.total-line{\n  display:flex;\n  justify-content:space-between;\n  margin-bottom:10px;\n}\n\n.final-total{\n  border-top:2px solid #E5E7EB;\n  padding-top:12px;\n  font-size:24px;\n  font-weight:bold;\n}\n\n.footer{\n  margin-top:30px;\n  text-align:center;\n  color:#64748B;\n}\n\n.status{\n  display:inline-block;\n  margin-top:14px;\n  padding:8px 14px;\n  border-radius:999px;\n  font-size:12px;\n  font-weight:bold;\n}\n\n.paid{\n  background:#DCFCE7;\n  color:#166534;\n}\n\n.pending{\n  background:#FEF3C7;\n  color:#92400E;\n}\n\n.overdue{\n  background:#FEE2E2;\n  color:#991B1B;\n}\n\n<\/style>\n\n<\/head>\n\n<body>\n\n${invoice}\n\n<\/body>\n\n<\/html>\n\n    `);\n\n    printWindow.document.close();\n\n    setTimeout(() => {\n\n      printWindow.print();\n\n    },500);\n\n  }\n);\n\n<\/script>\n\n<\/body>\n<\/html>\n\n\n\n\n<\/div><\/div>\n\n<\/div><\/div>\n\n<style>.kb-row-layout-id10_4f0539-e7 > .kt-row-column-wrap{align-content:start;}:where(.kb-row-layout-id10_4f0539-e7 > .kt-row-column-wrap) > .wp-block-kadence-column{justify-content:start;}.kb-row-layout-id10_4f0539-e7 > .kt-row-column-wrap{column-gap:var(--global-kb-gap-md, 2rem);row-gap:var(--global-kb-gap-md, 2rem);padding-top:var(--global-kb-spacing-sm, 1.5rem);padding-bottom:var(--global-kb-spacing-sm, 1.5rem);grid-template-columns:minmax(0, 1fr);}.kb-row-layout-id10_4f0539-e7 > .kt-row-layout-overlay{opacity:0.30;}@media all and (max-width: 1024px){.kb-row-layout-id10_4f0539-e7 > .kt-row-column-wrap{grid-template-columns:minmax(0, 1fr);}}@media all and (max-width: 767px){.kb-row-layout-id10_4f0539-e7 > .kt-row-column-wrap{grid-template-columns:minmax(0, 1fr);}}<\/style><div class=\"kb-row-layout-wrap kb-row-layout-id10_4f0539-e7 alignnone wp-block-kadence-rowlayout\"><div class=\"kt-row-column-wrap kt-has-1-columns kt-row-layout-equal kt-tab-layout-inherit kt-mobile-layout-row kt-row-valign-top\">\n<style>.kadence-column10_02df35-81 > .kt-inside-inner-col{padding-top:20px;padding-bottom:20px;}.kadence-column10_02df35-81 > .kt-inside-inner-col,.kadence-column10_02df35-81 > .kt-inside-inner-col:before{border-top-left-radius:0px;border-top-right-radius:0px;border-bottom-right-radius:0px;border-bottom-left-radius:0px;}.kadence-column10_02df35-81 > .kt-inside-inner-col{column-gap:var(--global-kb-gap-sm, 1rem);}.kadence-column10_02df35-81 > .kt-inside-inner-col{flex-direction:column;}.kadence-column10_02df35-81 > .kt-inside-inner-col > .aligncenter{width:100%;}.kadence-column10_02df35-81 > .kt-inside-inner-col{background-image:linear-gradient(135deg,rgb(218,235,245) 0%,rgb(154,174,246) 100%);}.kadence-column10_02df35-81 > .kt-inside-inner-col:before{opacity:0.3;}.kadence-column10_02df35-81{position:relative;}@media all and (max-width: 1024px){.kadence-column10_02df35-81 > .kt-inside-inner-col{flex-direction:column;justify-content:center;}}@media all and (max-width: 767px){.kadence-column10_02df35-81 > .kt-inside-inner-col{flex-direction:column;justify-content:center;}}<\/style>\n<div class=\"wp-block-kadence-column kadence-column10_02df35-81\"><div class=\"kt-inside-inner-col\">\n<style>\n:root{\n  --sm-primary:#2563EB;\n  --sm-dark:#0F172A;\n  --sm-bg:#F8FAFC;\n  --sm-border:#E2E8F0;\n  --sm-text:#1E293B;\n  --sm-muted:#64748B;\n  --sm-radius:16px;\n}\n\n*{\n  box-sizing:border-box;\n}\n\n.sm-tool-card{\n  background:#fff;\n  border:1px solid var(--sm-border);\n  border-radius:var(--sm-radius);\n  padding:24px;\n  box-shadow:0 4px 20px rgba(15,23,42,.04);\n  max-width:720px;\n  margin:auto;\n  font-family:Inter,sans-serif;\n}\n\n.sm-tool-header{\n  text-align:center;\n  margin-bottom:24px;\n}\n\n.sm-tool-title{\n  font-size:28px;\n  font-weight:700;\n  color:var(--sm-dark);\n  margin:0 0 10px;\n}\n\n.sm-tool-desc{\n  color:var(--sm-muted);\n  font-size:15px;\n  line-height:1.6;\n  margin:0;\n}\n\n.sm-social-grid{\n  display:grid;\n  grid-template-columns:repeat(auto-fit,minmax(52px,1fr));\n  gap:12px;\n  margin-bottom:24px;\n}\n\n.sm-social-item{\n  border:2px solid transparent;\n  background:#fff;\n  border-radius:14px;\n  padding:8px;\n  cursor:pointer;\n  transition:.2s ease;\n  display:flex;\n  align-items:center;\n  justify-content:center;\n}\n\n.sm-social-item:hover{\n  border-color:#BFDBFE;\n  transform:translateY(-2px);\n}\n\n.sm-social-item.active{\n  border-color:var(--sm-primary);\n  background:#EFF6FF;\n}\n\n.sm-social-item img{\n  width:32px;\n  height:32px;\n  object-fit:contain;\n}\n\n.sm-input{\n  width:100%;\n  padding:14px 16px;\n  border:1px solid var(--sm-border);\n  border-radius:12px;\n  font-size:15px;\n  outline:none;\n  transition:.2s ease;\n  margin-bottom:16px;\n}\n\n.sm-input:focus{\n  border-color:var(--sm-primary);\n  box-shadow:0 0 0 4px rgba(37,99,235,.1);\n}\n\n.sm-actions{\n  display:flex;\n  gap:12px;\n  flex-wrap:wrap;\n  margin-bottom:24px;\n}\n\n.sm-btn{\n  flex:1;\n  min-width:140px;\n  border:none;\n  border-radius:12px;\n  padding:14px 18px;\n  font-weight:600;\n  cursor:pointer;\n  transition:.2s ease;\n}\n\n.sm-btn-primary{\n  background:var(--sm-primary);\n  color:#fff;\n}\n\n.sm-btn-primary:hover{\n  background:#1D4ED8;\n}\n\n.sm-btn-secondary{\n  background:#fff;\n  border:1px solid var(--sm-border);\n  color:var(--sm-dark);\n}\n\n.sm-btn-secondary:hover{\n  background:#F1F5F9;\n}\n\n.sm-preview{\n  text-align:center;\n  margin-bottom:20px;\n}\n\n.sm-preview canvas{\n  max-width:100%;\n  background:#fff;\n  border-radius:14px;\n  padding:12px;\n  border:1px solid var(--sm-border);\n}\n\n.sm-logo-preview{\n  display:flex;\n  justify-content:center;\n  margin-bottom:18px;\n}\n\n.sm-logo-preview img{\n  width:70px;\n  height:70px;\n  object-fit:contain;\n  border-radius:12px;\n  border:1px solid var(--sm-border);\n  padding:6px;\n  background:#fff;\n}\n\n.sm-upload{\n  text-align:center;\n  margin-top:20px;\n}\n\n.sm-upload-label{\n  display:inline-block;\n  padding:12px 18px;\n  border:1px dashed var(--sm-border);\n  border-radius:12px;\n  cursor:pointer;\n  color:var(--sm-muted);\n  background:#F8FAFC;\n  transition:.2s ease;\n}\n\n.sm-upload-label:hover{\n  border-color:var(--sm-primary);\n  color:var(--sm-primary);\n}\n\n.sm-upload input{\n  display:none;\n}\n\n.sm-status{\n  margin-top:14px;\n  font-size:14px;\n  color:var(--sm-muted);\n  text-align:center;\n}\n\n@media(max-width:640px){\n\n  .sm-tool-card{\n    padding:20px;\n  }\n\n  .sm-tool-title{\n    font-size:22px;\n  }\n\n  .sm-actions{\n    flex-direction:column;\n  }\n\n  .sm-btn{\n    width:100%;\n  }\n\n}\n<\/style>\n\n<div class=\"sm-tool-card\">\n\n  <div class=\"sm-tool-header\">\n    <h2 class=\"sm-tool-title\">QR Code Generator<\/h2>\n    <p class=\"sm-tool-desc\">\n      Convert any link or text into a downloadable QR code with optional logo support.\n    <\/p>\n  <\/div>\n\n  <div class=\"sm-social-grid\" id=\"smSocialGrid\">\n\n    <div class=\"sm-social-item\">\n      <img decoding=\"async\" src=\"https:\/\/samirmoustakim.com\/wp-content\/uploads\/2025\/11\/facebook-logo.png\">\n    <\/div>\n\n    <div class=\"sm-social-item\">\n      <img decoding=\"async\" src=\"https:\/\/samirmoustakim.com\/wp-content\/uploads\/2025\/11\/tiktok-icon.png\">\n    <\/div>\n\n    <div class=\"sm-social-item\">\n      <img decoding=\"async\" src=\"https:\/\/samirmoustakim.com\/wp-content\/uploads\/2025\/11\/whatsapp-icon.png\">\n    <\/div>\n\n    <div class=\"sm-social-item\">\n      <img decoding=\"async\" src=\"https:\/\/samirmoustakim.com\/wp-content\/uploads\/2025\/11\/shopify-logo.png\">\n    <\/div>\n\n    <div class=\"sm-social-item\">\n      <img decoding=\"async\" src=\"https:\/\/samirmoustakim.com\/wp-content\/uploads\/2025\/11\/linkedin-icon.png\">\n    <\/div>\n\n    <div class=\"sm-social-item\">\n      <img decoding=\"async\" src=\"https:\/\/samirmoustakim.com\/wp-content\/uploads\/2025\/11\/instagram-logo.png\">\n    <\/div>\n\n    <div class=\"sm-social-item\">\n      <img decoding=\"async\" src=\"https:\/\/samirmoustakim.com\/wp-content\/uploads\/2025\/11\/youtube-logo.png\">\n    <\/div>\n\n    <div class=\"sm-social-item\">\n      <img decoding=\"async\" src=\"https:\/\/samirmoustakim.com\/wp-content\/uploads\/2025\/11\/website-logo.png\">\n    <\/div>\n\n  <\/div>\n\n  <input \n    type=\"text\" \n    id=\"smQrInput\" \n    class=\"sm-input\"\n    placeholder=\"Enter URL or text...\"\n  >\n\n  <div class=\"sm-actions\">\n    <button class=\"sm-btn sm-btn-primary\" id=\"smGenerateBtn\">\n      Generate QR\n    <\/button>\n\n    <button class=\"sm-btn sm-btn-secondary\" id=\"smClearBtn\">\n      Clear\n    <\/button>\n  <\/div>\n\n  <div class=\"sm-logo-preview\" id=\"smLogoPreview\"><\/div>\n\n  <div class=\"sm-preview\" id=\"smQrPreview\"><\/div>\n\n  <div class=\"sm-actions\">\n    <button \n      class=\"sm-btn sm-btn-primary\"\n      id=\"smDownloadBtn\"\n      style=\"display:none;\"\n    >\n      Download PNG\n    <\/button>\n  <\/div>\n\n  <div class=\"sm-upload\">\n    <label class=\"sm-upload-label\">\n      Upload Custom Logo\n      <input type=\"file\" id=\"smUploadLogo\" accept=\"image\/*\">\n    <\/label>\n  <\/div>\n\n  <div class=\"sm-status\" id=\"smStatus\"><\/div>\n\n<\/div>\n\n<script src=\"https:\/\/cdn.jsdelivr.net\/npm\/qrious@4.0.2\/dist\/qrious.min.js\"><\/script>\n\n<script>\n(() => {\n\n  let selectedLogo = null;\n  let finalCanvas = null;\n\n  const socialItems = document.querySelectorAll('.sm-social-item');\n  const input = document.getElementById('smQrInput');\n  const generateBtn = document.getElementById('smGenerateBtn');\n  const clearBtn = document.getElementById('smClearBtn');\n  const preview = document.getElementById('smQrPreview');\n  const downloadBtn = document.getElementById('smDownloadBtn');\n  const uploadInput = document.getElementById('smUploadLogo');\n  const logoPreview = document.getElementById('smLogoPreview');\n  const status = document.getElementById('smStatus');\n\n  const setStatus = (msg, error = false) => {\n    status.textContent = msg;\n    status.style.color = error ? '#DC2626' : '#64748B';\n  };\n\n  const loadImage = src => 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  socialItems.forEach(item => {\n\n    item.addEventListener('click', () => {\n\n      socialItems.forEach(el => el.classList.remove('active'));\n\n      item.classList.add('active');\n\n      selectedLogo = item.querySelector('img').src;\n\n      logoPreview.innerHTML = `\n        <img decoding=\"async\" src=\"${selectedLogo}\" alt=\"Logo\">\n      `;\n\n      setStatus('Logo selected');\n\n    });\n\n  });\n\n  uploadInput.addEventListener('change', e => {\n\n    const file = e.target.files[0];\n\n    if (!file) return;\n\n    const reader = new FileReader();\n\n    reader.onload = event => {\n\n      selectedLogo = event.target.result;\n\n      socialItems.forEach(el => el.classList.remove('active'));\n\n      logoPreview.innerHTML = `\n        <img decoding=\"async\" src=\"${selectedLogo}\" alt=\"Uploaded Logo\">\n      `;\n\n      setStatus('Custom logo uploaded');\n\n    };\n\n    reader.readAsDataURL(file);\n\n  });\n\n  generateBtn.addEventListener('click', async () => {\n\n    const value = input.value.trim();\n\n    if (!value) {\n      setStatus('Please enter text or URL', true);\n      return;\n    }\n\n    preview.innerHTML = '';\n    downloadBtn.style.display = 'none';\n\n    const qr = new QRious({\n      value,\n      size: 400,\n      level: 'H',\n      background: '#fff',\n      foreground: '#000'\n    });\n\n    const canvas = document.createElement('canvas');\n    const ctx = canvas.getContext('2d');\n\n    canvas.width = qr.canvas.width;\n    canvas.height = qr.canvas.height;\n\n    ctx.drawImage(qr.canvas, 0, 0);\n\n    if (selectedLogo) {\n\n      try {\n\n        const logo = await loadImage(selectedLogo);\n\n        const size = canvas.width * 0.18;\n        const x = (canvas.width - size) \/ 2;\n        const y = (canvas.height - size) \/ 2;\n\n        ctx.fillStyle = '#fff';\n        ctx.beginPath();\n        ctx.roundRect(x - 8, y - 8, size + 16, size + 16, 12);\n        ctx.fill();\n\n        ctx.drawImage(logo, x, y, size, size);\n\n      } catch(err) {}\n\n    }\n\n    preview.appendChild(canvas);\n\n    finalCanvas = canvas;\n\n    downloadBtn.style.display = 'block';\n\n    setStatus('QR generated successfully');\n\n  });\n\n  clearBtn.addEventListener('click', () => {\n\n    input.value = '';\n\n    preview.innerHTML = '';\n\n    logoPreview.innerHTML = '';\n\n    selectedLogo = null;\n\n    finalCanvas = null;\n\n    socialItems.forEach(el => el.classList.remove('active'));\n\n    uploadInput.value = '';\n\n    downloadBtn.style.display = 'none';\n\n    setStatus('');\n\n  });\n\n  downloadBtn.addEventListener('click', () => {\n\n    if (!finalCanvas) return;\n\n    const link = document.createElement('a');\n\n    link.href = finalCanvas.toDataURL('image\/png');\n\n    link.download = 'qr-code.png';\n\n    link.click();\n\n  });\n\n})();\n<\/script>\n<\/div><\/div>\n\n\n<style>.kadence-column10_bf5a48-69 > .kt-inside-inner-col{padding-top:20px;padding-bottom:20px;}.kadence-column10_bf5a48-69 > .kt-inside-inner-col,.kadence-column10_bf5a48-69 > .kt-inside-inner-col:before{border-top-left-radius:0px;border-top-right-radius:0px;border-bottom-right-radius:0px;border-bottom-left-radius:0px;}.kadence-column10_bf5a48-69 > .kt-inside-inner-col{column-gap:var(--global-kb-gap-sm, 1rem);}.kadence-column10_bf5a48-69 > .kt-inside-inner-col{flex-direction:column;}.kadence-column10_bf5a48-69 > .kt-inside-inner-col > .aligncenter{width:100%;}.kadence-column10_bf5a48-69 > .kt-inside-inner-col{background-image:linear-gradient(135deg,rgb(255,248,237) 0%,rgb(245,222,194) 100%);}.kadence-column10_bf5a48-69 > .kt-inside-inner-col:before{opacity:0.3;}.kadence-column10_bf5a48-69{position:relative;}@media all and (max-width: 1024px){.kadence-column10_bf5a48-69 > .kt-inside-inner-col{flex-direction:column;justify-content:center;}}@media all and (max-width: 767px){.kadence-column10_bf5a48-69 > .kt-inside-inner-col{flex-direction:column;justify-content:center;}}<\/style>\n<div class=\"wp-block-kadence-column kadence-column10_bf5a48-69\"><div class=\"kt-inside-inner-col\">\n<style>\n:root{\n  --sm-primary:#2563EB;\n  --sm-dark:#0F172A;\n  --sm-bg:#F8FAFC;\n  --sm-border:#E2E8F0;\n  --sm-text:#1E293B;\n  --sm-muted:#64748B;\n  --sm-danger:#DC2626;\n  --sm-radius:16px;\n}\n\n*{\n  box-sizing:border-box;\n}\n\n.sm-tool-card{\n  background:#fff;\n  border:1px solid var(--sm-border);\n  border-radius:var(--sm-radius);\n  padding:24px;\n  box-shadow:0 4px 20px rgba(15,23,42,.04);\n  max-width:1100px;\n  margin:auto;\n  font-family:Inter,sans-serif;\n}\n\n.sm-tool-header{\n  text-align:center;\n  margin-bottom:24px;\n}\n\n.sm-tool-title{\n  font-size:28px;\n  font-weight:700;\n  color:var(--sm-dark);\n  margin:0 0 10px;\n}\n\n.sm-tool-desc{\n  color:var(--sm-muted);\n  font-size:15px;\n  line-height:1.6;\n  margin:0;\n}\n\n.sm-upload{\n  border:2px dashed #BFDBFE;\n  border-radius:16px;\n  padding:32px 20px;\n  text-align:center;\n  background:#F8FAFC;\n  transition:.2s ease;\n}\n\n.sm-upload.dragover{\n  border-color:var(--sm-primary);\n  background:#EFF6FF;\n}\n\n.sm-upload-icon{\n  font-size:42px;\n  margin-bottom:12px;\n}\n\n.sm-upload-title{\n  font-size:18px;\n  font-weight:600;\n  color:var(--sm-dark);\n  margin-bottom:8px;\n}\n\n.sm-upload-subtitle{\n  color:var(--sm-muted);\n  font-size:14px;\n  margin-bottom:18px;\n}\n\n.sm-hidden{\n  display:none;\n}\n\n.sm-actions{\n  display:flex;\n  gap:12px;\n  flex-wrap:wrap;\n  margin-top:20px;\n}\n\n.sm-btn{\n  flex:1;\n  min-width:150px;\n  border:none;\n  border-radius:12px;\n  padding:14px 18px;\n  font-weight:600;\n  cursor:pointer;\n  transition:.2s ease;\n}\n\n.sm-btn-primary{\n  background:var(--sm-primary);\n  color:#fff;\n}\n\n.sm-btn-primary:hover{\n  background:#1D4ED8;\n}\n\n.sm-btn-secondary{\n  background:#fff;\n  border:1px solid var(--sm-border);\n  color:var(--sm-dark);\n}\n\n.sm-btn-secondary:hover{\n  background:#F1F5F9;\n}\n\n.sm-btn:disabled{\n  opacity:.5;\n  cursor:not-allowed;\n}\n\n.sm-progress{\n  height:10px;\n  background:#E2E8F0;\n  border-radius:999px;\n  overflow:hidden;\n  margin-top:18px;\n  display:none;\n}\n\n.sm-progress-bar{\n  height:100%;\n  width:0%;\n  background:var(--sm-primary);\n  transition:.25s ease;\n}\n\n.sm-warning{\n  margin-top:16px;\n  color:var(--sm-danger);\n  font-size:14px;\n  font-weight:600;\n  text-align:center;\n  display:none;\n}\n\n.sm-grid{\n  display:grid;\n  grid-template-columns:repeat(auto-fit,minmax(240px,1fr));\n  gap:18px;\n  margin-top:28px;\n}\n\n.sm-image-card{\n  background:#fff;\n  border:1px solid var(--sm-border);\n  border-radius:16px;\n  padding:14px;\n}\n\n.sm-thumb{\n  height:180px;\n  border-radius:12px;\n  overflow:hidden;\n  background:#F8FAFC;\n  border:1px solid var(--sm-border);\n  display:flex;\n  align-items:center;\n  justify-content:center;\n}\n\n.sm-thumb img{\n  width:100%;\n  height:100%;\n  object-fit:contain;\n}\n\n.sm-file-name{\n  margin-top:12px;\n  font-size:13px;\n  color:var(--sm-muted);\n  word-break:break-word;\n}\n\n.sm-metrics{\n  margin-top:12px;\n  display:flex;\n  flex-direction:column;\n  gap:6px;\n  font-size:13px;\n  color:var(--sm-text);\n}\n\n.sm-card-actions{\n  display:flex;\n  gap:8px;\n  flex-wrap:wrap;\n  margin-top:14px;\n}\n\n.sm-small-btn{\n  flex:1;\n  border:1px solid #CBD5E1;\n  background:#F8FAFC;\n  color:var(--sm-dark);\n  border-radius:10px;\n  padding:10px;\n  cursor:pointer;\n  font-size:13px;\n  font-weight:600;\n  transition:.2s ease;\n}\n\n.sm-small-btn:hover{\n  background:#E2E8F0;\n}\n\n.sm-small-btn:disabled{\n  opacity:.5;\n  cursor:not-allowed;\n}\n\n.sm-note{\n  margin-top:24px;\n  padding:14px;\n  border-radius:12px;\n  background:#F8FAFC;\n  border:1px solid var(--sm-border);\n  color:var(--sm-muted);\n  font-size:14px;\n}\n\n@media(max-width:640px){\n\n  .sm-tool-card{\n    padding:20px;\n  }\n\n  .sm-tool-title{\n    font-size:24px;\n  }\n\n  .sm-actions{\n    flex-direction:column;\n  }\n\n  .sm-btn{\n    width:100%;\n  }\n\n}\n<\/style>\n\n<div class=\"sm-tool-card\">\n\n  <div class=\"sm-tool-header\">\n\n    <h2 class=\"sm-tool-title\">\n      Image Compressor\n    <\/h2>\n\n    <p class=\"sm-tool-desc\">\n      Compress JPG, PNG and WebP images directly in your browser.\n    <\/p>\n\n  <\/div>\n\n  <div class=\"sm-upload\" id=\"smCompressUploadArea\">\n\n    <div class=\"sm-upload-icon\">\n      \ud83d\udcc1\n    <\/div>\n\n    <div class=\"sm-upload-title\">\n      Drag &#038; Drop Images\n    <\/div>\n\n    <div class=\"sm-upload-subtitle\">\n      JPG, PNG, WEBP supported\n    <\/div>\n\n    <button\n      type=\"button\"\n      class=\"sm-btn sm-btn-primary\"\n      id=\"smCompressChooseBtn\"\n    >\n      Choose Files\n    <\/button>\n\n    <input\n      type=\"file\"\n      id=\"smCompressFileInput\"\n      class=\"sm-hidden\"\n      accept=\"image\/*\"\n      multiple\n    >\n\n  <\/div>\n\n  <div\n    class=\"sm-warning\"\n    id=\"smCompressWarning\"\n  >\n    PNG files may not compress significantly.\n  <\/div>\n\n  <div class=\"sm-actions\">\n\n    <button\n      class=\"sm-btn sm-btn-primary\"\n      id=\"smCompressAllBtn\"\n    >\n      Compress All\n    <\/button>\n\n    <button\n      class=\"sm-btn sm-btn-secondary\"\n      id=\"smCompressClearBtn\"\n    >\n      Clear All\n    <\/button>\n\n    <button\n      class=\"sm-btn sm-btn-primary\"\n      id=\"smCompressZipBtn\"\n      disabled\n    >\n      Download ZIP\n    <\/button>\n\n  <\/div>\n\n  <div\n    class=\"sm-progress\"\n    id=\"smCompressProgress\"\n  >\n\n    <div\n      class=\"sm-progress-bar\"\n      id=\"smCompressProgressBar\"\n    ><\/div>\n\n  <\/div>\n\n  <div\n    class=\"sm-grid\"\n    id=\"smCompressGrid\"\n  ><\/div>\n\n  <div class=\"sm-note\">\n    All image processing happens locally in your browser for maximum privacy and speed.\n  <\/div>\n\n<\/div>\n\n<script src=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/jszip\/3.10.1\/jszip.min.js\"><\/script>\n\n<script>\n(() => {\n\n  const uploadArea =\n    document.getElementById('smCompressUploadArea');\n\n  const fileInput =\n    document.getElementById('smCompressFileInput');\n\n  const chooseBtn =\n    document.getElementById('smCompressChooseBtn');\n\n  const compressAllBtn =\n    document.getElementById('smCompressAllBtn');\n\n  const clearAllBtn =\n    document.getElementById('smCompressClearBtn');\n\n  const downloadZipBtn =\n    document.getElementById('smCompressZipBtn');\n\n  const grid =\n    document.getElementById('smCompressGrid');\n\n  const warning =\n    document.getElementById('smCompressWarning');\n\n  const progress =\n    document.getElementById('smCompressProgress');\n\n  const progressBar =\n    document.getElementById('smCompressProgressBar');\n\n  let files = [];\n\n  const formatBytes = bytes => {\n\n    if(bytes < 1024){\n      return bytes + ' B';\n    }\n\n    if(bytes < 1024 * 1024){\n      return (bytes \/ 1024).toFixed(1) + ' KB';\n    }\n\n    return (bytes \/ (1024 * 1024)).toFixed(2) + ' MB';\n\n  };\n\n  const updateProgress = value => {\n\n    if(value <= 0){\n\n      progress.style.display = 'none';\n\n      progressBar.style.width = '0%';\n\n      return;\n\n    }\n\n    progress.style.display = 'block';\n\n    progressBar.style.width = value + '%';\n\n  };\n\n  const revokeURLs = item => {\n\n    if(item.url){\n      URL.revokeObjectURL(item.url);\n    }\n\n    if(item.compressedUrl){\n      URL.revokeObjectURL(item.compressedUrl);\n    }\n\n  };\n\n  const updateWarning = () => {\n\n    const hasPNG = files.some(\n      item => item.file.type === 'image\/png'\n    );\n\n    warning.style.display =\n      hasPNG ? 'block' : 'none';\n\n  };\n\n  const render = () => {\n\n    grid.innerHTML = '';\n\n    files.forEach(item => {\n\n      const card =\n        document.createElement('div');\n\n      card.className = 'sm-image-card';\n\n      card.innerHTML = `\n        <div class=\"sm-thumb\">\n          <img decoding=\"async\" src=\"${item.url}\" alt=\"\">\n        <\/div>\n\n        <div class=\"sm-file-name\">\n          ${item.file.name}\n        <\/div>\n\n        <div class=\"sm-metrics\">\n          <div><strong>Before:<\/strong> ${formatBytes(item.before)}<\/div>\n\n          <div><strong>After:<\/strong> ${\n            item.after\n              ? formatBytes(item.after)\n              : '\u2014'\n          }<\/div>\n\n          <div><strong>Saved:<\/strong> ${\n            item.after\n              ? (100 - Math.round(item.after * 100 \/ item.before)) + '%'\n              : '\u2014'\n          }<\/div>\n        <\/div>\n\n        <div class=\"sm-card-actions\">\n\n          <button class=\"sm-small-btn compress-btn\">\n            Compress\n          <\/button>\n\n          <button\n            class=\"sm-small-btn download-btn\"\n            ${!item.compressedUrl ? 'disabled' : ''}\n          >\n            Download\n          <\/button>\n\n          <button class=\"sm-small-btn remove-btn\">\n            Remove\n          <\/button>\n\n        <\/div>\n      `;\n\n      card.querySelector('.compress-btn')\n        .addEventListener('click', () => {\n          compressOne(item.id);\n        });\n\n      card.querySelector('.download-btn')\n        .addEventListener('click', () => {\n\n          if(!item.compressedUrl) return;\n\n          const link =\n            document.createElement('a');\n\n          link.href = item.compressedUrl;\n\n          link.download = item.file.name;\n\n          link.click();\n\n        });\n\n      card.querySelector('.remove-btn')\n        .addEventListener('click', () => {\n\n          revokeURLs(item);\n\n          files = files.filter(\n            file => file.id !== item.id\n          );\n\n          render();\n\n          updateWarning();\n\n        });\n\n      grid.appendChild(card);\n\n    });\n\n    downloadZipBtn.disabled =\n      !files.some(file => file.blob);\n\n  };\n\n  const compressImage = (\n    file,\n    quality = .75\n  ) => {\n\n    return new Promise(resolve => {\n\n      const img = new Image();\n\n      const url =\n        URL.createObjectURL(file);\n\n      img.onload = () => {\n\n        const canvas =\n          document.createElement('canvas');\n\n        canvas.width = img.width;\n\n        canvas.height = img.height;\n\n        const ctx =\n          canvas.getContext('2d');\n\n        ctx.drawImage(img, 0, 0);\n\n        const mime = file.type;\n\n        const q =\n          mime === 'image\/png'\n            ? 1\n            : quality;\n\n        canvas.toBlob(blob => {\n\n          URL.revokeObjectURL(url);\n\n          resolve(blob);\n\n        }, mime, q);\n\n      };\n\n      img.src = url;\n\n    });\n\n  };\n\n  const compressOne = async id => {\n\n    const item = files.find(\n      file => file.id === id\n    );\n\n    if(!item) return;\n\n    updateProgress(10);\n\n    const blob =\n      await compressImage(item.file);\n\n    if(item.compressedUrl){\n      URL.revokeObjectURL(item.compressedUrl);\n    }\n\n    item.blob = blob;\n\n    item.after = blob.size;\n\n    item.compressedUrl =\n      URL.createObjectURL(blob);\n\n    render();\n\n    updateProgress(100);\n\n    setTimeout(() => {\n\n      updateProgress(0);\n\n    }, 400);\n\n  };\n\n  const handleFiles = list => {\n\n    [...list].forEach(file => {\n\n      if(!file.type.startsWith('image\/')){\n        return;\n      }\n\n      const exists = files.some(\n        item =>\n          item.file.name === file.name &&\n          item.file.size === file.size\n      );\n\n      if(exists){\n        return;\n      }\n\n      files.push({\n\n        id:crypto.randomUUID(),\n\n        file,\n\n        url:URL.createObjectURL(file),\n\n        before:file.size,\n\n        after:0,\n\n        blob:null,\n\n        compressedUrl:null\n\n      });\n\n    });\n\n    render();\n\n    updateWarning();\n\n  };\n\n  chooseBtn.addEventListener('click', e => {\n\n    e.preventDefault();\n\n    e.stopPropagation();\n\n    fileInput.value = null;\n\n    fileInput.click();\n\n  });\n\n  uploadArea.addEventListener('click', e => {\n\n    if(\n      e.target === uploadArea ||\n      e.target.classList.contains('sm-upload-title') ||\n      e.target.classList.contains('sm-upload-subtitle') ||\n      e.target.classList.contains('sm-upload-icon')\n    ){\n\n      fileInput.value = null;\n\n      fileInput.click();\n\n    }\n\n  });\n\n  fileInput.addEventListener('change', e => {\n\n    if(e.target.files.length){\n\n      handleFiles(e.target.files);\n\n    }\n\n  });\n\n  uploadArea.addEventListener('dragover', e => {\n\n    e.preventDefault();\n\n    uploadArea.classList.add('dragover');\n\n  });\n\n  ['dragleave','drop'].forEach(event => {\n\n    uploadArea.addEventListener(event, e => {\n\n      e.preventDefault();\n\n      uploadArea.classList.remove('dragover');\n\n    });\n\n  });\n\n  uploadArea.addEventListener('drop', e => {\n\n    if(e.dataTransfer.files.length){\n\n      handleFiles(e.dataTransfer.files);\n\n    }\n\n  });\n\n  compressAllBtn.addEventListener('click', async () => {\n\n    if(!files.length) return;\n\n    let done = 0;\n\n    updateProgress(1);\n\n    for(const item of files){\n\n      const blob =\n        await compressImage(item.file);\n\n      if(item.compressedUrl){\n\n        URL.revokeObjectURL(item.compressedUrl);\n\n      }\n\n      item.blob = blob;\n\n      item.after = blob.size;\n\n      item.compressedUrl =\n        URL.createObjectURL(blob);\n\n      done++;\n\n      updateProgress(\n        Math.round(done \/ files.length * 100)\n      );\n\n      render();\n\n    }\n\n    setTimeout(() => {\n\n      updateProgress(0);\n\n    }, 400);\n\n  });\n\n  downloadZipBtn.addEventListener('click', async () => {\n\n    const zip = new JSZip();\n\n    files.forEach(item => {\n\n      if(item.blob){\n\n        zip.file(\n          item.file.name,\n          item.blob\n        );\n\n      }\n\n    });\n\n    const output =\n      await zip.generateAsync({\n        type:'blob'\n      });\n\n    const link =\n      document.createElement('a');\n\n    link.href =\n      URL.createObjectURL(output);\n\n    link.download =\n      'compressed-images.zip';\n\n    link.click();\n\n  });\n\n  clearAllBtn.addEventListener('click', () => {\n\n    files.forEach(revokeURLs);\n\n    files = [];\n\n    grid.innerHTML = '';\n\n    updateWarning();\n\n    updateProgress(0);\n\n    downloadZipBtn.disabled = true;\n\n  });\n\n})();\n<\/script>\n<\/div><\/div>\n\n<\/div><\/div>\n\n<style>.kb-row-layout-id10_65ab63-b9 > .kt-row-column-wrap{align-content:start;}:where(.kb-row-layout-id10_65ab63-b9 > .kt-row-column-wrap) > .wp-block-kadence-column{justify-content:start;}.kb-row-layout-id10_65ab63-b9 > .kt-row-column-wrap{column-gap:var(--global-kb-gap-md, 2rem);row-gap:var(--global-kb-gap-md, 2rem);padding-top:var(--global-kb-spacing-sm, 1.5rem);padding-bottom:var(--global-kb-spacing-sm, 1.5rem);grid-template-columns:minmax(0, 1fr);}.kb-row-layout-id10_65ab63-b9 > .kt-row-layout-overlay{opacity:0.30;}@media all and (max-width: 1024px){.kb-row-layout-id10_65ab63-b9 > .kt-row-column-wrap{grid-template-columns:minmax(0, 1fr);}}@media all and (max-width: 767px){.kb-row-layout-id10_65ab63-b9 > .kt-row-column-wrap{grid-template-columns:minmax(0, 1fr);}}<\/style><div class=\"kb-row-layout-wrap kb-row-layout-id10_65ab63-b9 alignnone wp-block-kadence-rowlayout\"><div class=\"kt-row-column-wrap kt-has-1-columns kt-row-layout-equal kt-tab-layout-inherit kt-mobile-layout-row kt-row-valign-top\">\n<style>.kadence-column10_751af1-c4 > .kt-inside-inner-col{padding-top:20px;padding-bottom:20px;}.kadence-column10_751af1-c4 > .kt-inside-inner-col,.kadence-column10_751af1-c4 > .kt-inside-inner-col:before{border-top-left-radius:0px;border-top-right-radius:0px;border-bottom-right-radius:0px;border-bottom-left-radius:0px;}.kadence-column10_751af1-c4 > .kt-inside-inner-col{column-gap:var(--global-kb-gap-sm, 1rem);}.kadence-column10_751af1-c4 > .kt-inside-inner-col{flex-direction:column;}.kadence-column10_751af1-c4 > .kt-inside-inner-col > .aligncenter{width:100%;}.kadence-column10_751af1-c4 > .kt-inside-inner-col{background-image:linear-gradient(135deg,rgb(218,235,245) 0%,rgb(154,174,246) 100%);}.kadence-column10_751af1-c4 > .kt-inside-inner-col:before{opacity:0.3;}.kadence-column10_751af1-c4{position:relative;}@media all and (max-width: 1024px){.kadence-column10_751af1-c4 > .kt-inside-inner-col{flex-direction:column;justify-content:center;}}@media all and (max-width: 767px){.kadence-column10_751af1-c4 > .kt-inside-inner-col{flex-direction:column;justify-content:center;}}<\/style>\n<div class=\"wp-block-kadence-column kadence-column10_751af1-c4\"><div class=\"kt-inside-inner-col\">\n<style>\n:root{\n  --sm-primary:#2563EB;\n  --sm-dark:#0F172A;\n  --sm-bg:#F8FAFC;\n  --sm-border:#E2E8F0;\n  --sm-text:#1E293B;\n  --sm-muted:#64748B;\n  --sm-radius:16px;\n}\n\n*{\n  box-sizing:border-box;\n}\n\n.sm-tool-card{\n  background:#fff;\n  border:1px solid var(--sm-border);\n  border-radius:var(--sm-radius);\n  padding:24px;\n  box-shadow:0 4px 20px rgba(15,23,42,.04);\n  max-width:520px;\n  margin:auto;\n  font-family:Inter,sans-serif;\n}\n\n.sm-tool-header{\n  text-align:center;\n  margin-bottom:24px;\n}\n\n.sm-tool-title{\n  font-size:28px;\n  font-weight:700;\n  color:var(--sm-dark);\n  margin:0 0 10px;\n}\n\n.sm-tool-desc{\n  color:var(--sm-muted);\n  font-size:15px;\n  line-height:1.6;\n  margin:0;\n}\n\n.sm-upload{\n  border:2px dashed #BFDBFE;\n  border-radius:16px;\n  padding:28px 20px;\n  text-align:center;\n  background:#F8FAFC;\n  cursor:pointer;\n  transition:.2s ease;\n  margin-bottom:20px;\n}\n\n.sm-upload:hover{\n  border-color:var(--sm-primary);\n  background:#EFF6FF;\n}\n\n.sm-upload.dragover{\n  border-color:var(--sm-primary);\n  background:#DBEAFE;\n}\n\n.sm-upload-icon{\n  font-size:42px;\n  margin-bottom:10px;\n}\n\n.sm-upload-title{\n  font-size:17px;\n  font-weight:600;\n  color:var(--sm-dark);\n  margin-bottom:6px;\n}\n\n.sm-upload-subtitle{\n  font-size:14px;\n  color:var(--sm-muted);\n}\n\n.sm-hidden{\n  display:none;\n}\n\n.sm-preview{\n  margin-bottom:20px;\n  text-align:center;\n}\n\n.sm-preview img{\n  width:100%;\n  border-radius:14px;\n  border:1px solid var(--sm-border);\n  max-height:320px;\n  object-fit:contain;\n  background:#F8FAFC;\n}\n\n.sm-select{\n  width:100%;\n  padding:14px 16px;\n  border:1px solid var(--sm-border);\n  border-radius:12px;\n  font-size:15px;\n  outline:none;\n  background:#fff;\n  color:var(--sm-text);\n  margin-bottom:18px;\n  transition:.2s ease;\n}\n\n.sm-select:focus{\n  border-color:var(--sm-primary);\n  box-shadow:0 0 0 4px rgba(37,99,235,.1);\n}\n\n.sm-btn{\n  width:100%;\n  border:none;\n  border-radius:12px;\n  padding:14px 18px;\n  font-weight:600;\n  cursor:pointer;\n  transition:.2s ease;\n  background:var(--sm-primary);\n  color:#fff;\n}\n\n.sm-btn:hover{\n  background:#1D4ED8;\n}\n\n.sm-status{\n  margin-top:16px;\n  text-align:center;\n  font-size:14px;\n  color:var(--sm-muted);\n}\n\n@media(max-width:640px){\n\n  .sm-tool-card{\n    padding:20px;\n  }\n\n  .sm-tool-title{\n    font-size:24px;\n  }\n\n}\n<\/style>\n\n<div class=\"sm-tool-card\">\n\n  <div class=\"sm-tool-header\">\n\n    <h2 class=\"sm-tool-title\">\n      Image Converter\n    <\/h2>\n\n    <p class=\"sm-tool-desc\">\n      Convert images between JPG, PNG and WebP formats directly in your browser.\n    <\/p>\n\n  <\/div>\n\n  <div class=\"sm-upload\" id=\"smUploadArea\">\n\n    <div class=\"sm-upload-icon\">\ud83d\uddbc\ufe0f<\/div>\n\n    <div class=\"sm-upload-title\">\n      Upload Your Image\n    <\/div>\n\n    <div class=\"sm-upload-subtitle\">\n      JPG, PNG and WebP supported\n    <\/div>\n\n    <input \n      type=\"file\"\n      id=\"smImageInput\"\n      class=\"sm-hidden\"\n      accept=\"image\/*\"\n    >\n\n  <\/div>\n\n  <div class=\"sm-preview\" id=\"smPreview\" style=\"display:none;\">\n    <img id=\"smPreviewImage\" alt=\"Preview\">\n  <\/div>\n\n  <select class=\"sm-select\" id=\"smFormatSelect\">\n\n    <option value=\"image\/jpeg\">\n      Convert to JPG\n    <\/option>\n\n    <option value=\"image\/png\">\n      Convert to PNG\n    <\/option>\n\n    <option value=\"image\/webp\">\n      Convert to WebP\n    <\/option>\n\n  <\/select>\n\n  <button class=\"sm-btn\" id=\"smConvertBtn\">\n    Convert &#038; Download\n  <\/button>\n\n  <div class=\"sm-status\" id=\"smStatus\"><\/div>\n\n<\/div>\n\n<script>\n(() => {\n\n  const uploadArea = document.getElementById('smUploadArea');\n  const input = document.getElementById('smImageInput');\n  const preview = document.getElementById('smPreview');\n  const previewImage = document.getElementById('smPreviewImage');\n  const convertBtn = document.getElementById('smConvertBtn');\n  const formatSelect = document.getElementById('smFormatSelect');\n  const status = document.getElementById('smStatus');\n\n  let originalImage = null;\n  let originalFileName = 'converted-image';\n\n  const setStatus = (\n    message,\n    error = false\n  ) => {\n\n    status.textContent = message;\n\n    status.style.color = error\n      ? '#DC2626'\n      : '#64748B';\n\n  };\n\n  const loadImage = file => {\n\n    const reader = new FileReader();\n\n    reader.onload = e => {\n\n      previewImage.src = e.target.result;\n\n      preview.style.display = 'block';\n\n      originalImage = new Image();\n\n      originalImage.src = e.target.result;\n\n      originalFileName = file.name\n        .replace(\/\\.[^\/.]+$\/, '');\n\n      setStatus('Image ready for conversion');\n\n    };\n\n    reader.readAsDataURL(file);\n\n  };\n\n  uploadArea.addEventListener('click', () => {\n\n    input.value = '';\n\n    input.click();\n\n  });\n\n  input.addEventListener('change', e => {\n\n    const file = e.target.files[0];\n\n    if (!file) return;\n\n    if (!file.type.startsWith('image\/')) {\n\n      setStatus('Please upload an image file', true);\n\n      return;\n\n    }\n\n    loadImage(file);\n\n  });\n\n  uploadArea.addEventListener('dragover', e => {\n\n    e.preventDefault();\n\n    uploadArea.classList.add('dragover');\n\n  });\n\n  ['dragleave','drop'].forEach(event => {\n\n    uploadArea.addEventListener(event, e => {\n\n      e.preventDefault();\n\n      uploadArea.classList.remove('dragover');\n\n    });\n\n  });\n\n  uploadArea.addEventListener('drop', e => {\n\n    const file = e.dataTransfer.files[0];\n\n    if (!file) return;\n\n    if (!file.type.startsWith('image\/')) {\n\n      setStatus('Please upload an image file', true);\n\n      return;\n\n    }\n\n    loadImage(file);\n\n  });\n\n  convertBtn.addEventListener('click', () => {\n\n    if (!originalImage) {\n\n      setStatus(\n        'Please upload an image first',\n        true\n      );\n\n      return;\n\n    }\n\n    const format = formatSelect.value;\n\n    const canvas = document.createElement('canvas');\n\n    const ctx = canvas.getContext('2d');\n\n    canvas.width = originalImage.width;\n\n    canvas.height = originalImage.height;\n\n    ctx.drawImage(originalImage, 0, 0);\n\n    canvas.toBlob(blob => {\n\n      const extension = format.split('\/')[1];\n\n      const link = document.createElement('a');\n\n      link.href = URL.createObjectURL(blob);\n\n      link.download = `${originalFileName}.${extension}`;\n\n      link.click();\n\n      setStatus('Image converted successfully');\n\n    }, format, .92);\n\n  });\n\n})();\n<\/script>\n<\/div><\/div>\n\n\n<style>.kadence-column10_d76f9c-0b > .kt-inside-inner-col{padding-top:20px;padding-right:20px;padding-bottom:20px;padding-left:20px;}.kadence-column10_d76f9c-0b > .kt-inside-inner-col,.kadence-column10_d76f9c-0b > .kt-inside-inner-col:before{border-top-left-radius:0px;border-top-right-radius:0px;border-bottom-right-radius:0px;border-bottom-left-radius:0px;}.kadence-column10_d76f9c-0b > .kt-inside-inner-col{column-gap:var(--global-kb-gap-sm, 1rem);}.kadence-column10_d76f9c-0b > .kt-inside-inner-col{flex-direction:column;}.kadence-column10_d76f9c-0b > .kt-inside-inner-col > .aligncenter{width:100%;}.kadence-column10_d76f9c-0b > .kt-inside-inner-col{background-image:linear-gradient(135deg,rgb(255,248,237) 0%,rgb(245,222,194) 100%);}.kadence-column10_d76f9c-0b > .kt-inside-inner-col:before{opacity:0.3;}.kadence-column10_d76f9c-0b{position:relative;}@media all and (max-width: 1024px){.kadence-column10_d76f9c-0b > .kt-inside-inner-col{flex-direction:column;justify-content:center;}}@media all and (max-width: 767px){.kadence-column10_d76f9c-0b > .kt-inside-inner-col{flex-direction:column;justify-content:center;}}<\/style>\n<div class=\"wp-block-kadence-column kadence-column10_d76f9c-0b\"><div class=\"kt-inside-inner-col\">\n<style>\n:root{\n  --sm-primary:#2563EB;\n  --sm-dark:#0F172A;\n  --sm-bg:#F8FAFC;\n  --sm-border:#E2E8F0;\n  --sm-text:#1E293B;\n  --sm-muted:#64748B;\n  --sm-success:#10B981;\n  --sm-danger:#DC2626;\n  --sm-radius:16px;\n}\n\n*{\n  box-sizing:border-box;\n}\n\n.sm-sudoku{\n  max-width:1200px;\n  margin:auto;\n  padding:24px;\n  background:#fff;\n  border:1px solid var(--sm-border);\n  border-radius:20px;\n  font-family:Inter,sans-serif;\n  box-shadow:0 4px 20px rgba(15,23,42,.04);\n}\n\n.sm-header{\n  text-align:center;\n  margin-bottom:24px;\n}\n\n.sm-title{\n  font-size:32px;\n  font-weight:700;\n  color:var(--sm-dark);\n  margin-bottom:10px;\n}\n\n.sm-desc{\n  color:var(--sm-muted);\n  line-height:1.7;\n}\n\n.sm-controls{\n  display:grid;\n  grid-template-columns:repeat(auto-fit,minmax(220px,1fr));\n  gap:16px;\n  margin-bottom:24px;\n}\n\n.sm-select,\n.sm-btn{\n  width:100%;\n  padding:14px 16px;\n  border-radius:12px;\n  border:1px solid var(--sm-border);\n  font-size:15px;\n  font-weight:600;\n}\n\n.sm-select{\n  background:#fff;\n  color:var(--sm-text);\n}\n\n.sm-btn{\n  border:none;\n  cursor:pointer;\n  transition:.2s ease;\n}\n\n.sm-btn-primary{\n  background:var(--sm-primary);\n  color:#fff;\n}\n\n.sm-btn-primary:hover{\n  background:#1D4ED8;\n}\n\n.sm-btn-secondary{\n  background:#F1F5F9;\n  color:var(--sm-dark);\n}\n\n.sm-btn-secondary:hover{\n  background:#E2E8F0;\n}\n\n.sm-board-wrap{\n  display:flex;\n  justify-content:center;\n  margin-top:24px;\n}\n\n.sm-board{\n  display:grid;\n  gap:1px;\n  background:#CBD5E1;\n  padding:4px;\n  border-radius:12px;\n}\n\n.sm-cell{\n  width:48px;\n  height:48px;\n  border:none;\n  text-align:center;\n  font-size:20px;\n  font-weight:700;\n  color:var(--sm-dark);\n  background:#fff;\n  outline:none;\n}\n\n.sm-cell:focus{\n  background:#DBEAFE;\n}\n\n.sm-fixed{\n  background:#E2E8F0;\n}\n\n.sm-message{\n  margin-top:20px;\n  text-align:center;\n  font-weight:600;\n}\n\n.sm-success{\n  color:var(--sm-success);\n}\n\n.sm-error{\n  color:var(--sm-danger);\n}\n\n@media(max-width:768px){\n\n  .sm-cell{\n    width:36px;\n    height:36px;\n    font-size:16px;\n  }\n\n  .sm-title{\n    font-size:26px;\n  }\n\n}\n<\/style>\n\n<div class=\"sm-sudoku\">\n\n  <div class=\"sm-header\">\n\n    <div class=\"sm-title\">\n      Sudoku Puzzle Generator\n    <\/div>\n\n    <div class=\"sm-desc\">\n      Generate and play Sudoku puzzles instantly with multiple grid sizes and difficulty levels.\n    <\/div>\n\n  <\/div>\n\n  <div class=\"sm-controls\">\n\n    <select\n      id=\"smGridSize\"\n      class=\"sm-select\"\n    >\n      <option value=\"4\">4 \u00d7 4<\/option>\n      <option value=\"6\">6 \u00d7 6<\/option>\n      <option value=\"9\" selected>9 \u00d7 9<\/option>\n    <\/select>\n\n    <select\n      id=\"smDifficulty\"\n      class=\"sm-select\"\n    >\n      <option value=\"easy\">Easy<\/option>\n      <option value=\"medium\">Medium<\/option>\n      <option value=\"hard\">Hard<\/option>\n    <\/select>\n\n    <button\n      class=\"sm-btn sm-btn-primary\"\n      id=\"smGenerate\"\n    >\n      Generate Puzzle\n    <\/button>\n\n    <button\n      class=\"sm-btn sm-btn-secondary\"\n      id=\"smSolve\"\n    >\n      Show Solution\n    <\/button>\n\n    <button\n      class=\"sm-btn sm-btn-secondary\"\n      id=\"smCheck\"\n    >\n      Check Answers\n    <\/button>\n\n    <button\n      class=\"sm-btn sm-btn-primary\"\n      id=\"smPrint\"\n    >\n      Print Puzzles\n    <\/button>\n\n  <\/div>\n\n  <div class=\"sm-board-wrap\">\n\n    <div\n      class=\"sm-board\"\n      id=\"smBoard\"\n    ><\/div>\n\n  <\/div>\n\n  <div\n    class=\"sm-message\"\n    id=\"smMessage\"\n  ><\/div>\n\n<\/div>\n\n<script>\n(() => {\n\n  const board =\n    document.getElementById('smBoard');\n\n  const gridSize =\n    document.getElementById('smGridSize');\n\n  const difficulty =\n    document.getElementById('smDifficulty');\n\n  const generateBtn =\n    document.getElementById('smGenerate');\n\n  const solveBtn =\n    document.getElementById('smSolve');\n\n  const checkBtn =\n    document.getElementById('smCheck');\n\n  const printBtn =\n    document.getElementById('smPrint');\n\n  const message =\n    document.getElementById('smMessage');\n\n  let puzzle = [];\n  let solution = [];\n\n  const configs = {\n\n    4:{\n      boxRows:2,\n      boxCols:2,\n      remove:{\n        easy:4,\n        medium:6,\n        hard:8\n      }\n    },\n\n    6:{\n      boxRows:2,\n      boxCols:3,\n      remove:{\n        easy:10,\n        medium:14,\n        hard:18\n      }\n    },\n\n    9:{\n      boxRows:3,\n      boxCols:3,\n      remove:{\n        easy:30,\n        medium:40,\n        hard:50\n      }\n    }\n\n  };\n\n  const shuffle = array => {\n\n    return [...array].sort(\n      () => Math.random() - .5\n    );\n\n  };\n\n  const isValid = (\n    grid,\n    row,\n    col,\n    num,\n    size,\n    boxRows,\n    boxCols\n  ) => {\n\n    for(let i = 0; i < size; i++){\n\n      if(\n        grid[row][i] === num ||\n        grid[i][col] === num\n      ){\n        return false;\n      }\n\n    }\n\n    const startRow =\n      Math.floor(row \/ boxRows) * boxRows;\n\n    const startCol =\n      Math.floor(col \/ boxCols) * boxCols;\n\n    for(\n      let r = startRow;\n      r < startRow + boxRows;\n      r++\n    ){\n\n      for(\n        let c = startCol;\n        c < startCol + boxCols;\n        c++\n      ){\n\n        if(grid[r][c] === num){\n          return false;\n        }\n\n      }\n\n    }\n\n    return true;\n\n  };\n\n  const solveGrid = (\n    grid,\n    size,\n    boxRows,\n    boxCols\n  ) => {\n\n    for(let row = 0; row < size; row++){\n\n      for(let col = 0; col < size; col++){\n\n        if(grid[row][col] === 0){\n\n          for(\n            const num of shuffle(\n              [...Array(size)]\n                .map((_,i)=>i+1)\n            )\n          ){\n\n            if(\n              isValid(\n                grid,\n                row,\n                col,\n                num,\n                size,\n                boxRows,\n                boxCols\n              )\n            ){\n\n              grid[row][col] = num;\n\n              if(\n                solveGrid(\n                  grid,\n                  size,\n                  boxRows,\n                  boxCols\n                )\n              ){\n                return true;\n              }\n\n              grid[row][col] = 0;\n\n            }\n\n          }\n\n          return false;\n\n        }\n\n      }\n\n    }\n\n    return true;\n\n  };\n\n  const renderBoard = () => {\n\n    const size =\n      Number(gridSize.value);\n\n    const {\n      boxRows,\n      boxCols\n    } = configs[size];\n\n    board.innerHTML = '';\n\n    board.style.gridTemplateColumns =\n      `repeat(${size},1fr)`;\n\n    puzzle.forEach((row,rowIndex) => {\n\n      row.forEach((value,colIndex) => {\n\n        const input =\n          document.createElement('input');\n\n        input.type = 'number';\n\n        input.min = 1;\n\n        input.max = size;\n\n        input.className = 'sm-cell';\n\n        input.style.border =\n          '1px solid #CBD5E1';\n\n        if(colIndex % boxCols === 0){\n          input.style.borderLeft =\n            '3px solid #0F172A';\n        }\n\n        if(rowIndex % boxRows === 0){\n          input.style.borderTop =\n            '3px solid #0F172A';\n        }\n\n        if(colIndex === size - 1){\n          input.style.borderRight =\n            '3px solid #0F172A';\n        }\n\n        if(rowIndex === size - 1){\n          input.style.borderBottom =\n            '3px solid #0F172A';\n        }\n\n        if(value !== 0){\n\n          input.value = value;\n\n          input.disabled = true;\n\n          input.classList.add('sm-fixed');\n\n        }\n\n        input.dataset.row = rowIndex;\n\n        input.dataset.col = colIndex;\n\n        board.appendChild(input);\n\n      });\n\n    });\n\n  };\n\n  const generatePuzzle = () => {\n\n    const size =\n      Number(gridSize.value);\n\n    const level =\n      difficulty.value;\n\n    const {\n      boxRows,\n      boxCols,\n      remove\n    } = configs[size];\n\n    solution =\n      Array(size)\n        .fill()\n        .map(() =>\n          Array(size).fill(0)\n        );\n\n    solveGrid(\n      solution,\n      size,\n      boxRows,\n      boxCols\n    );\n\n    puzzle =\n      solution.map(row => [...row]);\n\n    let cellsToRemove =\n      remove[level];\n\n    while(cellsToRemove > 0){\n\n      const row =\n        Math.floor(Math.random() * size);\n\n      const col =\n        Math.floor(Math.random() * size);\n\n      if(puzzle[row][col] !== 0){\n\n        puzzle[row][col] = 0;\n\n        cellsToRemove--;\n\n      }\n\n    }\n\n    renderBoard();\n\n    message.textContent = '';\n\n  };\n\n  const showSolution = () => {\n\n    const cells =\n      board.querySelectorAll('.sm-cell');\n\n    cells.forEach(cell => {\n\n      const row =\n        Number(cell.dataset.row);\n\n      const col =\n        Number(cell.dataset.col);\n\n      cell.value =\n        solution[row][col];\n\n    });\n\n  };\n\n  const checkAnswers = () => {\n\n    let correct = true;\n\n    const cells =\n      board.querySelectorAll('.sm-cell');\n\n    cells.forEach(cell => {\n\n      const row =\n        Number(cell.dataset.row);\n\n      const col =\n        Number(cell.dataset.col);\n\n      if(\n        Number(cell.value) !==\n        solution[row][col]\n      ){\n\n        correct = false;\n\n      }\n\n    });\n\n    if(correct){\n\n      message.textContent =\n        'Puzzle solved correctly \u2714';\n\n      message.className =\n        'sm-message sm-success';\n\n    }else{\n\n      message.textContent =\n        'Some answers are incorrect \u2716';\n\n      message.className =\n        'sm-message sm-error';\n\n    }\n\n  };\n\n  const createPrintablePuzzle = (\n    size,\n    level\n  ) => {\n\n    const {\n      boxRows,\n      boxCols,\n      remove\n    } = configs[size];\n\n    let tempSolution =\n      Array(size)\n        .fill()\n        .map(() =>\n          Array(size).fill(0)\n        );\n\n    solveGrid(\n      tempSolution,\n      size,\n      boxRows,\n      boxCols\n    );\n\n    let tempPuzzle =\n      tempSolution.map(row => [...row]);\n\n    let cellsToRemove =\n      remove[level];\n\n    while(cellsToRemove > 0){\n\n      const row =\n        Math.floor(Math.random() * size);\n\n      const col =\n        Math.floor(Math.random() * size);\n\n      if(tempPuzzle[row][col] !== 0){\n\n        tempPuzzle[row][col] = 0;\n\n        cellsToRemove--;\n\n      }\n\n    }\n\n    return tempPuzzle;\n\n  };\n\n  const printPuzzles = () => {\n\n    const size =\n      Number(gridSize.value);\n\n    const level =\n      difficulty.value;\n\n    const puzzlesPerPage = {\n      4:8,\n      6:6,\n      9:4\n    };\n\n    const count =\n      puzzlesPerPage[size];\n\n    const {\n      boxRows,\n      boxCols\n    } = configs[size];\n\n    const cellSize =\n      size === 9 ? 52 :\n      size === 6 ? 70 :\n      90;\n\n    let html = `\n    <html>\n    <head>\n\n      <title>Sudoku Print<\/title>\n\n      <style>\n\n        *{\n          box-sizing:border-box;\n        }\n\n        body{\n          margin:0;\n          padding:20px;\n          font-family:Arial,sans-serif;\n        }\n\n        .page{\n          display:grid;\n          grid-template-columns:repeat(2,1fr);\n          gap:30px;\n          justify-items:center;\n          align-items:start;\n        }\n\n        .sudoku{\n          display:grid;\n          grid-template-columns:repeat(${size},${cellSize}px);\n        }\n\n        .cell{\n          width:${cellSize}px;\n          height:${cellSize}px;\n          border:1px solid #C5C5C5;\n          display:flex;\n          align-items:center;\n          justify-content:center;\n          font-size:${size === 9 ? 26 : 34}px;\n          font-weight:700;\n        }\n\n        .cell.top-bold{\n          border-top:3px solid #000;\n        }\n\n        .cell.left-bold{\n          border-left:3px solid #000;\n        }\n\n        .cell.right-bold{\n          border-right:3px solid #000;\n        }\n\n        .cell.bottom-bold{\n          border-bottom:3px solid #000;\n        }\n\n        @media print{\n\n          body{\n            margin:0;\n            padding:10px;\n          }\n\n        }\n\n      <\/style>\n\n    <\/head>\n\n    <body>\n\n      <div class=\"page\">\n    `;\n\n    for(let i = 0; i < count; i++){\n\n      const printablePuzzle =\n        createPrintablePuzzle(\n          size,\n          level\n        );\n\n      html += `\n        <div class=\"sudoku\">\n      `;\n\n      printablePuzzle.forEach((row,rowIndex) => {\n\n        row.forEach((cell,colIndex) => {\n\n          let classes = 'cell';\n\n          if(colIndex % boxCols === 0){\n            classes += ' left-bold';\n          }\n\n          if(rowIndex % boxRows === 0){\n            classes += ' top-bold';\n          }\n\n          if(colIndex === size - 1){\n            classes += ' right-bold';\n          }\n\n          if(rowIndex === size - 1){\n            classes += ' bottom-bold';\n          }\n\n          html += `\n            <div class=\"${classes}\">\n              ${cell || ''}\n            <\/div>\n          `;\n\n        });\n\n      });\n\n      html += `\n        <\/div>\n      `;\n\n    }\n\n    html += `\n      <\/div>\n    <\/body>\n    <\/html>\n    `;\n\n    const printWindow =\n      window.open('', '_blank');\n\n    printWindow.document.write(html);\n\n    printWindow.document.close();\n\n    printWindow.focus();\n\n    setTimeout(() => {\n\n      printWindow.print();\n\n    }, 500);\n\n  };\n\n  generateBtn.addEventListener(\n    'click',\n    generatePuzzle\n  );\n\n  solveBtn.addEventListener(\n    'click',\n    showSolution\n  );\n\n  checkBtn.addEventListener(\n    'click',\n    checkAnswers\n  );\n\n  printBtn.addEventListener(\n    'click',\n    printPuzzles\n  );\n\n  gridSize.addEventListener(\n    'change',\n    generatePuzzle\n  );\n\n  difficulty.addEventListener(\n    'change',\n    generatePuzzle\n  );\n\n  generatePuzzle();\n\n})();\n<\/script>\n<\/div><\/div>\n\n<\/div><\/div>\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Outils digitaux gratuits pour les professionnels et la productivit\u00e9 quotidienne Des outils simples, rapides et respectueux de la confidentialit\u00e9, con\u00e7us pour aider les professionnels, entreprises et utilisateurs \u00e0 accomplir leurs t\u00e2ches digitales plus efficacement \u2014 sans complexit\u00e9 inutile ni installation de logiciel. Calculateur TVA Calculez instantan\u00e9ment la TVA pour le Maroc, la France et les&#8230;<\/p>","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"inline_featured_image":false,"_kad_post_transparent":"","_kad_post_title":"hide","_kad_post_layout":"","_kad_post_sidebar_id":"","_kad_post_content_style":"","_kad_post_vertical_padding":"","_kad_post_feature":"","_kad_post_feature_position":"","_kad_post_header":false,"_kad_post_footer":false,"_kad_post_classname":"","footnotes":""},"class_list":["post-10","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/samirmoustakim.com\/ar\/wp-json\/wp\/v2\/pages\/10","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/samirmoustakim.com\/ar\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/samirmoustakim.com\/ar\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/samirmoustakim.com\/ar\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/samirmoustakim.com\/ar\/wp-json\/wp\/v2\/comments?post=10"}],"version-history":[{"count":192,"href":"https:\/\/samirmoustakim.com\/ar\/wp-json\/wp\/v2\/pages\/10\/revisions"}],"predecessor-version":[{"id":1831,"href":"https:\/\/samirmoustakim.com\/ar\/wp-json\/wp\/v2\/pages\/10\/revisions\/1831"}],"wp:attachment":[{"href":"https:\/\/samirmoustakim.com\/ar\/wp-json\/wp\/v2\/media?parent=10"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}