{"id":2286,"date":"2026-04-09T15:48:27","date_gmt":"2026-04-09T15:48:27","guid":{"rendered":"https:\/\/primetoolhub.com\/?page_id=2286"},"modified":"2026-07-14T03:14:12","modified_gmt":"2026-07-14T03:14:12","slug":"responsive-website-tester-pro","status":"publish","type":"page","link":"https:\/\/schoolict.net\/tools\/responsive-website-tester-pro\/","title":{"rendered":"Free Responsive Website Tester &amp; Mobile Simulator"},"content":{"rendered":"<div class=\"pth-hero-section\">\n<div class=\"pth-hero-content\">\n<h2>Responsive Website Tester with Mobile Simulator<\/h2>\n<p>Test your website&#8217;s responsiveness across multiple devices instantly. Use our free online mobile simulator to preview your site on iPhones, Androids, and tablets securely.Use now Responsive Website Tester<\/p>\n<div id=\"pth-toc-placeholder\"><\/div>\n<\/p>\n<\/div>\n<div class=\"pth-hero-image\">\n\t<img data-no-lazy=\"1\"\n         src=\"https:\/\/schoolict.net\/tools\/wp-content\/uploads\/2026\/04\/Responsive-Website-Tester-800x447.jpeg\"\n         width=\"800\"\n         height=\"447\"\n         alt=\"Responsive Website Tester\"\n         fetchpriority=\"high\"\n         loading=\"eager\"\n         decoding=\"async\"\n         style=\"width:100%; height:auto; display:block;\">\n  <\/div>\n<\/div>\n\n\n<div class=\"wp-block-rank-math-toc-block\" id=\"rank-math-toc\"><h2>Table of Contents<\/h2><nav><ul><li><a href=\"#\ud83d\udd34-five-checks-one-screen\">\ud83d\udd34\u00a0Five checks, one screen<\/a><\/li><li><a href=\"#\ud83d\udfe1-a-real-workflow-start-to-finish\">\ud83d\udfe1\u00a0A real workflow, start to finish<\/a><\/li><li><a href=\"#\ud83d\udfe2-what-browser-testing-cannot-do\">\ud83d\udfe2\u00a0What browser testing cannot do<\/a><\/li><\/ul><\/nav><\/div>\n\n\n<!-- LSCACHE_DISABLE -->\r\n<div id=\"pth-rsp-studio-wrapper\">\r\n<style>\r\n#pth-rsp-studio-wrapper{font-family:'Inter',system-ui,-apple-system,sans-serif;max-width:1500px;margin:0 auto;box-sizing:border-box;background:#f8fafc;padding:20px;border-radius:18px;color:#0f172a}\r\n#pth-rsp-studio-wrapper *{box-sizing:border-box}\r\n#pth-rsp-studio-wrapper .pth-rsp-top{background:#fff;border:1px solid #e2e8f0;border-radius:14px;padding:18px 22px;margin-bottom:18px;box-shadow:0 4px 10px rgba(0,0,0,.04)}\r\n#pth-rsp-studio-wrapper .pth-rsp-title{font-size:1.5rem;font-weight:800;color:#0f172a;margin:0;display:flex;align-items:center;gap:10px}\r\n#pth-rsp-studio-wrapper .pth-rsp-sub{font-size:.9rem;color:#475569;font-weight:500;margin-top:4px}\r\n#pth-rsp-studio-wrapper .pth-rsp-tabs{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:18px}\r\n#pth-rsp-studio-wrapper .pth-rsp-tab{background:#fff;border:1px solid #cbd5e1;color:#334155;font-weight:700;font-size:.9rem;padding:10px 16px;border-radius:10px;cursor:pointer;transition:.2s;font-family:inherit;display:flex;align-items:center;gap:7px}\r\n#pth-rsp-studio-wrapper .pth-rsp-tab:hover{border-color:#2563eb;color:#2563eb}\r\n#pth-rsp-studio-wrapper .pth-rsp-tab.pth-rsp-on{background:#2563eb;border-color:#2563eb;color:#fff}\r\n#pth-rsp-studio-wrapper .pth-rsp-panel{display:none}\r\n#pth-rsp-studio-wrapper .pth-rsp-panel.pth-rsp-show{display:block}\r\n#pth-rsp-studio-wrapper .pth-rsp-card{background:#fff;border:1px solid #e2e8f0;border-radius:12px;padding:20px;margin-bottom:18px;box-shadow:0 4px 6px -1px rgba(0,0,0,.02)}\r\n#pth-rsp-studio-wrapper .pth-rsp-h{font-size:1.05rem;font-weight:800;color:#1e293b;margin:0 0 14px;padding-bottom:12px;border-bottom:2px solid #e2e8f0;display:flex;align-items:center;gap:8px}\r\n#pth-rsp-studio-wrapper label{font-size:.82rem;font-weight:700;color:#334155;display:block;margin-bottom:6px}\r\n#pth-rsp-studio-wrapper input[type=text],#pth-rsp-studio-wrapper input[type=number],#pth-rsp-studio-wrapper textarea,#pth-rsp-studio-wrapper select{width:100%;padding:10px 12px;border:1px solid #cbd5e1;border-radius:8px;font-size:.92rem;font-family:inherit;color:#0f172a;background:#fff;outline:none;transition:.2s}\r\n#pth-rsp-studio-wrapper input:focus,#pth-rsp-studio-wrapper textarea:focus,#pth-rsp-studio-wrapper select:focus{border-color:#2563eb;box-shadow:0 0 0 3px rgba(37,99,235,.12)}\r\n#pth-rsp-studio-wrapper textarea{min-height:120px;resize:vertical;font-family:ui-monospace,Menlo,Consolas,monospace;font-size:.85rem;line-height:1.5}\r\n#pth-rsp-studio-wrapper .pth-rsp-btn{background:#2563eb;color:#fff;border:none;border-radius:8px;padding:10px 18px;font-weight:700;font-size:.9rem;cursor:pointer;transition:.2s;font-family:inherit}\r\n#pth-rsp-studio-wrapper .pth-rsp-btn:hover{background:#1d4ed8}\r\n#pth-rsp-studio-wrapper .pth-rsp-btn.pth-rsp-ghost{background:#f1f5f9;color:#334155;border:1px solid #cbd5e1}\r\n#pth-rsp-studio-wrapper .pth-rsp-btn.pth-rsp-ghost:hover{background:#e2e8f0}\r\n#pth-rsp-studio-wrapper .pth-rsp-row{display:flex;flex-wrap:wrap;gap:10px;align-items:flex-end}\r\n#pth-rsp-studio-wrapper .pth-rsp-row>div{flex:1;min-width:140px}\r\n#pth-rsp-studio-wrapper .pth-rsp-seg{display:inline-flex;background:#f1f5f9;border:1px solid #cbd5e1;border-radius:9px;padding:3px;gap:3px}\r\n#pth-rsp-studio-wrapper .pth-rsp-seg button{background:transparent;border:none;color:#475569;font-weight:700;font-size:.82rem;padding:7px 13px;border-radius:6px;cursor:pointer;font-family:inherit}\r\n#pth-rsp-studio-wrapper .pth-rsp-seg button.pth-rsp-segon{background:#fff;color:#2563eb;box-shadow:0 1px 3px rgba(0,0,0,.08)}\r\n#pth-rsp-studio-wrapper .pth-rsp-devices{display:flex;flex-wrap:wrap;gap:7px;margin:14px 0}\r\n#pth-rsp-studio-wrapper .pth-rsp-chip{background:#fff;border:1px solid #cbd5e1;color:#334155;font-size:.78rem;font-weight:700;padding:6px 11px;border-radius:20px;cursor:pointer;transition:.15s}\r\n#pth-rsp-studio-wrapper .pth-rsp-chip:hover{border-color:#2563eb;color:#2563eb}\r\n#pth-rsp-studio-wrapper .pth-rsp-chip.pth-rsp-chipon{background:#eff6ff;border-color:#2563eb;color:#1d4ed8}\r\n#pth-rsp-studio-wrapper .pth-rsp-stage{background:#e2e8f0;border-radius:12px;padding:22px;overflow:auto;display:flex;justify-content:center;gap:24px;flex-wrap:wrap;min-height:300px}\r\n#pth-rsp-studio-wrapper .pth-rsp-frame{background:#fff;border-radius:10px;box-shadow:0 10px 30px rgba(0,0,0,.14);border:1px solid #94a3b8;flex-shrink:0}\r\n#pth-rsp-studio-wrapper .pth-rsp-frame iframe{border:none;display:block;background:#fff;border-radius:0 0 10px 10px}\r\n#pth-rsp-studio-wrapper .pth-rsp-fbar{background:#1e293b;color:#fff;font-size:.72rem;font-weight:700;padding:6px 12px;border-radius:10px 10px 0 0;display:flex;justify-content:space-between;gap:10px;white-space:nowrap}\r\n#pth-rsp-studio-wrapper .pth-rsp-note{background:#fffbeb;border:1px solid #fde68a;color:#92400e;font-size:.82rem;font-weight:600;padding:10px 14px;border-radius:8px;margin-top:12px;line-height:1.5}\r\n#pth-rsp-studio-wrapper .pth-rsp-hint{font-size:.8rem;color:#475569;margin-top:8px;line-height:1.5}\r\n#pth-rsp-studio-wrapper .pth-rsp-ruler{position:relative;height:46px;background:#f1f5f9;border:1px solid #cbd5e1;border-radius:10px;margin:14px 0}\r\n#pth-rsp-studio-wrapper .pth-rsp-slider{width:100%;margin:8px 0}\r\n#pth-rsp-studio-wrapper .pth-rsp-wpill{display:inline-block;background:#2563eb;color:#fff;font-weight:800;font-size:1.1rem;padding:6px 16px;border-radius:8px}\r\n#pth-rsp-studio-wrapper .pth-rsp-bpgrid{display:grid;grid-template-columns:repeat(auto-fit,minmax(120px,1fr));gap:10px;margin-top:14px}\r\n#pth-rsp-studio-wrapper .pth-rsp-bp{background:#f8fafc;border:1px solid #e2e8f0;border-radius:8px;padding:10px 12px;text-align:center}\r\n#pth-rsp-studio-wrapper .pth-rsp-bp.pth-rsp-bpon{background:#eff6ff;border-color:#2563eb}\r\n#pth-rsp-studio-wrapper .pth-rsp-bp b{display:block;color:#0f172a;font-size:.9rem}\r\n#pth-rsp-studio-wrapper .pth-rsp-bp span{font-size:.75rem;color:#475569}\r\n#pth-rsp-studio-wrapper .pth-rsp-report{margin-top:14px}\r\n#pth-rsp-studio-wrapper .pth-rsp-ri{display:flex;gap:10px;padding:11px 14px;border-radius:8px;margin-bottom:8px;font-size:.88rem;font-weight:600;line-height:1.5;align-items:flex-start}\r\n#pth-rsp-studio-wrapper .pth-rsp-ri.ok{background:#f0fdf4;border:1px solid #bbf7d0;color:#15803d}\r\n#pth-rsp-studio-wrapper .pth-rsp-ri.warn{background:#fffbeb;border:1px solid #fde68a;color:#b45309}\r\n#pth-rsp-studio-wrapper .pth-rsp-ri.bad{background:#fef2f2;border:1px solid #fecaca;color:#b91c1c}\r\n#pth-rsp-studio-wrapper .pth-rsp-code{background:#0f172a;color:#e2e8f0;font-family:ui-monospace,Menlo,Consolas,monospace;font-size:.82rem;padding:12px 14px;border-radius:8px;overflow-x:auto;white-space:pre-wrap;word-break:break-word;margin-top:10px}\r\n#pth-rsp-studio-wrapper table.pth-rsp-tbl{width:100%;border-collapse:collapse;font-size:.85rem}\r\n#pth-rsp-studio-wrapper table.pth-rsp-tbl th{background:#f1f5f9;color:#1e293b;font-weight:800;text-align:left;padding:10px 12px;border-bottom:2px solid #e2e8f0;position:sticky;top:0}\r\n#pth-rsp-studio-wrapper table.pth-rsp-tbl td{padding:10px 12px;border-bottom:1px solid #e2e8f0;color:#334155}\r\n#pth-rsp-studio-wrapper table.pth-rsp-tbl tr:hover td{background:#f8fafc}\r\n#pth-rsp-studio-wrapper .pth-rsp-cat{display:inline-block;font-size:.72rem;font-weight:800;padding:2px 9px;border-radius:20px;background:#eff6ff;color:#1d4ed8}\r\n#pth-rsp-studio-wrapper .pth-rsp-tblwrap{max-height:520px;overflow:auto;border:1px solid #e2e8f0;border-radius:10px}\r\n#pth-rsp-studio-wrapper .pth-rsp-xlink{color:#1d4ed8;font-weight:700;text-decoration:none}\r\n#pth-rsp-studio-wrapper .pth-rsp-xlink:hover{text-decoration:underline}\r\n#pth-rsp-studio-wrapper .pth-rsp-toast{position:fixed;bottom:22px;right:22px;background:#0f172a;color:#fff;font-weight:700;font-size:.86rem;padding:12px 20px;border-radius:9px;box-shadow:0 10px 30px rgba(0,0,0,.3);z-index:99999;opacity:0;transform:translateY(10px);transition:.3s;pointer-events:none}\r\n#pth-rsp-studio-wrapper .pth-rsp-toast.pth-rsp-tshow{opacity:1;transform:translateY(0)}\r\n@media(max-width:768px){#pth-rsp-studio-wrapper{padding:14px}#pth-rsp-studio-wrapper .pth-rsp-stage{padding:12px;gap:14px}}\r\n<\/style>\r\n\r\n<div class=\"pth-rsp-top\">\r\n  <h2 class=\"pth-rsp-title\">\ud83d\udcf1 Responsive Studio Pro<\/h2>\r\n  <div class=\"pth-rsp-sub\">Preview across devices, inspect breakpoints, check your viewport meta tag, capture screenshots, and look up device sizes \u2014 all 100% offline in your browser.<\/div>\r\n<\/div>\r\n\r\n<div class=\"pth-rsp-tabs\" role=\"tablist\">\r\n  <button class=\"pth-rsp-tab pth-rsp-on\" data-tab=\"preview\">\ud83d\udda5\ufe0f Live Preview<\/button>\r\n  <button class=\"pth-rsp-tab\" data-tab=\"bp\">\ud83d\udccf Breakpoint Inspector<\/button>\r\n  <button class=\"pth-rsp-tab\" data-tab=\"meta\">\ud83d\udcf1 Viewport Meta Checker<\/button>\r\n  <button class=\"pth-rsp-tab\" data-tab=\"shot\">\ud83d\udcf8 Screenshot Export<\/button>\r\n  <button class=\"pth-rsp-tab\" data-tab=\"ref\">\ud83d\udcd0 Device Reference<\/button>\r\n<\/div>\r\n\r\n<!-- TAB 1: LIVE PREVIEW -->\r\n<div class=\"pth-rsp-panel pth-rsp-show\" id=\"pth-rsp-panel-preview\">\r\n  <div class=\"pth-rsp-card\">\r\n    <div class=\"pth-rsp-h\">\ud83d\udda5\ufe0f Source<\/div>\r\n    <div class=\"pth-rsp-seg\" id=\"pth-rsp-srcseg\">\r\n      <button data-src=\"url\" class=\"pth-rsp-segon\">Load a URL<\/button>\r\n      <button data-src=\"code\">Paste your code<\/button>\r\n    <\/div>\r\n    <div id=\"pth-rsp-srcurl\" style=\"margin-top:14px\">\r\n      <label for=\"pth-rsp-url\">Website URL<\/label>\r\n      <div class=\"pth-rsp-row\">\r\n        <div style=\"flex:3\"><input type=\"text\" id=\"pth-rsp-url\" placeholder=\"https:\/\/example.com\" value=\"\"><\/div>\r\n        <div style=\"flex:0 0 auto\"><button class=\"pth-rsp-btn\" id=\"pth-rsp-loadurl\">Load<\/button><\/div>\r\n      <\/div>\r\n      <div class=\"pth-rsp-note\">Some sites block being shown inside another page (an <b>X-Frame-Options<\/b> \/ CSP rule). If the preview stays blank, that site cannot be framed \u2014 switch to <b>Paste your code<\/b> instead, which always works.<\/div>\r\n    <\/div>\r\n    <div id=\"pth-rsp-srccode\" style=\"margin-top:14px;display:none\">\r\n      <label for=\"pth-rsp-code\">Paste HTML (inline CSS works best)<\/label>\r\n      <textarea id=\"pth-rsp-code\" spellcheck=\"false\"><\/textarea>\r\n      <div style=\"margin-top:10px\"><button class=\"pth-rsp-btn\" id=\"pth-rsp-rendercode\">Render<\/button>\r\n      <button class=\"pth-rsp-btn pth-rsp-ghost\" id=\"pth-rsp-loadsample\">Load sample<\/button><\/div>\r\n      <div class=\"pth-rsp-hint\">This code is shared with the Breakpoint and Screenshot tabs. Need a full editor with live output? Use the <a class=\"pth-rsp-xlink\" href=\"\/offline-html-editor-with-css-js\/\" target=\"_blank\" rel=\"noopener\">Offline HTML Editor<\/a>.<\/div>\r\n    <\/div>\r\n  <\/div>\r\n\r\n  <div class=\"pth-rsp-card\">\r\n    <div class=\"pth-rsp-h\">\u2699\ufe0f Devices &amp; View<\/div>\r\n    <div class=\"pth-rsp-row\">\r\n      <div>\r\n        <label>View mode<\/label>\r\n        <div class=\"pth-rsp-seg\" id=\"pth-rsp-viewseg\">\r\n          <button data-view=\"single\" class=\"pth-rsp-segon\">Single<\/button>\r\n          <button data-view=\"compare\">Compare<\/button>\r\n          <button data-view=\"grid\">All devices<\/button>\r\n        <\/div>\r\n      <\/div>\r\n      <div>\r\n        <label>Zoom<\/label>\r\n        <div class=\"pth-rsp-seg\" id=\"pth-rsp-zoomseg\">\r\n          <button data-zoom=\"fit\" class=\"pth-rsp-segon\">Fit<\/button>\r\n          <button data-zoom=\"100\">100%<\/button>\r\n          <button data-zoom=\"75\">75%<\/button>\r\n          <button data-zoom=\"50\">50%<\/button>\r\n        <\/div>\r\n      <\/div>\r\n      <div style=\"flex:0 0 auto\"><label>&nbsp;<\/label><button class=\"pth-rsp-btn pth-rsp-ghost\" id=\"pth-rsp-rotate\">\ud83d\udd04 Rotate<\/button><\/div>\r\n    <\/div>\r\n    <div class=\"pth-rsp-devices\" id=\"pth-rsp-devchips\"><\/div>\r\n    <div class=\"pth-rsp-row\" id=\"pth-rsp-customrow\">\r\n      <div><label for=\"pth-rsp-cw\">Custom width (px)<\/label><input type=\"number\" id=\"pth-rsp-cw\" min=\"240\" max=\"3840\" value=\"390\"><\/div>\r\n      <div><label for=\"pth-rsp-ch\">Custom height (px)<\/label><input type=\"number\" id=\"pth-rsp-ch\" min=\"320\" max=\"3840\" value=\"844\"><\/div>\r\n      <div style=\"flex:0 0 auto\"><label>&nbsp;<\/label><button class=\"pth-rsp-btn pth-rsp-ghost\" id=\"pth-rsp-applycustom\">Apply<\/button><\/div>\r\n      <div id=\"pth-rsp-cmpwrap\" style=\"display:none\"><label for=\"pth-rsp-cmpdev\">Compare with<\/label><select id=\"pth-rsp-cmpdev\"><\/select><\/div>\r\n    <\/div>\r\n  <\/div>\r\n\r\n  <div class=\"pth-rsp-stage\" id=\"pth-rsp-stage\"><\/div>\r\n<\/div>\r\n\r\n<!-- TAB 2: BREAKPOINT INSPECTOR -->\r\n<div class=\"pth-rsp-panel\" id=\"pth-rsp-panel-bp\">\r\n  <div class=\"pth-rsp-card\">\r\n    <div class=\"pth-rsp-h\">\ud83d\udccf Width &amp; Active Breakpoint<\/div>\r\n    <div><span class=\"pth-rsp-wpill\" id=\"pth-rsp-bpwidth\">390 px<\/span><\/div>\r\n    <input type=\"range\" class=\"pth-rsp-slider\" id=\"pth-rsp-bpslider\" min=\"320\" max=\"1920\" value=\"390\" step=\"1\">\r\n    <div class=\"pth-rsp-hint\">Drag to any width. The active breakpoint updates live for both common CSS frameworks and for any breakpoints found in your pasted CSS.<\/div>\r\n    <div style=\"margin-top:16px\"><label>Tailwind CSS<\/label><div class=\"pth-rsp-bpgrid\" id=\"pth-rsp-bptw\"><\/div><\/div>\r\n    <div style=\"margin-top:16px\"><label>Bootstrap 5<\/label><div class=\"pth-rsp-bpgrid\" id=\"pth-rsp-bpbs\"><\/div><\/div>\r\n  <\/div>\r\n  <div class=\"pth-rsp-card\">\r\n    <div class=\"pth-rsp-h\">\ud83d\udd0e Your CSS Breakpoints<\/div>\r\n    <label for=\"pth-rsp-css\">Paste CSS containing @media rules<\/label>\r\n    <textarea id=\"pth-rsp-css\" spellcheck=\"false\" placeholder=\"@media (min-width: 768px) { ... }\"><\/textarea>\r\n    <div style=\"margin-top:10px\"><button class=\"pth-rsp-btn\" id=\"pth-rsp-parsecss\">Find breakpoints<\/button><\/div>\r\n    <div class=\"pth-rsp-bpgrid\" id=\"pth-rsp-cssbp\" style=\"margin-top:14px\"><\/div>\r\n  <\/div>\r\n  <div class=\"pth-rsp-card\">\r\n    <div class=\"pth-rsp-h\">\ud83d\udc41\ufe0f Live Width Preview<\/div>\r\n    <div class=\"pth-rsp-hint\">Uses the code from the Live Preview tab, resized to the width above.<\/div>\r\n    <div class=\"pth-rsp-stage\" id=\"pth-rsp-bpstage\" style=\"min-height:220px;margin-top:12px\"><\/div>\r\n  <\/div>\r\n<\/div>\r\n\r\n<!-- TAB 3: VIEWPORT META CHECKER -->\r\n<div class=\"pth-rsp-panel\" id=\"pth-rsp-panel-meta\">\r\n  <div class=\"pth-rsp-card\">\r\n    <div class=\"pth-rsp-h\">\ud83d\udcf1 Viewport Meta Checker<\/div>\r\n    <label for=\"pth-rsp-metain\">Paste your page HTML (the &lt;head&gt; section is enough)<\/label>\r\n    <textarea id=\"pth-rsp-metain\" spellcheck=\"false\" placeholder=\"Paste HTML here...\"><\/textarea>\r\n    <div style=\"margin-top:10px\"><button class=\"pth-rsp-btn\" id=\"pth-rsp-checkmeta\">Check viewport tag<\/button><\/div>\r\n    <div class=\"pth-rsp-report\" id=\"pth-rsp-metaout\"><\/div>\r\n  <\/div>\r\n<\/div>\r\n\r\n<!-- TAB 4: SCREENSHOT EXPORT -->\r\n<div class=\"pth-rsp-panel\" id=\"pth-rsp-panel-shot\">\r\n  <div class=\"pth-rsp-card\">\r\n    <div class=\"pth-rsp-h\">\ud83d\udcf8 Screenshot Export<\/div>\r\n    <div class=\"pth-rsp-hint\">Renders the code from the Live Preview tab at a chosen device size and saves it as a PNG.<\/div>\r\n    <div class=\"pth-rsp-row\" style=\"margin-top:12px\">\r\n      <div><label for=\"pth-rsp-shotdev\">Device size<\/label><select id=\"pth-rsp-shotdev\"><\/select><\/div>\r\n      <div style=\"flex:0 0 auto\"><label>&nbsp;<\/label><button class=\"pth-rsp-btn\" id=\"pth-rsp-capture\">Capture PNG<\/button><\/div>\r\n    <\/div>\r\n    <div class=\"pth-rsp-note\">Client-side capture works best for <b>self-contained HTML and CSS<\/b>. External images without CORS permission, cross-origin URLs, and scripts cannot be rasterized in the browser \u2014 that is a limit of the platform, not a bug.<\/div>\r\n    <div id=\"pth-rsp-shotout\" style=\"margin-top:14px;text-align:center\"><\/div>\r\n  <\/div>\r\n<\/div>\r\n\r\n<!-- TAB 5: DEVICE REFERENCE -->\r\n<div class=\"pth-rsp-panel\" id=\"pth-rsp-panel-ref\">\r\n  <div class=\"pth-rsp-card\">\r\n    <div class=\"pth-rsp-h\">\ud83d\udcd0 Device Size Reference<\/div>\r\n    <div class=\"pth-rsp-row\">\r\n      <div style=\"flex:3\"><input type=\"text\" id=\"pth-rsp-refsearch\" placeholder=\"Search device name...\"><\/div>\r\n      <div><select id=\"pth-rsp-refcat\"><option value=\"all\">All categories<\/option><option value=\"Phone\">Phone<\/option><option value=\"Tablet\">Tablet<\/option><option value=\"Laptop\">Laptop<\/option><option value=\"Desktop\">Desktop<\/option><\/select><\/div>\r\n    <\/div>\r\n    <div class=\"pth-rsp-tblwrap\" style=\"margin-top:14px\">\r\n      <table class=\"pth-rsp-tbl\">\r\n        <thead><tr><th>Device<\/th><th>Category<\/th><th>CSS width<\/th><th>CSS height<\/th><th>DPR<\/th><\/tr><\/thead>\r\n        <tbody id=\"pth-rsp-refbody\"><\/tbody>\r\n      <\/table>\r\n    <\/div>\r\n    <div class=\"pth-rsp-hint\">CSS width is the value your media queries respond to (not the raw pixel count). DPR is the device pixel ratio \u2014 a DPR of 3 means 3 physical pixels per CSS pixel.<\/div>\r\n  <\/div>\r\n<\/div>\r\n\r\n<div class=\"pth-rsp-toast\" id=\"pth-rsp-toast\"><\/div>\r\n<\/div>\r\n\r\n<script data-no-optimize=\"1\" data-no-minify=\"1\" data-cfasync=\"false\">\r\nwindow.pthResponsiveStudioApp = (function () {\r\n    'use strict';\r\n\r\n    var root = null;\r\n    var SAMPLE = ''\r\n        + '<div style=\"font-family:system-ui,sans-serif;padding:24px;color:#0f172a\">'\r\n        + '<h1 style=\"color:#2563eb;margin:0 0 8px\">Responsive Demo<\/h1>'\r\n        + '<p style=\"color:#475569\">Resize the viewport to watch this layout adapt.<\/p>'\r\n        + '<div style=\"display:grid;grid-template-columns:repeat(auto-fit,minmax(120px,1fr));gap:12px;margin-top:16px\">'\r\n        + '<div style=\"background:#e0e7ff;padding:22px;border-radius:8px;text-align:center;font-weight:700\">Box 1<\/div>'\r\n        + '<div style=\"background:#dcfce7;padding:22px;border-radius:8px;text-align:center;font-weight:700\">Box 2<\/div>'\r\n        + '<div style=\"background:#fef9c3;padding:22px;border-radius:8px;text-align:center;font-weight:700\">Box 3<\/div>'\r\n        + '<div style=\"background:#fee2e2;padding:22px;border-radius:8px;text-align:center;font-weight:700\">Box 4<\/div>'\r\n        + '<\/div><\/div>';\r\n\r\n    var DEVICES = [\r\n        { name: 'iPhone SE', cat: 'Phone', w: 375, h: 667, dpr: 2 },\r\n        { name: 'iPhone 14 \/ 15', cat: 'Phone', w: 390, h: 844, dpr: 3 },\r\n        { name: 'iPhone 15 Pro Max', cat: 'Phone', w: 430, h: 932, dpr: 3 },\r\n        { name: 'Pixel 7', cat: 'Phone', w: 412, h: 915, dpr: 2.6 },\r\n        { name: 'Galaxy S22', cat: 'Phone', w: 360, h: 780, dpr: 3 },\r\n        { name: 'iPad Mini', cat: 'Tablet', w: 768, h: 1024, dpr: 2 },\r\n        { name: 'iPad Air', cat: 'Tablet', w: 820, h: 1180, dpr: 2 },\r\n        { name: 'iPad Pro 11', cat: 'Tablet', w: 834, h: 1194, dpr: 2 },\r\n        { name: 'iPad Pro 12.9', cat: 'Tablet', w: 1024, h: 1366, dpr: 2 },\r\n        { name: 'Surface Duo', cat: 'Tablet', w: 540, h: 720, dpr: 2.5 },\r\n        { name: 'Laptop 13\"', cat: 'Laptop', w: 1280, h: 800, dpr: 2 },\r\n        { name: 'Laptop 15\"', cat: 'Laptop', w: 1440, h: 900, dpr: 2 },\r\n        { name: 'Desktop HD', cat: 'Desktop', w: 1920, h: 1080, dpr: 1 },\r\n        { name: 'Desktop QHD', cat: 'Desktop', w: 2560, h: 1440, dpr: 1 }\r\n    ];\r\n\r\n    var TW = [\r\n        { n: 'base', min: 0 }, { n: 'sm', min: 640 }, { n: 'md', min: 768 },\r\n        { n: 'lg', min: 1024 }, { n: 'xl', min: 1280 }, { n: '2xl', min: 1536 }\r\n    ];\r\n    var BS = [\r\n        { n: 'xs', min: 0 }, { n: 'sm', min: 576 }, { n: 'md', min: 768 },\r\n        { n: 'lg', min: 992 }, { n: 'xl', min: 1200 }, { n: 'xxl', min: 1400 }\r\n    ];\r\n\r\n    var state = {\r\n        source: 'url',\r\n        url: '',\r\n        html: SAMPLE,\r\n        view: 'single',\r\n        zoom: 'fit',\r\n        device: DEVICES[1],\r\n        compareDevice: DEVICES[10],\r\n        orient: 'portrait',\r\n        customW: 390,\r\n        customH: 844\r\n    };\r\n\r\n    function $(sel) { return root.querySelector(sel); }\r\n    function byId(id) { return document.getElementById(id); }\r\n\r\n    function toast(msg) {\r\n        var t = byId('pth-rsp-toast');\r\n        if (!t) { return; }\r\n        t.textContent = msg;\r\n        t.className = 'pth-rsp-toast pth-rsp-tshow';\r\n        window.setTimeout(function () { t.className = 'pth-rsp-toast'; }, 2200);\r\n    }\r\n\r\n    function activeDims(dev) {\r\n        var w = dev.w, h = dev.h;\r\n        if (state.orient === 'landscape') { var t = w; w = h; h = t; }\r\n        return { w: w, h: h };\r\n    }\r\n\r\n    function zoomFactor(w) {\r\n        if (state.zoom === '100') { return 1; }\r\n        if (state.zoom === '75') { return 0.75; }\r\n        if (state.zoom === '50') { return 0.5; }\r\n        var stage = byId('pth-rsp-stage');\r\n        var avail = stage ? (stage.clientWidth - 60) : 900;\r\n        if (state.view === 'compare') { avail = avail \/ 2 - 24; }\r\n        if (w <= avail) { return 1; }\r\n        var f = avail \/ w;\r\n        if (f < 0.25) { f = 0.25; }\r\n        return f;\r\n    }\r\n\r\n    function makeFrame(dev) {\r\n        var d = activeDims(dev);\r\n        var f = zoomFactor(d.w);\r\n        var wrap = document.createElement('div');\r\n        wrap.className = 'pth-rsp-frame';\r\n        wrap.style.width = Math.round(d.w * f) + 'px';\r\n\r\n        var bar = document.createElement('div');\r\n        bar.className = 'pth-rsp-fbar';\r\n        var nm = document.createElement('span');\r\n        nm.textContent = dev.name;\r\n        var rs = document.createElement('span');\r\n        rs.textContent = d.w + ' x ' + d.h + (f < 1 ? '  (' + Math.round(f * 100) + '%)' : '');\r\n        bar.appendChild(nm);\r\n        bar.appendChild(rs);\r\n        wrap.appendChild(bar);\r\n\r\n        var scaleBox = document.createElement('div');\r\n        scaleBox.style.width = Math.round(d.w * f) + 'px';\r\n        scaleBox.style.height = Math.round(d.h * f) + 'px';\r\n        scaleBox.style.overflow = 'hidden';\r\n\r\n        var frame = document.createElement('iframe');\r\n        frame.setAttribute('title', 'Preview ' + dev.name);\r\n        frame.setAttribute('sandbox', 'allow-same-origin allow-scripts allow-forms allow-popups');\r\n        frame.style.width = d.w + 'px';\r\n        frame.style.height = d.h + 'px';\r\n        frame.style.transform = 'scale(' + f + ')';\r\n        frame.style.transformOrigin = 'top left';\r\n\r\n        if (state.source === 'url' && state.url) {\r\n            frame.setAttribute('src', state.url);\r\n        } else {\r\n            frame.setAttribute('srcdoc', state.html);\r\n        }\r\n        scaleBox.appendChild(frame);\r\n        wrap.appendChild(scaleBox);\r\n        return wrap;\r\n    }\r\n\r\n    function renderPreview() {\r\n        var stage = byId('pth-rsp-stage');\r\n        if (!stage) { return; }\r\n        stage.innerHTML = '';\r\n        if (state.view === 'grid') {\r\n            var i;\r\n            for (i = 0; i < DEVICES.length; i++) { stage.appendChild(makeFrame(DEVICES[i])); }\r\n        } else if (state.view === 'compare') {\r\n            stage.appendChild(makeFrame(state.device));\r\n            stage.appendChild(makeFrame(state.compareDevice));\r\n        } else {\r\n            stage.appendChild(makeFrame(state.device));\r\n        }\r\n    }\r\n\r\n    function buildDeviceChips() {\r\n        var box = byId('pth-rsp-devchips');\r\n        if (!box) { return; }\r\n        box.innerHTML = '';\r\n        var i;\r\n        for (i = 0; i < DEVICES.length; i++) {\r\n            (function (dev) {\r\n                var b = document.createElement('button');\r\n                b.className = 'pth-rsp-chip' + (dev === state.device ? ' pth-rsp-chipon' : '');\r\n                b.textContent = dev.name + ' (' + dev.w + ')';\r\n                b.addEventListener('click', function () {\r\n                    state.device = dev;\r\n                    state.customW = dev.w; state.customH = dev.h;\r\n                    var cw = byId('pth-rsp-cw'), ch = byId('pth-rsp-ch');\r\n                    if (cw) { cw.value = dev.w; } if (ch) { ch.value = dev.h; }\r\n                    markChips();\r\n                    renderPreview();\r\n                });\r\n                box.appendChild(b);\r\n            })(DEVICES[i]);\r\n        }\r\n    }\r\n\r\n    function markChips() {\r\n        var chips = root.querySelectorAll('#pth-rsp-devchips .pth-rsp-chip');\r\n        var i;\r\n        for (i = 0; i < chips.length; i++) {\r\n            chips[i].className = 'pth-rsp-chip' + (chips[i].textContent.indexOf(state.device.name + ' (') === 0 ? ' pth-rsp-chipon' : '');\r\n        }\r\n    }\r\n\r\n    function fillDeviceSelect(sel, selected) {\r\n        if (!sel) { return; }\r\n        sel.innerHTML = '';\r\n        var i;\r\n        for (i = 0; i < DEVICES.length; i++) {\r\n            var o = document.createElement('option');\r\n            o.value = String(i);\r\n            o.textContent = DEVICES[i].name + ' - ' + DEVICES[i].w + 'x' + DEVICES[i].h;\r\n            if (DEVICES[i] === selected) { o.selected = true; }\r\n            sel.appendChild(o);\r\n        }\r\n    }\r\n\r\n    function initTabs() {\r\n        var tabs = root.querySelectorAll('.pth-rsp-tab');\r\n        var i;\r\n        for (i = 0; i < tabs.length; i++) {\r\n            tabs[i].addEventListener('click', function () {\r\n                var name = this.getAttribute('data-tab');\r\n                var all = root.querySelectorAll('.pth-rsp-tab');\r\n                var j;\r\n                for (j = 0; j < all.length; j++) { all[j].className = 'pth-rsp-tab'; }\r\n                this.className = 'pth-rsp-tab pth-rsp-on';\r\n                var panels = root.querySelectorAll('.pth-rsp-panel');\r\n                for (j = 0; j < panels.length; j++) { panels[j].className = 'pth-rsp-panel'; }\r\n                var p = byId('pth-rsp-panel-' + name);\r\n                if (p) { p.className = 'pth-rsp-panel pth-rsp-show'; }\r\n                if (name === 'preview') { renderPreview(); }\r\n                if (name === 'bp') { renderBpStage(); }\r\n            });\r\n        }\r\n    }\r\n\r\n    function seg(id, attr, cb) {\r\n        var box = byId(id);\r\n        if (!box) { return; }\r\n        var btns = box.querySelectorAll('button');\r\n        var i;\r\n        for (i = 0; i < btns.length; i++) {\r\n            btns[i].addEventListener('click', function () {\r\n                var b = box.querySelectorAll('button'), j;\r\n                for (j = 0; j < b.length; j++) { b[j].className = ''; }\r\n                this.className = 'pth-rsp-segon';\r\n                cb(this.getAttribute(attr));\r\n            });\r\n        }\r\n    }\r\n\r\n    function initPreview() {\r\n        seg('pth-rsp-srcseg', 'data-src', function (v) {\r\n            state.source = v;\r\n            byId('pth-rsp-srcurl').style.display = (v === 'url') ? 'block' : 'none';\r\n            byId('pth-rsp-srccode').style.display = (v === 'code') ? 'block' : 'none';\r\n            renderPreview();\r\n        });\r\n        seg('pth-rsp-viewseg', 'data-view', function (v) {\r\n            state.view = v;\r\n            byId('pth-rsp-cmpwrap').style.display = (v === 'compare') ? 'block' : 'none';\r\n            renderPreview();\r\n        });\r\n        seg('pth-rsp-zoomseg', 'data-zoom', function (v) { state.zoom = v; renderPreview(); });\r\n\r\n        byId('pth-rsp-loadurl').addEventListener('click', function () {\r\n            var u = byId('pth-rsp-url').value.replace(\/^\\s+|\\s+$\/g, '');\r\n            if (u && u.indexOf('http') !== 0) { u = 'https:\/\/' + u; }\r\n            state.url = u; state.source = 'url';\r\n            renderPreview();\r\n            toast('Loading ' + (u || 'URL'));\r\n        });\r\n        byId('pth-rsp-rendercode').addEventListener('click', function () {\r\n            state.html = byId('pth-rsp-code').value || SAMPLE;\r\n            state.source = 'code';\r\n            renderPreview(); renderBpStage();\r\n            toast('Rendered your code');\r\n        });\r\n        byId('pth-rsp-loadsample').addEventListener('click', function () {\r\n            byId('pth-rsp-code').value = SAMPLE;\r\n            state.html = SAMPLE; state.source = 'code';\r\n            renderPreview();\r\n            toast('Sample loaded');\r\n        });\r\n        byId('pth-rsp-rotate').addEventListener('click', function () {\r\n            state.orient = (state.orient === 'portrait') ? 'landscape' : 'portrait';\r\n            renderPreview();\r\n            toast(state.orient === 'landscape' ? 'Landscape' : 'Portrait');\r\n        });\r\n        byId('pth-rsp-applycustom').addEventListener('click', function () {\r\n            var w = parseInt(byId('pth-rsp-cw').value, 10);\r\n            var h = parseInt(byId('pth-rsp-ch').value, 10);\r\n            if (!w || w < 200) { w = 390; } if (!h || h < 200) { h = 844; }\r\n            state.device = { name: 'Custom', cat: 'Custom', w: w, h: h, dpr: 1 };\r\n            markChips(); renderPreview();\r\n        });\r\n        fillDeviceSelect(byId('pth-rsp-cmpdev'), state.compareDevice);\r\n        byId('pth-rsp-cmpdev').addEventListener('change', function () {\r\n            state.compareDevice = DEVICES[parseInt(this.value, 10)];\r\n            renderPreview();\r\n        });\r\n        buildDeviceChips();\r\n        renderPreview();\r\n        window.addEventListener('resize', function () {\r\n            if (state.zoom === 'fit') { renderPreview(); }\r\n        });\r\n    }\r\n\r\n    \/* ---- TAB 2 ---- *\/\r\n    function activeBp(list, w) {\r\n        var name = list[0].n, i;\r\n        for (i = 0; i < list.length; i++) { if (w >= list[i].min) { name = list[i].n; } }\r\n        return name;\r\n    }\r\n    function renderBpSets(w) {\r\n        var mk = function (boxId, list) {\r\n            var box = byId(boxId);\r\n            if (!box) { return; }\r\n            box.innerHTML = '';\r\n            var act = activeBp(list, w), i;\r\n            for (i = 0; i < list.length; i++) {\r\n                var d = document.createElement('div');\r\n                d.className = 'pth-rsp-bp' + (list[i].n === act ? ' pth-rsp-bpon' : '');\r\n                var b = document.createElement('b'); b.textContent = list[i].n;\r\n                var s = document.createElement('span'); s.textContent = list[i].min === 0 ? '< next' : '>= ' + list[i].min + 'px';\r\n                d.appendChild(b); d.appendChild(s); box.appendChild(d);\r\n            }\r\n        };\r\n        mk('pth-rsp-bptw', TW);\r\n        mk('pth-rsp-bpbs', BS);\r\n    }\r\n    function renderBpStage() {\r\n        var stage = byId('pth-rsp-bpstage');\r\n        if (!stage) { return; }\r\n        var w = parseInt(byId('pth-rsp-bpslider').value, 10);\r\n        stage.innerHTML = '';\r\n        var dev = { name: w + 'px wide', cat: '', w: w, h: 380, dpr: 1 };\r\n        var save = state.orient; state.orient = 'portrait';\r\n        stage.appendChild(makeFrame(dev));\r\n        state.orient = save;\r\n    }\r\n    function initBreakpoints() {\r\n        var sl = byId('pth-rsp-bpslider');\r\n        var upd = function () {\r\n            var w = parseInt(sl.value, 10);\r\n            byId('pth-rsp-bpwidth').textContent = w + ' px';\r\n            renderBpSets(w);\r\n        };\r\n        sl.addEventListener('input', upd);\r\n        sl.addEventListener('change', function () { renderBpStage(); });\r\n        byId('pth-rsp-parsecss').addEventListener('click', function () {\r\n            var css = byId('pth-rsp-css').value || '';\r\n            var re = \/@media[^{]*\\(\\s*(?:min|max)-width\\s*:\\s*(\\d+)\\s*px\/gi;\r\n            var found = {}, m;\r\n            while ((m = re.exec(css)) !== null) { found[parseInt(m[1], 10)] = true; }\r\n            var list = [];\r\n            for (var k in found) { if (found.hasOwnProperty(k)) { list.push(parseInt(k, 10)); } }\r\n            list.sort(function (a, b) { return a - b; });\r\n            var box = byId('pth-rsp-cssbp');\r\n            box.innerHTML = '';\r\n            if (!list.length) {\r\n                var e = document.createElement('div'); e.className = 'pth-rsp-hint';\r\n                e.textContent = 'No min-width or max-width media queries found in that CSS.';\r\n                box.appendChild(e); return;\r\n            }\r\n            var w = parseInt(sl.value, 10), i;\r\n            for (i = 0; i < list.length; i++) {\r\n                var on = w >= list[i];\r\n                var d = document.createElement('div');\r\n                d.className = 'pth-rsp-bp' + (on ? ' pth-rsp-bpon' : '');\r\n                var b = document.createElement('b'); b.textContent = list[i] + 'px';\r\n                var s = document.createElement('span'); s.textContent = on ? 'active now' : 'inactive';\r\n                d.appendChild(b); d.appendChild(s); box.appendChild(d);\r\n            }\r\n            toast(list.length + ' breakpoint(s) found');\r\n        });\r\n        renderBpSets(parseInt(sl.value, 10));\r\n    }\r\n\r\n    \/* ---- TAB 3 ---- *\/\r\n    function ri(cls, txt) {\r\n        var d = document.createElement('div');\r\n        d.className = 'pth-rsp-ri ' + cls;\r\n        var ic = document.createElement('span');\r\n        ic.textContent = cls === 'ok' ? '\u2714' : (cls === 'warn' ? '\u26a0' : '\u2715');\r\n        var sp = document.createElement('span'); sp.textContent = txt;\r\n        d.appendChild(ic); d.appendChild(sp); return d;\r\n    }\r\n    function initViewportChecker() {\r\n        byId('pth-rsp-checkmeta').addEventListener('click', function () {\r\n            var out = byId('pth-rsp-metaout');\r\n            out.innerHTML = '';\r\n            var src = byId('pth-rsp-metain').value || '';\r\n            if (!src.replace(\/^\\s+|\\s+$\/g, '')) { out.appendChild(ri('warn', 'Paste some HTML first.')); return; }\r\n            var doc;\r\n            try { doc = new DOMParser().parseFromString(src, 'text\/html'); }\r\n            catch (e) { out.appendChild(ri('bad', 'Could not parse that HTML.')); return; }\r\n            var metas = doc.querySelectorAll('meta[name]');\r\n            var vp = null, i;\r\n            for (i = 0; i < metas.length; i++) {\r\n                if ((metas[i].getAttribute('name') || '').toLowerCase() === 'viewport') { vp = metas[i]; break; }\r\n            }\r\n            if (!vp) {\r\n                out.appendChild(ri('bad', 'No viewport meta tag found. Mobile browsers will render your page at a desktop width and zoom out.'));\r\n                showRecommended(out);\r\n                return;\r\n            }\r\n            var content = (vp.getAttribute('content') || '').toLowerCase();\r\n            out.appendChild(ri('ok', 'A viewport meta tag is present.'));\r\n            if (content.indexOf('width=device-width') !== -1) {\r\n                out.appendChild(ri('ok', 'width=device-width is set, so the layout matches the real screen width.'));\r\n            } else {\r\n                out.appendChild(ri('bad', 'width=device-width is missing. Without it the page will not size to the device.'));\r\n            }\r\n            if (\/initial-scale\\s*=\\s*1\/.test(content)) {\r\n                out.appendChild(ri('ok', 'initial-scale=1 is set.'));\r\n            } else {\r\n                out.appendChild(ri('warn', 'initial-scale=1 is not set. It is recommended so the page starts un-zoomed.'));\r\n            }\r\n            if (content.indexOf('user-scalable=no') !== -1) {\r\n                out.appendChild(ri('bad', 'user-scalable=no blocks pinch-zoom. This is an accessibility problem and should be removed.'));\r\n            }\r\n            var mx = content.match(\/maximum-scale\\s*=\\s*([0-9.]+)\/);\r\n            if (mx && parseFloat(mx[1]) < 2) {\r\n                out.appendChild(ri('warn', 'maximum-scale is ' + mx[1] + ', which limits zoom. Allow at least 2 for accessibility.'));\r\n            }\r\n            showRecommended(out);\r\n        });\r\n    }\r\n    function showRecommended(out) {\r\n        var lbl = document.createElement('div');\r\n        lbl.className = 'pth-rsp-hint'; lbl.style.marginTop = '12px';\r\n        lbl.textContent = 'Recommended tag:';\r\n        var code = document.createElement('div');\r\n        code.className = 'pth-rsp-code';\r\n        code.textContent = '<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">';\r\n        out.appendChild(lbl); out.appendChild(code);\r\n    }\r\n\r\n    \/* ---- TAB 4 ---- *\/\r\n    function initScreenshot() {\r\n        fillDeviceSelect(byId('pth-rsp-shotdev'), state.device);\r\n        byId('pth-rsp-capture').addEventListener('click', function () {\r\n            var sel = byId('pth-rsp-shotdev');\r\n            var dev = DEVICES[parseInt(sel.value, 10)];\r\n            var out = byId('pth-rsp-shotout');\r\n            out.innerHTML = '';\r\n            var w = dev.w, h = dev.h;\r\n            var body = state.html;\r\n            var svg = ''\r\n                + '<svg xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"' + w + '\" height=\"' + h + '\">'\r\n                + '<foreignObject width=\"100%\" height=\"100%\">'\r\n                + '<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\" style=\"width:' + w + 'px;height:' + h + 'px;overflow:hidden;background:#ffffff\">'\r\n                + body\r\n                + '<\/div><\/foreignObject><\/svg>';\r\n            var img = new Image();\r\n            img.onload = function () {\r\n                try {\r\n                    var c = document.createElement('canvas');\r\n                    c.width = w; c.height = h;\r\n                    var ctx = c.getContext('2d');\r\n                    ctx.fillStyle = '#ffffff'; ctx.fillRect(0, 0, w, h);\r\n                    ctx.drawImage(img, 0, 0);\r\n                    var url = c.toDataURL('image\/png');\r\n                    var a = document.createElement('a');\r\n                    a.href = url;\r\n                    a.download = 'responsive-' + dev.name.replace(\/[^a-z0-9]+\/gi, '-').toLowerCase() + '-' + w + 'x' + h + '.png';\r\n                    a.className = 'pth-rsp-btn';\r\n                    a.style.display = 'inline-block';\r\n                    a.textContent = 'Download PNG (' + w + 'x' + h + ')';\r\n                    var prev = document.createElement('img');\r\n                    prev.src = url; prev.style.maxWidth = '100%'; prev.style.border = '1px solid #cbd5e1';\r\n                    prev.style.borderRadius = '8px'; prev.style.marginTop = '12px'; prev.style.display = 'block';\r\n                    out.appendChild(a); out.appendChild(prev);\r\n                    toast('Screenshot ready');\r\n                } catch (err) {\r\n                    out.appendChild(ri('bad', 'This content could not be rasterized in the browser (usually an external or cross-origin image). Try self-contained HTML with inline styles.'));\r\n                }\r\n            };\r\n            img.onerror = function () {\r\n                out.appendChild(ri('bad', 'The HTML could not be turned into an image. Make sure it is well-formed and self-contained.'));\r\n            };\r\n            img.src = 'data:image\/svg+xml;charset=utf-8,' + encodeURIComponent(svg);\r\n        });\r\n    }\r\n\r\n    \/* ---- TAB 5 ---- *\/\r\n    function renderRef() {\r\n        var body = byId('pth-rsp-refbody');\r\n        if (!body) { return; }\r\n        var q = (byId('pth-rsp-refsearch').value || '').toLowerCase();\r\n        var cat = byId('pth-rsp-refcat').value;\r\n        body.innerHTML = '';\r\n        var i, shown = 0;\r\n        for (i = 0; i < DEVICES.length; i++) {\r\n            var d = DEVICES[i];\r\n            if (cat !== 'all' && d.cat !== cat) { continue; }\r\n            if (q && d.name.toLowerCase().indexOf(q) === -1) { continue; }\r\n            var tr = document.createElement('tr');\r\n            var c1 = document.createElement('td'); c1.innerHTML = '';\r\n            var strong = document.createElement('strong'); strong.textContent = d.name; c1.appendChild(strong);\r\n            var c2 = document.createElement('td');\r\n            var chip = document.createElement('span'); chip.className = 'pth-rsp-cat'; chip.textContent = d.cat; c2.appendChild(chip);\r\n            var c3 = document.createElement('td'); c3.textContent = d.w + ' px';\r\n            var c4 = document.createElement('td'); c4.textContent = d.h + ' px';\r\n            var c5 = document.createElement('td'); c5.textContent = d.dpr + 'x';\r\n            tr.appendChild(c1); tr.appendChild(c2); tr.appendChild(c3); tr.appendChild(c4); tr.appendChild(c5);\r\n            body.appendChild(tr); shown++;\r\n        }\r\n        if (!shown) {\r\n            var tr2 = document.createElement('tr');\r\n            var td = document.createElement('td'); td.setAttribute('colspan', '5');\r\n            td.style.textAlign = 'center'; td.style.color = '#475569'; td.textContent = 'No devices match.';\r\n            tr2.appendChild(td); body.appendChild(tr2);\r\n        }\r\n    }\r\n    function initReference() {\r\n        byId('pth-rsp-refsearch').addEventListener('input', renderRef);\r\n        byId('pth-rsp-refcat').addEventListener('change', renderRef);\r\n        renderRef();\r\n    }\r\n\r\n    function init() {\r\n        root = document.getElementById('pth-rsp-studio-wrapper');\r\n        if (!root || root.getAttribute('data-pth-init') === '1') { return; }\r\n        root.setAttribute('data-pth-init', '1');\r\n        initTabs();\r\n        initPreview();\r\n        initBreakpoints();\r\n        initViewportChecker();\r\n        initScreenshot();\r\n        initReference();\r\n    }\r\n\r\n    return { init: init };\r\n})();\r\n\r\n\/* 4-layer bootstrap (LiteSpeed-safe) *\/\r\n(function () {\r\n    function boot() {\r\n        if (window.pthResponsiveStudioApp && document.getElementById('pth-rsp-studio-wrapper')) {\r\n            window.pthResponsiveStudioApp.init();\r\n        }\r\n    }\r\n    if (document.readyState === 'complete' || document.readyState === 'interactive') { window.setTimeout(boot, 1); }\r\n    document.addEventListener('DOMContentLoaded', boot);\r\n    window.addEventListener('load', boot);\r\n    window.setTimeout(boot, 900);\r\n})();\r\n<\/script>\n\n\n\n<style>\n.pth-feature-wrap { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 20px; margin-bottom: 30px; }\n.pth-feat-box { border: 1px solid #e2e8f0; background: #ffffff; padding: 24px; border-radius: 12px; box-shadow: 0 4px 6px -1px rgba(0,0,0,0.02); transition: all 0.3s ease; }\n.pth-feat-box:hover { border-color: #bfdbfe; transform: translateY(-3px); box-shadow: 0 10px 15px -3px rgba(0,0,0,0.05); }\n.pth-feat-title { font-size: 1.1rem; font-weight: 800; color: #0f172a; margin-bottom: 10px; display: flex; align-items: center; gap: 10px; }\n.pth-feat-text { font-size: 0.9rem; color: #475569; line-height: 1.6; margin: 0; }\n.pth-steps-wrap { border: 1px solid #e2e8f0; background: #ffffff; padding: 40px 30px; border-radius: 16px; text-align: center; box-shadow: 0 4px 6px -1px rgba(0,0,0,0.02); margin-bottom: 40px; }\n.pth-steps-title { font-size: 1.2rem; font-weight: 800; color: #1e293b; text-transform: uppercase; margin-bottom: 35px; letter-spacing: 1px; }\n.pth-steps-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 30px; }\n.pth-step-item { display: flex; flex-direction: column; align-items: center; }\n.pth-step-num { width: 45px; height: 45px; background: #3b82f6; color: #ffffff; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-weight: 800; font-size: 1.2rem; margin-bottom: 15px; box-shadow: 0 4px 10px rgba(59,130,246,0.3); }\n.pth-step-name { font-weight: 800; color: #0f172a; margin-bottom: 8px; font-size: 1.05rem; }\n.pth-step-desc { font-size: 0.9rem; color: #64748b; line-height: 1.5; margin: 0; }\n<\/style>\n<div class=\"pth-feature-wrap\">\n    <div class=\"pth-feat-box\">\n        <div class=\"pth-feat-title\">\ud83d\udfe2 Iframe Viewport Scaling<\/div>\n        <p class=\"pth-feat-text\">The Responsive Website Tester executes mathematically precise CSS transforms to simulate high-resolution hardware dimensions on limited physical screens.<\/p>\n    <\/div>\n    <div class=\"pth-feat-box\">\n        <div class=\"pth-feat-title\">\ud83d\udd35 Dual-Device Comparison<\/div>\n        <p class=\"pth-feat-text\">Initiate multiple sandboxed rendering engines simultaneously to debug cascading style sheets across conflicting media queries in real-time.<\/p>\n    <\/div>\n    <div class=\"pth-feat-box\">\n        <div class=\"pth-feat-title\">\ud83d\udfe3 Client-Side Execution<\/div>\n        <p class=\"pth-feat-text\">This toolkit relies entirely on the local browser document object model, allowing frontend developers to inspect localhost URLs without external server proxying.<\/p>\n    <\/div>\n<\/div>\n<div class=\"pth-steps-wrap\">\n    <div class=\"pth-steps-title\">How to Use the Responsive Website Tester<\/div>\n    <div class=\"pth-steps-grid\">\n        <div class=\"pth-step-item\">\n            <div class=\"pth-step-num\">1<\/div>\n            <div class=\"pth-step-name\">Inject Target URL<\/div>\n            <p class=\"pth-step-desc\">Enter your production domain or local development server address into the primary input vector.<\/p>\n        <\/div>\n        <div class=\"pth-step-item\">\n            <div class=\"pth-step-num\">2<\/div>\n            <div class=\"pth-step-name\">Define Dimensions<\/div>\n            <p class=\"pth-step-desc\">Select a predefined hardware breakpoint or manually assign custom pixel boundaries for the viewport.<\/p>\n        <\/div>\n        <div class=\"pth-step-item\">\n            <div class=\"pth-step-num\">3<\/div>\n            <div class=\"pth-step-name\">Analyze Rendering<\/div>\n            <p class=\"pth-step-desc\">Observe the CSS layout shifts and JavaScript DOM mutations as the layout scales dynamically.<\/p>\n        <\/div>\n        <div class=\"pth-step-item\">\n            <div class=\"pth-step-num\">4<\/div>\n            <div class=\"pth-step-name\">Compare &#038; Debug<\/div>\n            <p class=\"pth-step-desc\">Activate the split-screen mode to compare structural integrity between mobile and desktop configurations simultaneously.<\/p>\n        <\/div>\n    <\/div>\n<\/div>\n\n\n<div id=\"start-seo-article\"><\/div>\n\n\n<div id=\"start-seo-article\"><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Last updated: July 2026<\/p>\n\n\n\n<h2 id=\"\ud83d\udd34-five-checks-one-screen\" class=\"wp-block-heading\">\ud83d\udd34&nbsp;<strong>Five checks, one screen<\/strong><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The studio is built around the five things you actually do when checking a layout. The Live Preview tab renders a page at real device widths, either from a URL or from HTML you paste in. The Breakpoint Inspector lets you drag a width slider and see exactly which CSS breakpoint is active at any pixel value. The Viewport Meta Checker reads your page head and tells you whether the one tag that controls mobile rendering is set correctly. The Screenshot Export turns your pasted layout into a PNG you can drop into a ticket or a review. And the Device Reference is a quick lookup for the CSS widths and pixel ratios of common phones, tablets, and laptops.<\/p>\n\n\n\n<h2 id=\"\ud83d\udfe1-a-real-workflow-start-to-finish\" class=\"wp-block-heading\">\ud83d\udfe1&nbsp;<strong>A real workflow, start to finish<\/strong><\/h2>\n\n\n<figure class=\"pth-article-figure pth-img-left\" style=\"float:left; width:700px; max-width:100%; margin:4px 28px 16px 0; clear:left;\"><img decoding=\"async\" src=\"https:\/\/schoolict.net\/tools\/wp-content\/uploads\/2026\/07\/responsive-tester-workflow-800x447.jpeg\" alt=\"Testing a web page across phone, tablet and laptop widths in the browser\" width=\"700\" height=\"394\" loading=\"lazy\" data-no-lazy=\"1\" class=\"pth-article-img\" style=\"width:100%;height:auto;display:block;border-radius:10px;border:1px solid #e2e8f0;\"><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Say a client says your page &#8220;looks off&#8221; on their phone but fine on your monitor. Start in Live Preview: paste your page&#8217;s HTML, or load the URL if the site allows framing, and switch to a phone size like 390 wide. Input a 390&nbsp;px viewport; output is the page exactly as a modern iPhone would lay it out, so the broken spot is visible immediately. Now open the Breakpoint Inspector and drag the slider to 390. It highlights which framework breakpoint is active there, and if you paste your CSS it lists your own media-query widths and marks which ones apply. Nine times out of ten the bug is a layout rule that only kicks in above a breakpoint your phone never reaches.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Before you blame the CSS, check the Viewport Meta tab. Paste your page head; if the viewport tag is missing or set to a fixed width, the phone is rendering at desktop width and zooming out, which looks exactly like a responsive bug but is a one-line fix. Once it looks right, use Screenshot Export to capture the corrected layout at that device size and attach it to your reply. If the fix touches page weight or layout shift, run the result through the <a href=\"https:\/\/schoolict.net\/tools\/free-offline-pagespeed-code-analyzer\/\" rel=\"noreferrer noopener\" target=\"_blank\">PageSpeed Code Analyzer<\/a>, and if you want to edit the markup live rather than just preview it, the <a href=\"https:\/\/schoolict.net\/tools\/offline-html-editor-with-css-js\/\" rel=\"noreferrer noopener\" target=\"_blank\">Offline HTML Editor<\/a> is the companion tool.<\/p>\n\n\n\n<h2 id=\"\ud83d\udfe2-what-browser-testing-cannot-do\" class=\"wp-block-heading\">\ud83d\udfe2&nbsp;<strong>What browser testing cannot do<\/strong><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Being clear about the edges saves frustration. A browser preview is an accurate size simulation, not a real device: it will not reproduce a specific phone&#8217;s fonts, its touch behaviour, or a quirk in one manufacturer&#8217;s browser. For final sign-off on a critical page, a real handset still matters.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>\ud83d\udd35 <strong>Some URLs will not load.<\/strong> Many large sites send an X-Frame-Options or CSP rule that blocks being shown inside another page. If the URL preview stays blank, that is the site refusing to be framed, not a fault in the tool. Paste the page&#8217;s HTML instead and it will always render.<\/li>\n\n\n\n<li>\ud83d\udfe0 <strong>Screenshots suit self-contained code.<\/strong> Capture works by rasterising your pasted HTML in the browser. External images without CORS permission and cross-origin URLs cannot be turned into an image locally, which is a browser security limit, not a bug.<\/li>\n\n\n\n<li>\ud83d\udfe3 <strong>Sizes are CSS pixels, not raw pixels.<\/strong> The widths shown are the values your media queries respond to. A device with a pixel ratio of 3 has three times as many physical pixels, which the Device Reference tab lays out for you.<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">If you want the reasoning underneath all of this, why one meta tag decides mobile rendering, how CSS pixels differ from device pixels, and how breakpoints and fluid units actually work, it is covered in the companion guide on <a href=\"https:\/\/schoolict.net\/tools\/responsive-web-design-viewport-breakpoints-guide\/\" target=\"_blank\" rel=\"noreferrer noopener\">how responsive web design works<\/a><\/p>\n\n\n\n<style>\n.pth-faq-section{margin:50px auto 40px;font-family:inherit;max-width:1480px;padding:0 20px;box-sizing:border-box}\n.pth-faq-header{font-size:1.8rem;font-weight:800;color:#0f172a;margin-bottom:25px;border-bottom:2px solid #e2e8f0;padding-bottom:10px;display:flex;align-items:center;gap:10px}\n.pth-faq-grid{display:grid;grid-template-columns:1fr;gap:20px}\n@media(min-width:768px){.pth-faq-grid{grid-template-columns:repeat(2,1fr)}}\n@media(min-width:1024px){.pth-faq-grid{grid-template-columns:repeat(3,1fr)}}\n.pth-faq-card{background:#f8fafc;padding:24px;border-radius:12px;border:1px solid #e2e8f0;transition:transform .2s ease;break-inside:avoid}\n.pth-faq-card:hover{transform:translateY(-3px);box-shadow:0 4px 12px rgba(0,0,0,.05)}\n.pth-faq-q{color:#0f172a;font-size:1rem;font-weight:700;margin:0 0 12px;line-height:1.4}\n.pth-faq-a{margin:0;font-size:.95rem;color:#1e293b;line-height:1.6;font-weight:500}\n<\/style>\n<div class=\"pth-faq-section\">\n  <div class=\"pth-faq-header\">\u2753 Frequently Asked Questions<\/div>\n  <div class=\"pth-faq-grid\">\n    <div class=\"pth-faq-card\"><p class=\"pth-faq-q\">Why is my URL preview blank?<\/p><p class=\"pth-faq-a\">That site blocks being shown inside another page with an X-Frame-Options or CSP rule. It is a server setting, not a fault here. Switch to Paste Code mode, which always renders.<\/p><\/div>\n    <div class=\"pth-faq-card\"><p class=\"pth-faq-q\">Is this the same as testing on a real phone?<\/p><p class=\"pth-faq-a\">It is an accurate size and layout simulation, which catches most responsive bugs early. For final sign-off, a real device still matters for fonts, touch, and browser quirks.<\/p><\/div>\n    <div class=\"pth-faq-card\"><p class=\"pth-faq-q\">Does my code or URL get uploaded?<\/p><p class=\"pth-faq-a\">No. Everything runs in your browser tab. Pasted code and typed URLs stay on your device, so you can test private or unreleased pages safely.<\/p><\/div>\n    <div class=\"pth-faq-card\"><p class=\"pth-faq-q\">What width should I test first?<\/p><p class=\"pth-faq-a\">Start around 390px, a common modern phone. Then check a tablet near 768px and a laptop near 1280px. Those three widths surface most layout breakage.<\/p><\/div>\n    <div class=\"pth-faq-card\"><p class=\"pth-faq-q\">Why does the screenshot sometimes fail?<\/p><p class=\"pth-faq-a\">The browser cannot rasterise external or cross-origin images for security reasons. Screenshots work best with self-contained HTML and inline CSS.<\/p><\/div>\n    <div class=\"pth-faq-card\"><p class=\"pth-faq-q\">What is device pixel ratio (DPR)?<\/p><p class=\"pth-faq-a\">It is how many physical pixels sit in one CSS pixel. A DPR of 3 means a 390px-wide phone actually has 1170 hardware pixels. Your CSS responds to the 390.<\/p><\/div>\n    <div class=\"pth-faq-card\"><p class=\"pth-faq-q\">Can it show all devices at once?<\/p><p class=\"pth-faq-a\">Yes. The Live Preview tab has an &#8220;All devices&#8221; view that renders the page across every listed size in a grid, plus a two-up compare mode.<\/p><\/div>\n    <div class=\"pth-faq-card\"><p class=\"pth-faq-q\">How do I know which breakpoint is active?<\/p><p class=\"pth-faq-a\">Open the Breakpoint Inspector and drag the width slider. It highlights the active Tailwind and Bootstrap breakpoint, and parses any breakpoints in your own pasted CSS.<\/p><\/div>\n  <\/div>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Responsive Website Tester with Mobile Simulator Test your website&#8217;s responsiveness across multiple devices instantly. Use our free online mobile simulator to preview your site on iPhones, Androids, and tablets securely.Use now Responsive Website Tester \ud83d\udfe2 Iframe Viewport Scaling The Responsive Website Tester executes mathematically precise CSS transforms to simulate high-resolution hardware dimensions on limited physical &#8230; <a title=\"Free Responsive Website Tester &amp; Mobile Simulator\" class=\"read-more\" href=\"https:\/\/schoolict.net\/tools\/responsive-website-tester-pro\/\" aria-label=\"Read more about Free Responsive Website Tester &amp; Mobile Simulator\">Read more<\/a><\/p>\n","protected":false},"author":1,"featured_media":2292,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-2286","page","type-page","status-publish","has-post-thumbnail"],"_links":{"self":[{"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/pages\/2286","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/comments?post=2286"}],"version-history":[{"count":0,"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/pages\/2286\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/media\/2292"}],"wp:attachment":[{"href":"https:\/\/schoolict.net\/tools\/wp-json\/wp\/v2\/media?parent=2286"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}