.elementor-kit-1296{--e-global-color-primary:#FFBE0B;--e-global-color-secondary:#3A86FF;--e-global-color-text:#808080;--e-global-color-accent:#FFFFFF;--e-global-color-4efce01:#FFBE0B;--e-global-color-26766d8:#FB5607;--e-global-color-742bb02:#FF006E;--e-global-color-9e87540:#8338EC;--e-global-color-f2f10d6:#3A86FF;--e-global-color-bb44042:#006547;--e-global-typography-primary-font-family:"Quicksand";--e-global-typography-primary-font-weight:600;--e-global-typography-secondary-font-family:"Questrial";--e-global-typography-secondary-font-weight:400;--e-global-typography-text-font-family:"Questrial";--e-global-typography-text-font-size:clamp(1rem, 0.84426rem + 0.65574vw, 1.5rem);--e-global-typography-text-font-weight:400;--e-global-typography-accent-font-family:"Roboto";--e-global-typography-accent-font-weight:500;--e-global-typography-c93c842-font-family:"Trebuchet MS";--e-global-typography-c93c842-font-size:143px;background-color:#F9F9FE;color:var(--e-global-color-text);font-size:clamp(1rem, 0.84426rem + 0.65574vw, 1.5rem);--e-page-transition-entrance-animation:e-page-transition-fade-out;--e-page-transition-animation-duration:1500ms;--e-preloader-animation-duration:4200ms;--e-preloader-delay:0ms;--e-preloader-color:#FFF;--e-preloader-size:20px}.elementor-kit-1296 button:hover,.elementor-kit-1296 button:focus,.elementor-kit-1296 input[type="button"]:hover,.elementor-kit-1296 input[type="button"]:focus,.elementor-kit-1296 input[type="submit"]:hover,.elementor-kit-1296 input[type="submit"]:focus,.elementor-kit-1296 .elementor-button:hover,.elementor-kit-1296 .elementor-button:focus{background-color:#0000000D}.elementor-kit-1296 e-page-transition{background-color:#FBFAF99C}.elementor-kit-1296 p{margin-block-end:0}.elementor-kit-1296 h1{color:var(--e-global-color-text);font-size:clamp(1.81rem, 0.67927rem + 4.76098vw, 4.25rem)}.elementor-kit-1296 h2{color:#000;font-size:clamp(1.5rem, 0.71683rem + 3.29756vw, 3.19rem);font-weight:300}.elementor-kit-1296 h3{font-size:clamp(1.25rem, 0.89803rem + 1.48197vw, 2.38rem)}.elementor-kit-1296 h4{font-size:clamp(1.06rem, 0.82639rem + 0.98361vw, 1.81rem)}.elementor-kit-1296 h5{font-size:clamp(0.88rem, 0.72426rem + 0.65574vw, 1.38rem)}.elementor-kit-1296 h6{font-size:clamp(0.75rem, 0.67213rem + 0.32787vw, 1rem)}.elementor-kit-1296 button,.elementor-kit-1296 input[type="button"],.elementor-kit-1296 input[type="submit"],.elementor-kit-1296 .elementor-button{color:#000;border-style:solid;border-color:#000;border-radius:21px 21px 21px 21px}.elementor-section.elementor-section-boxed>.elementor-container{max-width:1120px}.e-con{--container-max-width:1120px;--container-default-padding-top:0px;--container-default-padding-right:0px;--container-default-padding-bottom:0px;--container-default-padding-left:0px}.elementor-widget:not(:last-child){--kit-widget-spacing:2rem}.elementor-element{--widgets-spacing:2rem 2rem;--widgets-spacing-row:2rem;--widgets-spacing-column:2rem}{}h1.entry-title{display:var(--page-title-display)}.site-header .site-branding{flex-direction:column;align-items:stretch}.site-header{padding-inline-end:0;padding-inline-start:0}.site-footer .site-branding{flex-direction:column;align-items:stretch}@media(max-width:1366px){.elementor-section.elementor-section-boxed>.elementor-container{max-width:100%}.e-con{--container-max-width:100%}}@media(max-width:1024px){.elementor-section.elementor-section-boxed>.elementor-container{max-width:80%}.e-con{--container-max-width:80%;--container-default-padding-top:0%;--container-default-padding-right:0%;--container-default-padding-bottom:0%;--container-default-padding-left:0%}}@media(max-width:767px){.elementor-section.elementor-section-boxed>.elementor-container{max-width:85%}.e-con{--container-max-width:85%}}// Prevent direct access to the file if (!defined('ABSPATH')){exit}// Add menu item to the WordPress admin dashboard function font_clamp_calculator_menu(){add_menu_page('Font Clamp Calculator','Font Clamp','manage_options','font-clamp-calculator','font_clamp_calculator_page','dashicons-editor-textcolor',80)}add_action('admin_menu','font_clamp_calculator_menu');// Callback function to render the Font Clamp Calculator page function font_clamp_calculator_page(){// Load saved settings $settings=get_option('font_clamp_settings',['rootSize'=>16,'minViewport'=>375,'maxViewport'=>1100,'unitType'=>'px','selectedClassSizeId'=>6,'selectedTagSizeId'=>1,'selectedScaleSizeId'=>7,'activeTab'=>'class','scalePMinFont'=>16,'scalePMaxFont'=>16,'scaleRatioMin'=>1.333,'scaleRatioMax'=>1.4,'scalePLineHeight'=>1.4,'previewFontUrl'=>'','previewFontUrlP'=>'']);?><div class="wrap"><h1 class="text-2xl font-bold mb-4">Font Clamp Calculator V4</h1><style>.preview-text{transition:font-size 0.3s ease;line-height:1.2;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-family:var(--preview-font,inherit)}.preview-text.p{font-family:var(--preview-font-p,var(--preview-font,inherit))}.code-block{font-family:'Menlo','Monaco','Courier New',monospace}.input-field:focus{outline:2px solid #3b82f6;outline-offset:!important}.size-row{transition:background-color 0.2s ease;cursor:move}.size-row:hover{background-color:#f1f5f9}.size-row.selected{background-color:#e0f2fe}.size-row.dragging{opacity:.5;background-color:#dbeafe}.drag-over{border-top:2px solid #3b82f6}.wrap button,.wrap [type=button],.wrap [type=submit]{border-color:transparent!important;outline:none!important;box-shadow:none!important;--tw-ring-shadow:none !important}.tab-button{background-color:#f4f4f4;color:#444;border:1px solid #444;transition:background-color 0.2s ease,color 0.2s ease}.tab-button:hover{background-color:#444;color:#fff}.tab-button.active{background-color:#3b82f6;color:#fff}.copy-button,#add-size{background-color:#3b82f6;color:#fff;transition:background-color 0.2s ease,color 0.2s ease}.copy-button:hover,#add-size:hover{background-color:#444;color:#fff}.copy-button:active,#add-size:active{background-color:#3b82f6;color:#fff}.edit-btn,.delete-btn{background-color:#fff0;padding:4px;border-radius:4px;transition:color 0.2s ease}.edit-btn{color:#3b82f6}.edit-btn:hover{color:#1e40af}.delete-btn{color:#ef4444}.delete-btn:hover{color:#b91c1c}#cancel-edit,#save-edit-btn{background-color:#3b82f6;color:#fff;border:none;transition:background-color 0.2s ease,color 0.2s ease}#cancel-edit:hover,#save-edit-btn:hover{background-color:#444;color:#fff}#cancel-edit:active,#save-edit-btn:active{background-color:#3b82f6;color:#fff}table#sizes-table,table#sizes-table th,table#sizes-table td{border:0 solid #d1d5db;border-collapse:collapse}table#sizes-table th,table#sizes-table td{padding:0 8px}.size-row{height:8px}#sizes-table tr:hover{border-left:3px solid #3b82f6}table.min-w-full,table.min-w-full th,table.min-w-full td,table.min-w-full tr{border:none!important;border-width:0!important;border-style:none!important;outline:none!important;box-shadow:none!important}.scale-inputs{display:none}.scale-inputs.active{display:block}.disabled-btn{background-color:#d1d5db!important;cursor:not-allowed!important}.disabled-btn:hover{background-color:#d1d5db!important;color:#ffffff!important}#preview-font-url,#preview-font-url-p{width:200px}</style><div class="max-w-7xl mx-auto bg-white rounded-lg shadow-md overflow-hidden"><div class="p-2"><div class="flex justify-between items-center mb-2"><div class="flex space-x-2"><button id="class-tab" class="tab-button px-3 py-1 rounded-md text-sm <?php echo $settings['activeTab'] === 'class' ? 'active' : ''; ?>">Class</button><button id="tag-tab" class="tab-button px-3 py-1 rounded-md text-sm <?php echo $settings['activeTab'] === 'tag' ? 'active' : ''; ?>">Tag</button><button id="scale-tab" class="tab-button px-3 py-1 rounded-md text-sm <?php echo $settings['activeTab'] === 'scale' ? 'active' : ''; ?>">Scale</button></div><div class="flex space-x-2 items-center"><input type="text" id="preview-font-url" class="input-field px-2 py-1 border border-gray-300 rounded-md text-sm" placeholder="Paste WOFF2 font URL" value="<?php echo esc_attr($settings['previewFontUrl']); ?>"><input type="text" id="preview-font-url-p" class="input-field px-2 py-1 border border-gray-300 rounded-md text-sm" placeholder="Paste WOFF2 font URL for p" value="<?php echo esc_attr($settings['previewFontUrlP']); ?>"><button id="push-to-customizer" class="copy-button bg-green-600 hover:bg-green-700 text-white px-2 py-1 rounded-md text-sm">Push to Theme Custom CSS</button><button id="export-json" class="copy-button bg-yellow-500 hover:bg-yellow-600 text-white px-2 py-1 rounded-md text-sm">Export JSON</button><button id="import-json" class="copy-button bg-purple-600 hover:bg-purple-700 text-white px-2 py-1 rounded-md text-sm">Import JSON</button><input type="file" id="import-json-file" accept="application/json" class="hidden" /></div></div><div class="grid grid-cols-1 lg:grid-cols-2 gap-2"><div><div class="bg-gray-50 p-2 rounded-lg mb-2"><h2 class="text-base font-semibold mb-2">Settings</h2><div class="mb-2"><label class="block text-sm font-medium text-gray-700 mb-1">Input Unit Type</label><div class="flex rounded-md overflow-hidden border border-gray-300"><button id="px-tab" class="tab-button w-1/2 py-1 text-center text-sm font-medium <?php echo $settings['unitType'] === 'px' ? 'active' : ''; ?>">PX</button><button id="rem-tab" class="tab-button w-1/2 py-1 text-center text-sm font-medium <?php echo $settings['unitType'] === 'rem' ? 'active' : ''; ?>">REM</button></div></div><div class="grid grid-cols-3 gap-2 global-settings"><div><label for="root-size" class="block text-sm font-medium text-gray-700 mb-1">Root Size (px)</label><input type="number" id="root-size" value="<?php echo esc_attr($settings['rootSize']); ?>" class="input-field w-full px-2 py-1 border border-gray-300 rounded-md text-sm"></div><div><label for="min-viewport" class="block text-sm font-medium text-gray-700 mb-1">Min Width (px)</label><input type="number" id="min-viewport" value="<?php echo esc_attr($settings['minViewport']); ?>" class="input-field w-full px-2 py-1 border border-gray-300 rounded-md text-sm"></div><div><label for="max-viewport" class="block text-sm font-medium text-gray-700 mb-1">Max Width (px)</label><input type="number" id="max-viewport" value="<?php echo esc_attr($settings['maxViewport']); ?>" class="input-field w-full px-2 py-1 border border-gray-300 rounded-md text-sm"></div></div><div id="scale-inputs" class="scale-inputs grid grid-cols-2 gap-2 mt-2 <?php echo $settings['activeTab'] === 'scale' ? 'active' : ''; ?>"><div><label for="scale-p-min-font" class="block text-sm font-medium text-gray-700 mb-1">P Min Font</label><input type="number" id="scale-p-min-font" step="0.1" value="<?php echo esc_attr($settings['scalePMinFont']); ?>" class="input-field w-full px-2 py-1 border border-gray-300 rounded-md text-sm"></div><div><label for="scale-p-max-font" class="block text-sm font-medium text-gray-700 mb-1">P Max Font</label><input type="number" id="scale-p-max-font" step="0.1" value="<?php echo esc_attr($settings['scalePMaxFont']); ?>" class="input-field w-full px-2 py-1 border border-gray-300 rounded-md text-sm"></div><div><label for="scale-ratio-min" class="block text-sm font-medium text-gray-700 mb-1">Scale Ratio for Min</label><input type="number" id="scale-ratio-min" step="0.01" value="<?php echo esc_attr($settings['scaleRatioMin']); ?>" class="input-field w-full px-2 py-1 border border-gray-300 rounded-md text-sm"></div><div><label for="scale-ratio-max" class="block text-sm font-medium text-gray-700 mb-1">Scale Ratio for Max</label><input type="number" id="scale-ratio-max" step="0.01" value="<?php echo esc_attr($settings['scaleRatioMax']); ?>" class="input-field w-full px-2 py-1 border border-gray-300 rounded-md text-sm"></div></div></div><div class="bg-gray-50 p-2 rounded-lg"><div class="flex justify-between items-center mb-2"><h2 class="text-base font-semibold" id="table-title">Font Size Classes</h2><div class="flex space-x-2"><button id="add-size" class="bg-blue-500 hover:bg-blue-600 text-white px-2 py-1 rounded-md text-sm">Add Size</button><button id="reset-defaults" class="bg-gray-600 hover:bg-gray-700 text-white px-2 py-1 rounded-md text-sm">Reset to Default</button><button id="clear-sizes" class="bg-red-500 hover:bg-red-600 text-white px-2 py-1 rounded-md text-sm">Clear All</button></div></div><div class="overflow-auto" style="max-height: calc(100vh - 350px)"><table class="min-w-full"><thead class="bg-gray-100"><tr><th class="px-2 py-1 text-left text-xs font-medium text-gray-500 uppercase tracking-wider w-8"></th><th class="px-2 py-1 text-left text-xs font-medium text-gray-500 uppercase tracking-wider" id="name-header">Class Name</th><th class="px-2 py-1 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Min Size</th><th class="px-2 py-1 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Max Size</th><th class="px-2 py-1 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Line Height</th><th class="px-2 py-1 text-left text-xs font-medium text-gray-500 uppercase tracking-wider w-16"></th></tr></thead><tbody id="sizes-table"></tbody></table></div></div></div><div><div class="bg-gray-50 p-2 rounded-lg"><h2 class="text-base font-semibold mb-2">Preview</h2><div id="preview-container" class="grid grid-cols-1 gap-1 overflow-auto" style="max-height: calc(100vh - 150px)"></div></div></div></div><div class="bg-gray-50 p-2 rounded-lg mt-2"><div class="flex justify-between items-center mb-2"><h2 class="text-base font-semibold" id="selected-code-title">Selected Class CSS</h2><button id="copy-class" class="copy-button bg-blue-500 hover:bg-blue-600 text-white px-2 py-1 rounded-md text-sm">Copy Class</button></div><div class="bg-gray-800 rounded-lg p-2"><pre id="class-code" class="code-block text-green-400 text-xs whitespace-pre-wrap"></pre></div></div><div class="bg-gray-50 p-2 rounded-lg mt-2"><div class="flex justify-between items-center mb-2"><h2 class="text-base font-semibold" id="generated-code-title">Generated CSS (All Classes)</h2><button id="copy-all" class="copy-button bg-blue-500 hover:bg-blue-600 text-white px-2 py-1 rounded-md text-sm">Copy All</button></div><div class="overflow-auto bg-gray-800 rounded-lg p-2" style="max-height: 300px"><pre id="generated-code" class="code-block text-green-400 text-xs whitespace-pre-wrap"></pre></div></div></div></div><div id="edit-modal" class="fixed inset-0 bg-black bg-opacity-50 z-50 hidden"><div class="absolute top-[300px] left-[180px] bg-white rounded-lg p-4 w-96 max-w-full shadow-lg"><h3 class="text-lg font-semibold mb-3" id="edit-modal-title">Edit Font Size Class</h3><div class="space-y-3"><div><label for="edit-class-name" class="block text-sm font-medium text-gray-700 mb-1" id="edit-name-label">Class Name</label><input type="text" id="edit-class-name" class="input-field w-full px-2 py-1 border border-gray-300 rounded-md"></div><div><label for="edit-min-size" class="block text-sm font-medium text-gray-700 mb-1">Min Size</label><input type="number" id="edit-min-size" step="0.1" class="input-field w-full px-2 py-1 border border-gray-300 rounded-md"></div><div><label for="edit-max-size" class="block text-sm font-medium text-gray-700 mb-1">Max Size</label><input type="number" id="edit-max-size" step="0.1" class="input-field w-full px-2 py-1 border border-gray-300 rounded-md"></div><div><label for="edit-line-height" class="block text-sm font-medium text-gray-700 mb-1">Line Height</label><input type="number" step="0.1" id="edit-line-height" placeholder="1.3" class="input-field w-full px-2 py-1 border border-gray-300 rounded-md"></div><div class="flex justify-end space-x-2 pt-2"><button id="cancel-edit" class="px-3 py-1 border border-gray-300 rounded-md text-sm">Cancel</button><button id="save-edit-btn" class="px-3 py-1 bg-blue-500 text-white rounded-md text-sm">Save</button></div></div></div></div><script src="https://cdn.tailwindcss.com"></script><script>let classSizes=<?php $saved_class_sizes=get_option('font_clamp_class_sizes',false);if ($saved_class_sizes===false){echo json_encode([['id'=>1,'className'=>'xxxlarge','min'=>42,'max'=>52,'lineHeight'=>1.3],['id'=>2,'className'=>'xxlarge','min'=>36,'max'=>44,'lineHeight'=>1.3],['id'=>3,'className'=>'xlarge','min'=>30,'max'=>36,'lineHeight'=>1.3],['id'=>4,'className'=>'large','min'=>24,'max'=>28,'lineHeight'=>1.3],['id'=>5,'className'=>'medium','min'=>18,'max'=>20,'lineHeight'=>1.3],['id'=>6,'className'=>'normal','min'=>16,'max'=>16,'lineHeight'=>1.3],['id'=>7,'className'=>'small','min'=>15,'max'=>15,'lineHeight'=>1.3],['id'=>8,'className'=>'xsmall','min'=>14,'max'=>14,'lineHeight'=>1.3]])}else{echo json_encode($saved_class_sizes)}?>;let tagSizes=<?php $saved_tag_sizes=get_option('font_clamp_tag_sizes',false);if ($saved_tag_sizes===false){echo json_encode([['id'=>1,'tagName'=>'h1','min'=>36,'max'=>48,'lineHeight'=>1.4],['id'=>2,'tagName'=>'h2','min'=>30,'max'=>40,'lineHeight'=>1.4],['id'=>3,'tagName'=>'h3','min'=>24,'max'=>32,'lineHeight'=>1.4],['id'=>4,'tagName'=>'h4','min'=>20,'max'=>28,'lineHeight'=>1.4],['id'=>5,'tagName'=>'h5','min'=>18,'max'=>24,'lineHeight'=>1.4],['id'=>6,'tagName'=>'h6','min'=>16,'max'=>20,'lineHeight'=>1.4],['id'=>7,'tagName'=>'p','min'=>14,'max'=>18,'lineHeight'=>1.4]])}else{echo json_encode($saved_tag_sizes)}?>;let scaleSizes=[];let settings=<?php echo json_encode($settings);?>;let unitType='<?php echo esc_js($settings['unitType']); ?>';let rootSize=<?php echo floatval($settings['rootSize']);?>;let minViewport=<?php echo floatval($settings['minViewport']);?>;let maxViewport=<?php echo floatval($settings['maxViewport']);?>;let selectedClassSizeId=<?php echo intval($settings['selectedClassSizeId']);?>;let selectedTagSizeId=<?php echo intval($settings['selectedTagSizeId']);?>;let selectedScaleSizeId=<?php echo intval($settings['selectedScaleSizeId']);?>;let scalePMinFont=<?php echo floatval($settings['scalePMinFont']);?>;let scalePMaxFont=<?php echo floatval($settings['scalePMaxFont']);?>;let scaleRatioMin=<?php echo floatval($settings['scaleRatioMin']);?>;let scaleRatioMax=<?php echo floatval($settings['scaleRatioMax']);?>;let scalePLineHeight=<?php echo floatval($settings['scalePLineHeight']);?>;let previewFontUrl='<?php echo esc_js($settings['previewFontUrl']); ?>';let previewFontUrlP='<?php echo esc_js($settings['previewFontUrlP']); ?>';let activeTab='<?php echo esc_js($settings['activeTab']); ?>';let editingSizeId=null;let classNextId=Math.max(...classSizes.map(size => size.id))+1;let tagNextId=Math.max(...tagSizes.map(size => size.id))+1;let scaleNextId=8;const classTab=document.getElementById('class-tab');const tagTab=document.getElementById('tag-tab');const scaleTab=document.getElementById('scale-tab');const pxTab=document.getElementById('px-tab');const remTab=document.getElementById('rem-tab');const rootSizeInput=document.getElementById('root-size');const minViewportInput=document.getElementById('min-viewport');const maxViewportInput=document.getElementById('max-viewport');const scalePMinFontInput=document.getElementById('scale-p-min-font');const scalePMaxFontInput=document.getElementById('scale-p-max-font');const scaleRatioMinInput=document.getElementById('scale-ratio-min');const scaleRatioMaxInput=document.getElementById('scale-ratio-max');const scaleInputs=document.getElementById('scale-inputs');const sizesTable=document.getElementById('sizes-table');const previewContainer=document.getElementById('preview-container');const generatedCode=document.getElementById('generated-code');const classCode=document.getElementById('class-code');const copyAllBtn=document.getElementById('copy-all');const copyClassBtn=document.getElementById('copy-class');const addSizeBtn=document.getElementById('add-size');const clearSizesBtn=document.getElementById('clear-sizes');const editModal=document.getElementById('edit-modal');const editClassName=document.getElementById('edit-class-name');const editLineHeight=document.getElementById('edit-line-height');const editMinSize=document.getElementById('edit-min-size');const editMaxSize=document.getElementById('edit-max-size');const cancelEditBtn=document.getElementById('cancel-edit');const saveEditBtn=document.getElementById('save-edit-btn');const tableTitle=document.getElementById('table-title');const nameHeader=document.getElementById('name-header');const selectedCodeTitle=document.getElementById('selected-code-title');const generatedCodeTitle=document.getElementById('generated-code-title');const editModalTitle=document.getElementById('edit-modal-title');const editNameLabel=document.getElementById('edit-name-label');const previewFontUrlInput=document.getElementById('preview-font-url');const previewFontUrlPInput=document.getElementById('preview-font-url-p');function applyPreviewFonts(url,urlP){const siteUrl='<?php echo esc_js(home_url()); ?>';const style=document.createElement('style');let fontFaceRules='';document.documentElement.style.setProperty('--preview-font','inherit');document.documentElement.style.setProperty('--preview-font-p','inherit');if (url && url.endsWith('.woff2') && url.startsWith(siteUrl)){const fontName='CustomPreviewFont';fontFaceRules+=` @font-face{font-display:swap;font-family:'${fontName}';src:url(https://shanghai-h3.com/wp-content/uploads/elementor/css/${url}) format('woff2');font-weight:400;font-style:normal}`;document.documentElement.style.setProperty('--preview-font',`'${fontName}'`);previewFontUrl=url}else{previewFontUrl='';previewFontUrlInput.value=''}if (urlP && urlP.endsWith('.woff2') && urlP.startsWith(siteUrl)){const fontNameP='CustomPreviewFontP';fontFaceRules+=` @font-face{font-display:swap;font-family:'${fontNameP}';src:url(https://shanghai-h3.com/wp-content/uploads/elementor/css/${urlP}) format('woff2');font-weight:400;font-style:normal}`;document.documentElement.style.setProperty('--preview-font-p',`'${fontNameP}'`);previewFontUrlP=urlP}else{previewFontUrlP='';previewFontUrlPInput.value=''}if (fontFaceRules){style.textContent=fontFaceRules;document.head.appendChild(style)}}function generateScaleSizes(){scaleSizes=[];const tags=['h1','h2','h3','h4','h5','h6','p'];let minFont=unitType==='px' ? scalePMinFont :scalePMinFont / rootSize;let maxFont=unitType==='px' ? scalePMaxFont :scalePMaxFont / rootSize;for (let i=0;i < tags.length;i++){const id=i+1;const tagName=tags[i];let minSize,maxSize;if (tagName==='p'){minSize=unitType==='px' ? scalePMinFont:scalePMinFont;maxSize=unitType==='px' ? scalePMaxFont:scalePMaxFont}else{const level=6 - i;minSize=minFont * Math.pow(scaleRatioMin,level);maxSize=maxFont * Math.pow(scaleRatioMax,level);if (unitType==='rem'){minSize*=rootSize;maxSize*=rootSize}}scaleSizes.push({id:id,tagName:tagName,min:minSize,max:maxSize,lineHeight:scalePLineHeight})}}function init(){generateScaleSizes();updateTabUI();renderSizesTable();renderPreviews();generateAllCode();applyPreviewFonts(previewFontUrl,previewFontUrlP)}function updateTabUI(){classTab.classList.toggle('active',activeTab==='class');tagTab.classList.toggle('active',activeTab==='tag');scaleTab.classList.toggle('active',activeTab==='scale');pxTab.classList.toggle('active',unitType==='px');remTab.classList.toggle('active',unitType==='rem');scaleInputs.classList.toggle('active',activeTab==='scale');addSizeBtn.classList.toggle('disabled-btn',activeTab==='scale');clearSizesBtn.classList.toggle('disabled-btn',activeTab==='scale');tableTitle.textContent=activeTab==='class' ? 'Font Size Classes':(activeTab==='tag' ? 'Font Size Tags':'Font Size Scale');nameHeader.textContent=activeTab==='class' ? 'Class Name':'Tag Name';selectedCodeTitle.textContent=activeTab==='class' ? 'Selected Class CSS':(activeTab==='tag' ? 'Selected Tag CSS':'Selected Scale CSS');generatedCodeTitle.textContent=activeTab==='class' ? 'Generated CSS (All Classes)':(activeTab==='tag' ? 'Generated CSS (All Tags)':'Generated CSS (All Scale)');editModalTitle.textContent=activeTab==='class' ? 'Edit Font Size Class':(activeTab==='tag' ? 'Edit Font Size Tag':'Edit Font Size Scale');editNameLabel.textContent=activeTab==='class' ? 'Class Name':'Tag Name'}function saveSettings(){fetch('<?php echo admin_url(https://shanghai-h3.com/wp-content/uploads/elementor/css/admin-ajax.php); ?>',{method:'POST',headers:{'Content-Type':'application/x-www-form-urlencoded'},body:new URLSearchParams({'action':'save_font_clamp_settings','settings':JSON.stringify({unitType,rootSize,minViewport,maxViewport,selectedClassSizeId,selectedTagSizeId,selectedScaleSizeId,scalePMinFont,scalePMaxFont,scaleRatioMin,scaleRatioMax,scalePLineHeight,previewFontUrl,previewFontUrlP,activeTab}),'nonce':'<?php echo wp_create_nonce('font_clamp_nonce'); ?>'})}) .then(response=>response.json()) .then(data=>{if (!data.success) console.error('Failed to save settings:',data.data)}) .catch(error=>console.error('Error saving settings:',error))}function saveFontSizes(){fetch('<?php echo admin_url(https://shanghai-h3.com/wp-content/uploads/elementor/css/admin-ajax.php); ?>',{method:'POST',headers:{'Content-Type':'application/x-www-form-urlencoded'},body:new URLSearchParams({'action':'save_font_clamp_sizes','class_sizes':JSON.stringify(classSizes),'tag_sizes':JSON.stringify(tagSizes),'nonce':'<?php echo wp_create_nonce('font_clamp_nonce'); ?>'})}) .then(response=>response.json()) .then(data=>{if (!data.success) console.error('Failed to save sizes:',data.data)}) .catch(error=>console.error('Error saving sizes:',error))}classTab.addEventListener('click',()=>{activeTab='class';updateTabUI();renderSizesTable();renderPreviews();generateAllCode();saveSettings()});tagTab.addEventListener('click',()=>{activeTab='tag';updateTabUI();renderSizesTable();renderPreviews();generateAllCode();saveSettings()});scaleTab.addEventListener('click',()=>{activeTab='scale';updateTabUI();renderSizesTable();renderPreviews();generateAllCode();saveSettings()});pxTab.addEventListener('click',()=>{unitType='px';scalePMinFontInput.value=scalePMinFont;scalePMaxFontInput.value=scalePMaxFont;generateScaleSizes();updateTabUI();renderSizesTable();renderPreviews();generateAllCode();saveSettings()});remTab.addEventListener('click',()=>{unitType='rem';scalePMinFontInput.value=(scalePMinFont / rootSize).toFixed(2);scalePMaxFontInput.value=(scalePMaxFont / rootSize).toFixed(2);generateScaleSizes();updateTabUI();renderSizesTable();renderPreviews();generateAllCode();saveSettings()});rootSizeInput.addEventListener('input',()=>{rootSize=parseFloat(rootSizeInput.value) || 16;generateScaleSizes();renderSizesTable();renderPreviews();generateAllCode();saveSettings()});minViewportInput.addEventListener('input',()=>{minViewport=parseFloat(minViewportInput.value) || 375;generateAllCode();saveSettings()});maxViewportInput.addEventListener('input',()=>{maxViewport=parseFloat(maxViewportInput.value) || 1100;generateAllCode();saveSettings()});scalePMinFontInput.addEventListener('input',()=>{scalePMinFont=unitType==='px' ? parseFloat(scalePMinFontInput.value) || 16:(parseFloat(scalePMinFontInput.value) || 1) * rootSize;generateScaleSizes();renderSizesTable();renderPreviews();generateAllCode();saveSettings()});scalePMaxFontInput.addEventListener('input',()=>{scalePMaxFont=unitType==='px' ? parseFloat(scalePMaxFontInput.value) || 16:(parseFloat(scalePMaxFontInput.value) || 1) * rootSize;generateScaleSizes();renderSizesTable();renderPreviews();generateAllCode();saveSettings()});scaleRatioMinInput.addEventListener('input',()=>{scaleRatioMin=parseFloat(scaleRatioMinInput.value) || 1.333;generateScaleSizes();renderSizesTable();renderPreviews();generateAllCode();saveSettings()});scaleRatioMaxInput.addEventListener('input',()=>{scaleRatioMax=parseFloat(scaleRatioMaxInput.value) || 1.4;generateScaleSizes();renderSizesTable();renderPreviews();generateAllCode();saveSettings()});previewFontUrlInput.addEventListener('input',()=>{const url=previewFontUrlInput.value.trim();applyPreviewFonts(url,previewFontUrlP);renderPreviews();saveSettings()});previewFontUrlPInput.addEventListener('input',()=>{const urlP=previewFontUrlPInput.value.trim();applyPreviewFonts(previewFontUrl,urlP);renderPreviews();saveSettings()});copyAllBtn.addEventListener('click',()=>{copyToClipboard(generatedCode.textContent);showCopyFeedback(copyAllBtn)});copyClassBtn.addEventListener('click',()=>{copyToClipboard(classCode.textContent);showCopyFeedback(copyClassBtn)});addSizeBtn.addEventListener('click',()=>{if (activeTab==='scale') return;let newSize;if (activeTab==='class'){newSize={id:classNextId++,className:`custom-${classNextId - 10}`,min:16,max:24,lineHeight:1.4};classSizes.push(newSize);selectedClassSizeId=newSize.id}else if (activeTab==='tag'){newSize={id:tagNextId++,tagName:`custom${tagNextId - 10}`,min:16,max:24,lineHeight:1.4};tagSizes.push(newSize);selectedTagSizeId=newSize.id}renderSizesTable();renderPreviews();generateAllCode();saveFontSizes();saveSettings();openEditModal(newSize.id)});clearSizesBtn.addEventListener('click',()=>{if (activeTab==='scale') return;if (confirm(`Are you sure you want to delete all ${activeTab==='class' ? 'font size classes':'font size tags'}?`)){if (activeTab==='class'){classSizes=[];selectedClassSizeId=null}else if (activeTab==='tag'){tagSizes=[];selectedTagSizeId=null}renderSizesTable();renderPreviews();generateAllCode();saveFontSizes();saveSettings()}});document.getElementById('reset-defaults').addEventListener('click',()=>{if (confirm(`Reset ${activeTab==='class' ? 'class':(activeTab==='tag' ? 'tag':'scale')}sizes and settings to default?`)){fetch('<?php echo admin_url(https://shanghai-h3.com/wp-content/uploads/elementor/css/admin-ajax.php); ?>',{method:'POST',headers:{'Content-Type':'application/x-www-form-urlencoded'},body:new URLSearchParams({action:'reset_font_clamp_defaults',tab:activeTab,nonce:'<?php echo wp_create_nonce('font_clamp_nonce'); ?>'})}) .then(response=>response.json()) .then(data=>{if (data.success){location.reload()}else{alert('Failed to reset to defaults.')}})}});document.getElementById('push-to-customizer').addEventListener('click',()=>{const css=generatedCode.textContent;fetch('<?php echo admin_url(https://shanghai-h3.com/wp-content/uploads/elementor/css/admin-ajax.php); ?>',{method:'POST',headers:{'Content-Type':'application/x-www-form-urlencoded'},body:new URLSearchParams({action:'font_clamp_push_to_customizer',nonce:'<?php echo wp_create_nonce('font_clamp_nonce'); ?>',css:css})}) .then(res=>res.json()) .then(data=>{if (data.success){alert('CSS added to Customizer successfully!')}else{alert('Failed to update Customizer CSS')}})});document.getElementById('export-json').addEventListener('click',()=>{let exportData;if (activeTab==='class'){exportData={settings:{unitType,rootSize,minViewport,maxViewport,selectedClassSizeId,previewFontUrl,previewFontUrlP},sizes:classSizes}}else if (activeTab==='tag'){exportData={settings:{unitType,rootSize,minViewport,maxViewport,selectedTagSizeId,previewFontUrl,previewFontUrlP},sizes:tagSizes}}else if (activeTab==='scale'){exportData={settings:{unitType,rootSize,minViewport,maxViewport,selectedScaleSizeId,scalePMinFont,scalePMaxFont,scaleRatioMin,scaleRatioMax,scalePLineHeight,previewFontUrl,previewFontUrlP},sizes:scaleSizes}}const blob=new Blob([JSON.stringify(exportData,null,2)],{type:'application/json'});const url=URL.createObjecturl(https://shanghai-h3.com/wp-content/uploads/elementor/css/blob);const a=document.createElement('a');a.href=url;a.download=`font-clamp-${activeTab}-config.json`;document.body.appendChild(a);a.click();document.body.removeChild(a)});document.getElementById('import-json').addEventListener('click',()=>{document.getElementById('import-json-file').click()});document.getElementById('import-json-file').addEventListener('change',(event)=>{const file=event.target.files[0];if (!file) return;const reader=new FileReader();reader.onload=function(e){try{const imported=JSON.parse(e.target.result);if (imported.settings && imported.sizes){unitType=imported.settings.unitType || 'px';rootSize=parseFloat(imported.settings.rootSize) || 16;minViewport=parseFloat(imported.settings.minViewport) || 375;maxViewport=parseFloat(imported.settings.maxViewport) || 1100;previewFontUrl=imported.settings.previewFontUrl || '';previewFontUrlP=imported.settings.previewFontUrlP || '';if (activeTab==='class'){classSizes=imported.sizes;selectedClassSizeId=imported.settings.selectedClassSizeId || 1;classNextId=Math.max(...classSizes.map(f => f.id))+1}else if (activeTab==='tag'){tagSizes=imported.sizes;selectedTagSizeId=imported.settings.selectedTagSizeId || 1;tagNextId=Math.max(...tagSizes.map(f => f.id))+1}else if (activeTab==='scale'){scalePMinFont=parseFloat(imported.settings.scalePMinFont) || 16;scalePMaxFont=parseFloat(imported.settings.scalePMaxFont) || 16;scaleRatioMin=parseFloat(imported.settings.scaleRatioMin) || 1.333;scaleRatioMax=parseFloat(imported.settings.scaleRatioMax) || 1.4;scalePLineHeight=parseFloat(imported.settings.scalePLineHeight) || 1.4;selectedScaleSizeId=imported.settings.selectedScaleSizeId || 7;generateScaleSizes()}rootSizeInput.value=rootSize;minViewportInput.value=minViewport;maxViewportInput.value=maxViewport;scalePMinFontInput.value=scalePMinFont;scalePMaxFontInput.value=scalePMaxFont;scaleRatioMinInput.value=scaleRatioMin;scaleRatioMaxInput.value=scaleRatioMax;previewFontUrlInput.value=previewFontUrl;previewFontUrlPInput.value=previewFontUrlP;applyPreviewFonts(previewFontUrl,previewFontUrlP);renderSizesTable();renderPreviews();generateAllCode();saveSettings();if (activeTab !=='scale') saveFontSizes()}else{alert('Invalid JSON file format.')}}catch (err){alert('Failed to parse JSON file.')}};reader.readAsText(file)});cancelEditBtn.addEventListener('click',closeEditModal);saveEditBtn.addEventListener('click',()=>{const sizes=activeTab==='class' ? classSizes :(activeTab==='tag' ? tagSizes :scaleSizes);const sizeIndex=sizes.findIndex(size=>size.id===editingSizeId);if (sizeIndex !==-1){const newName=editClassName.value.trim();const newMinSize=parseFloat(editMinSize.value) || 0;const newMaxSize=parseFloat(editMaxSize.value) || 0;const newLineHeight=parseFloat(editLineHeight.value) || 1.4;if (newName && newMinSize>0 && newMaxSize>0){if (activeTab==='class') sizes[sizeIndex].className=newName;else sizes[sizeIndex].tagName=newName;sizes[sizeIndex].lineHeight=newLineHeight;if (unitType==='px'){sizes[sizeIndex].min=newMinSize;sizes[sizeIndex].max=newMaxSize}else{sizes[sizeIndex].min=newMinSize * rootSize;sizes[sizeIndex].max=newMaxSize * rootSize}if (activeTab==='scale' && sizes[sizeIndex].tagName==='p'){scalePMinFont=sizes[sizeIndex].min;scalePMaxFont=sizes[sizeIndex].max;scalePLineHeight=newLineHeight;scalePMinFontInput.value=unitType==='px' ? scalePMinFont:scalePMinFont / rootSize;scalePMaxFontInput.value=unitType==='px' ? scalePMaxFont:scalePMaxFont / rootSize;generateScaleSizes()}renderSizesTable();renderPreviews();generateAllCode();if (activeTab !=='scale') saveFontSizes();saveSettings();closeEditModal()}}});function renderSizesTable(){sizesTable.innerHTML='';const sizes=activeTab==='class' ? classSizes :(activeTab==='tag' ? tagSizes :scaleSizes);const selectedSizeId=activeTab==='class' ? selectedClassSizeId :(activeTab==='tag' ? selectedTagSizeId :selectedScaleSizeId);sizes.forEach((size,index)=>{const row=document.createElement('tr');row.className=`size-row ${size.id===selectedSizeId ? 'selected':''}`;row.dataset.id=size.id;const isScaleNonP=activeTab==='scale' && size.tagName !=='p';row.draggable=!isScaleNonP;const minSizeDisplay=unitType==='px' ? size.min.toFixed(2) :(size.min / rootSize).toFixed(2);const maxSizeDisplay=unitType==='px' ? size.max.toFixed(2) :(size.max / rootSize).toFixed(2);const name=activeTab==='class' ? size.className :size.tagName;row.innerHTML=` <td class="px-2 py-1"><div class="drag-handle text-gray-400 cursor-move ${isScaleNonP ? 'opacity-0' : ''}">⬍</div></td><td class="px-2 py-[2px] font-medium">${name}</td><td class="px-2 py-[2px]">${minSizeDisplay}${unitType}</td><td class="px-2 py-[2px]">${maxSizeDisplay}${unitType}</td><td class="px-2 py-[2px]">${(size.lineHeight ?? 1.4).toFixed(1)}</td><td class="px-2 py-[2px] flex space-x-1"><button class="edit-btn text-blue-500 hover:text-blue-700 ${isScaleNonP ? 'opacity-0 pointer-events-none' : ''}"><svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z" /></svg></button><button id="delete-btn" class="delete-btn text-red-500 hover:text-red-700 ${isScaleNonP ? 'opacity-0 pointer-events-none' : ''}"><svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" /></svg></button></td>`;row.addEventListener('click',(e)=>{if (!e.target.closest('.edit-btn') && !e.target.closest('.delete-btn')){if (activeTab==='class') selectedClassSizeId=size.id;else if (activeTab==='tag') selectedTagSizeId=size.id;else if (activeTab==='scale') selectedScaleSizeId=size.id;renderSizesTable();renderPreviews();generateAllCode();saveSettings()}});const editBtn=row.querySelector('.edit-btn');editBtn.addEventListener('click',()=>openEditModal(size.id));const deleteBtn=row.querySelector('.delete-btn');deleteBtn.addEventListener('click',()=>{if (confirm(`Are you sure you want to delete the "${name}"`)){const sizes=activeTab==='class' ? classSizes :(activeTab==='tag' ? tagSizes :scaleSizes);sizes.splice(index,1);if (activeTab==='class' && selectedClassSizeId===size.id){selectedClassSizeId=classSizes.length>0 ? classSizes[0].id:null}else if (activeTab==='tag' && selectedTagSizeId===size.id){selectedTagSizeId=tagSizes.length>0 ? tagSizes[0].id:null}else if (activeTab==='scale' && selectedScaleSizeId===size.id){selectedScaleSizeId=scaleSizes.length>0 ? scaleSizes[0].id:null}renderSizesTable();renderPreviews();generateAllCode();if (activeTab !=='scale') saveFontSizes();saveSettings()}});if (!isScaleNonP){row.addEventListener('dragstart',(e)=>{row.classList.add('dragging');e.dataTransfer.setData('text/plain',size.id)});row.addEventListener('dragend',()=>{row.classList.remove('dragging');sizesTable.querySelectorAll('.size-row').forEach(r=>r.classList.remove('drag-over'))});row.addEventListener('dragover',(e)=>{e.preventDefault();row.classList.add('drag-over')});row.addEventListener('dragleave',()=>{row.classList.remove('drag-over')});row.addEventListener('drop',(e)=>{e.preventDefault();const draggedId=parseInt(e.dataTransfer.getData('text/plain'));const targetId=parseInt(row.dataset.id);const sizes=activeTab==='class' ? classSizes:(activeTab==='tag' ? tagSizes:scaleSizes);const draggedIndex=sizes.findIndex(s=>s.id===draggedId);const targetIndex=sizes.findIndex(s=>s.id===targetId);const [draggedItem]=sizes.splice(draggedIndex,1);sizes.splice(targetIndex,0,draggedItem);renderSizesTable();renderPreviews();generateAllCode();if (activeTab !=='scale') saveFontSizes();sizesTable.querySelectorAll('.size-row').forEach(r=>r.classList.remove('drag-over'))})}sizesTable.appendChild(row)})}function renderPreviews(){previewContainer.innerHTML='';const sizes=activeTab==='class' ? classSizes :(activeTab==='tag' ? tagSizes :scaleSizes);const selectedSizeId=activeTab==='class' ? selectedClassSizeId :(activeTab==='tag' ? selectedTagSizeId :selectedScaleSizeId);sizes.forEach(size=>{const previewDiv=document.createElement('div');previewDiv.className=`px-2 py-[0px] border rounded-lg ${size.id===selectedSizeId ? 'border-blue-500 bg-blue-50':'border-gray-200'}`;const flexContainer=document.createElement('div');flexContainer.className='flex justify-between items-center';const minPreviewContainer=document.createElement('div');minPreviewContainer.className='flex-1 text-center';const minPreview=document.createElement('div');minPreview.className=`preview-text ${activeTab !=='class' && size.tagName==='p' ? 'p':''}`;minPreview.style.fontSize=`${size.min}px`;minPreview.style.lineHeight=`${(size.lineHeight ?? 1.4).toFixed(1)}`;minPreview.textContent=activeTab==='class' ? size.className :size.tagName;minPreviewContainer.appendChild(minPreview);const maxPreviewContainer=document.createElement('div');maxPreviewContainer.className='flex-1 text-center';const maxPreview=document.createElement('div');maxPreview.className=`preview-text ${activeTab !=='class' && size.tagName==='p' ? 'p':''}`;maxPreview.style.fontSize=`${size.max}px`;maxPreview.style.lineHeight=`${(size.lineHeight ?? 1.4).toFixed(1)}`;maxPreview.textContent=activeTab==='class' ? size.className :size.tagName;maxPreviewContainer.appendChild(maxPreview);const divider=document.createElement('div');divider.className='mx-1 h-8 border-l border-gray-300';flexContainer.appendChild(minPreviewContainer);flexContainer.appendChild(divider);flexContainer.appendChild(maxPreviewContainer);previewDiv.appendChild(flexContainer);previewDiv.addEventListener('click',()=>{if (activeTab==='class') selectedClassSizeId=size.id;else if (activeTab==='tag') selectedTagSizeId=size.id;else if (activeTab==='scale') selectedScaleSizeId=size.id;renderSizesTable();renderPreviews();generateAllCode();saveSettings()});previewContainer.appendChild(previewDiv)})}function calculateClamp(minSize,maxSize,minViewport,maxViewport){const minSizePx=minSize;const maxSizePx=maxSize;const slope=(maxSizePx - minSizePx) / (maxViewport - minViewport);const yIntercept=minSizePx - slope * minViewport;const slopeVw=slope * 100;const minSizeRem=minSizePx / rootSize;const maxSizeRem=maxSizePx / rootSize;const yInterceptRem=yIntercept / rootSize;return `clamp(${minSizeRem.toFixed(2)}rem,${yInterceptRem.toFixed(5)}rem+${slopeVw.toFixed(5)}vw,${maxSizeRem.toFixed(2)}rem)`}function generateClassCode(size){const clampValue=calculateClamp(size.min,size.max,minViewport,maxViewport);if (activeTab==='class'){return `:is(.${size.className}:is(h1,h2,h3,h4,h5,h6,p,a,span,button,div,li),.${size.className}:is(.e-heading-base,.e-paragraph-base,.e-button-base)){font-size:${clampValue};line-height:${(size.lineHeight ?? 1.4).toFixed(1)}}`}else{return `${size.tagName}{\n font-size:${clampValue};\n line-height:${(size.lineHeight ?? 1.4).toFixed(1)};\n}\n`}}function generateAllCode(){const sizes=activeTab==='class' ? classSizes :(activeTab==='tag' ? tagSizes :scaleSizes);if (sizes.length===0){classCode.textContent='';generatedCode.textContent=``;return}let code=`html{font-size:${rootSize}px}\n\n`;sizes.forEach(size=>{code+=generateClassCode(size)+'\n'});generatedCode.textContent=code.trim();const selectedSizeId=activeTab==='class' ? selectedClassSizeId:(activeTab==='tag' ? selectedTagSizeId:selectedScaleSizeId);const selectedSize=sizes.find(size=>size.id===selectedSizeId);classCode.textContent=selectedSize ? generateClassCode(selectedSize):''}function copyToClipboard(text){navigator.clipboard.writeText(text)}function showCopyFeedback(button){const originalText=button.textContent;button.textContent='Copied!';button.classList.add('bg-green-600');setTimeout(()=>{button.textContent=originalText;button.classList.remove('bg-green-600')},1500)}let boundUpdateLivePreview=null;function openEditModal(sizeId){const sizes=activeTab==='class' ? classSizes :(activeTab==='tag' ? tagSizes :scaleSizes);const size=sizes.find(s=>s.id===sizeId);if (!size || (activeTab==='scale' && size.tagName !=='p')) return;editingSizeId=sizeId;editClassName.value=activeTab==='class' ? size.className :size.tagName;if (unitType==='px'){editMinSize.value=size.min.toFixed(1);editMaxSize.value=size.max.toFixed(1)}else{editMinSize.value=(size.min / rootSize).toFixed(2);editMaxSize.value=(size.max / rootSize).toFixed(2)}editLineHeight.value=size.lineHeight ?? 1.4;editClassName.disabled=activeTab==='scale';editModal.classList.remove('hidden');editModal.classList.remove('justify-center');editModal.classList.add('justify-start');boundUpdateLivePreview=function(){const newMin=parseFloat(editMinSize.value) || 0;const newMax=parseFloat(editMaxSize.value) || 0;const tempSize={...size};if (unitType==='px'){tempSize.min=newMin;tempSize.max=newMax}else{tempSize.min=newMin * rootSize;tempSize.max=newMax * rootSize}if (activeTab==='class') tempSize.className=editClassName.value;else tempSize.tagName=editClassName.value;const previewBlock=[...previewContainer.children].find(block=>{return block.querySelector('.preview-text')?.textContent===(activeTab==='class' ? size.className:size.tagName)});if (previewBlock){const minPreview=previewBlock.querySelector('.flex > div:first-child .preview-text');const maxPreview=previewBlock.querySelector('.flex > div:last-child .preview-text');if (minPreview) minPreview.style.fontSize=`${tempSize.min}px`;if (maxPreview) maxPreview.style.fontSize=`${tempSize.max}px`}classCode.textContent=generateClassCode(tempSize)};editMinSize.addEventListener('input',boundUpdateLivePreview);editMaxSize.addEventListener('input',boundUpdateLivePreview)}function closeEditModal(){editModal.classList.add('hidden');editingSizeId=null;editClassName.value='';editMinSize.value='';editMaxSize.value='';editClassName.disabled=false;if (boundUpdateLivePreview){editMinSize.removeEventListener('input',boundUpdateLivePreview);editMaxSize.removeEventListener('input',boundUpdateLivePreview);boundUpdateLivePreview=null}}init();</script></div><?php}function save_font_clamp_sizes(){check_ajax_referer('font_clamp_nonce','nonce');if (isset($_POST['class_sizes']) && isset($_POST['tag_sizes'])){$class_sizes=json_decode(stripslashes($_POST['class_sizes']),true);$tag_sizes=json_decode(stripslashes($_POST['tag_sizes']),true);if (json_last_error()===JSON_ERROR_NONE){update_option('font_clamp_class_sizes',$class_sizes);update_option('font_clamp_tag_sizes',$tag_sizes);wp_send_json_success()}else{wp_send_json_error('Invalid JSON data')}}else{wp_send_json_error('No sizes provided')}}add_action('wp_ajax_save_font_clamp_sizes','save_font_clamp_sizes');function reset_font_clamp_defaults(){check_ajax_referer('font_clamp_nonce','nonce');$tab=isset($_POST['tab']) ? sanitize_text_field($_POST['tab']) :'class';if ($tab==='class'){update_option('font_clamp_class_sizes',[['id'=>1,'className'=>'xxxlarge','min'=>42,'max'=>52,'lineHeight'=>1.3],['id'=>2,'className'=>'xxlarge','min'=>36,'max'=>44,'lineHeight'=>1.3],['id'=>3,'className'=>'xlarge','min'=>30,'max'=>36,'lineHeight'=>1.3],['id'=>4,'className'=>'large','min'=>24,'max'=>28,'lineHeight'=>1.3],['id'=>5,'className'=>'medium','min'=>18,'max'=>20,'lineHeight'=>1.3],['id'=>6,'className'=>'normal','min'=>16,'max'=>16,'lineHeight'=>1.3],['id'=>7,'className'=>'small','min'=>15,'max'=>15,'lineHeight'=>1.3],['id'=>8,'className'=>'xsmall','min'=>14,'max'=>14,'lineHeight'=>1.3]]);update_option('font_clamp_settings',array_merge(get_option('font_clamp_settings',[]),['selectedClassSizeId'=>6,'previewFontUrl'=>'','previewFontUrlP'=>'']))}else if ($tab==='tag'){update_option('font_clamp_tag_sizes',[['id'=>1,'tagName'=>'h1','min'=>36,'max'=>48,'lineHeight'=>1.4],['id'=>2,'tagName'=>'h2','min'=>30,'max'=>40,'lineHeight'=>1.4],['id'=>3,'tagName'=>'h3','min'=>24,'max'=>32,'lineHeight'=>1.4],['id'=>4,'tagName'=>'h4','min'=>20,'max'=>28,'lineHeight'=>1.4],['id'=>5,'tagName'=>'h5','min'=>18,'max'=>24,'lineHeight'=>1.4],['id'=>6,'tagName'=>'h6','min'=>16,'max'=>20,'lineHeight'=>1.4],['id'=>7,'tagName'=>'p','min'=>14,'max'=>18,'lineHeight'=>1.4]]);update_option('font_clamp_settings',array_merge(get_option('font_clamp_settings',[]),['selectedTagSizeId'=>1,'previewFontUrl'=>'','previewFontUrlP'=>'']))}else if ($tab==='scale'){update_option('font_clamp_settings',array_merge(get_option('font_clamp_settings',[]),['scalePMinFont'=>16,'scalePMaxFont'=>16,'scaleRatioMin'=>1.333,'scaleRatioMax'=>1.4,'scalePLineHeight'=>1.4,'selectedScaleSizeId'=>7,'previewFontUrl'=>'','previewFontUrlP'=>'']))}wp_send_json_success()}add_action('wp_ajax_reset_font_clamp_defaults','reset_font_clamp_defaults');function save_font_clamp_settings(){check_ajax_referer('font_clamp_nonce','nonce');if (isset($_POST['settings'])){$settings=json_decode(stripslashes($_POST['settings']),true);if (json_last_error()===JSON_ERROR_NONE){update_option('font_clamp_settings',$settings);wp_send_json_success()}else{wp_send_json_error('Invalid JSON data')}}else{wp_send_json_error('No settings provided')}}add_action('wp_ajax_save_font_clamp_settings','save_font_clamp_settings');function font_clamp_push_to_customizer(){check_ajax_referer('font_clamp_nonce','nonce');if (!current_user_can('edit_theme_options')){wp_send_json_error('Permission denied')}$new_css=stripslashes($_POST['css'] ?? '');$existing_css=wp_get_custom_css();$final_css=$existing_css . "\n\n/* Font Clamp Calculator Output */\n" . $new_css;$result=wp_update_custom_css_post($final_css);if ($result instanceof WP_Post){wp_send_json_success()}else{wp_send_json_error('Failed to update customizer CSS')}}add_action('wp_ajax_font_clamp_push_to_customizer','font_clamp_push_to_customizer');function font_clamp_calculator_enqueue_assets(){if (isset($_GET['page']) && $_GET['page']==='font-clamp-calculator'){wp_enqueue_style('font-clamp-tailwind','https://cdn.tailwindcss.com',[],null)}}add_action('admin_enqueue_scripts','font_clamp_calculator_enqueue_assets');add_shortcode('font_clamp_calculator','render_font_clamp_calculator_shortcode');function render_font_clamp_calculator_shortcode(){ob_start();$settings=get_option('font_clamp_settings',['rootSize'=>16,'minViewport'=>375,'maxViewport'=>1100,'unitType'=>'px','selectedClassSizeId'=>6,'selectedTagSizeId'=>1,'selectedScaleSizeId'=>7,'scalePMinFont'=>16,'scalePMaxFont'=>16,'scaleRatioMin'=>1.333,'scaleRatioMax'=>1.4,'scalePLineHeight'=>1.4,'previewFontUrl'=>'','previewFontUrlP'=>'','activeTab'=>'class']);font_clamp_calculator_page();return ob_get_clean()}add_action('wp_enqueue_scripts','enqueue_font_clamp_tailwind_frontend');function enqueue_font_clamp_tailwind_frontend(){if (is_singular()){global $post;if (has_shortcode($post->post_content,'font_clamp_calculator')){wp_enqueue_script('font-clamp-tailwind','https://cdn.tailwindcss.com',[],null,true)}}}