Changeset 3763637
- Timestamp:
- 10/24/2026 06:25:14 PM (18 hours ago)
- Location:
- indiatvdna-turbo-cache-lite/trunk
- Files:
-
- 93 added
- 5 edited
-
assets/admin-search.js (added)
-
assets/admin.css (modified) (2 diffs)
-
assets/admin.js (modified) (1 diff)
-
assets/browser-public-probe.js (added)
-
assets/live-monitor.css (added)
-
assets/live-monitor.js (added)
-
assets/settings-search-index.json (added)
-
assets/worker-image-fallback.js (added)
-
changelog.txt (added)
-
dropins (added)
-
dropins/advanced-cache-runtime.php (added)
-
dropins/advanced-cache.php (added)
-
dropins/object-cache-runtime.php (added)
-
dropins/object-cache.php (added)
-
includes/bootstrap-admin-light.php (added)
-
includes/bootstrap-full.php (added)
-
includes/bootstrap-recovery.php (added)
-
includes/bootstrap-rest-lite.php (added)
-
includes/bootstrap-router.php (added)
-
includes/bootstrap-runtime-loader.php (added)
-
includes/bootstrap-runtime-plan.php (added)
-
includes/class-itdna-adaptive-intelligence.php (added)
-
includes/class-itdna-admin.php (added)
-
includes/class-itdna-advanced-optimization.php (added)
-
includes/class-itdna-asset-optimizer.php (added)
-
includes/class-itdna-auto-cookie-probe.php (added)
-
includes/class-itdna-auto-optimizer.php (added)
-
includes/class-itdna-background-load-governor.php (added)
-
includes/class-itdna-benchmark-lab.php (added)
-
includes/class-itdna-cache-engine.php (added)
-
includes/class-itdna-cache-fallback-diagnostics.php (added)
-
includes/class-itdna-cdn.php (added)
-
includes/class-itdna-central-dependency-queue.php (added)
-
includes/class-itdna-change-impact-analyzer.php (added)
-
includes/class-itdna-cloudflare.php (added)
-
includes/class-itdna-css-engine.php (added)
-
includes/class-itdna-css-safe-release.php (added)
-
includes/class-itdna-database.php (added)
-
includes/class-itdna-diagnostic-journal.php (added)
-
includes/class-itdna-direct-static.php (added)
-
includes/class-itdna-easy-auto-setup.php (added)
-
includes/class-itdna-filesystem.php (added)
-
includes/class-itdna-fragment-cache.php (added)
-
includes/class-itdna-frontend.php (added)
-
includes/class-itdna-full-option-diagnostics.php (added)
-
includes/class-itdna-generated-image-registry.php (added)
-
includes/class-itdna-hosting-guard.php (added)
-
includes/class-itdna-image-optimizer.php (added)
-
includes/class-itdna-input-guard.php (added)
-
includes/class-itdna-intelligence.php (added)
-
includes/class-itdna-js-engine.php (added)
-
includes/class-itdna-layer-test.php (added)
-
includes/class-itdna-lite-upgrade.php (added)
-
includes/class-itdna-litespeed-integration.php (added)
-
includes/class-itdna-live-activity-monitor.php (added)
-
includes/class-itdna-low-load-engine.php (added)
-
includes/class-itdna-master-control.php (added)
-
includes/class-itdna-object-cache.php (added)
-
includes/class-itdna-optimization-ownership.php (added)
-
includes/class-itdna-optimizer.php (added)
-
includes/class-itdna-orphan-cache-cleaner.php (added)
-
includes/class-itdna-parity-suite.php (added)
-
includes/class-itdna-performance-engine.php (added)
-
includes/class-itdna-performance-extensions.php (added)
-
includes/class-itdna-preload-engine.php (added)
-
includes/class-itdna-privacy.php (added)
-
includes/class-itdna-pro-lab.php (added)
-
includes/class-itdna-production-guards.php (added)
-
includes/class-itdna-public-probe.php (added)
-
includes/class-itdna-real-image-pool.php (added)
-
includes/class-itdna-regression-suite.php (added)
-
includes/class-itdna-rollback-manager.php (added)
-
includes/class-itdna-safe-auto-settings.php (added)
-
includes/class-itdna-scale-intelligence.php (added)
-
includes/class-itdna-scheduler-gate.php (added)
-
includes/class-itdna-server-telemetry.php (added)
-
includes/class-itdna-site-profiler.php (added)
-
includes/class-itdna-state-store.php (added)
-
includes/class-itdna-strict-event-scheduler.php (added)
-
includes/class-itdna-superfast-safety.php (added)
-
includes/class-itdna-telemetry-guard.php (added)
-
includes/class-itdna-theme-compat.php (added)
-
includes/class-itdna-turbo-cache.php (added)
-
includes/class-itdna-universal-delivery.php (added)
-
includes/class-itdna-woocommerce-safety.php (added)
-
includes/class-itdna-workers-assets.php (added)
-
indiatvdna-turbo-cache.php (modified) (2 diffs)
-
readme.txt (modified) (1 diff)
-
tools (added)
-
tools/browser-audit (added)
-
tools/browser-audit/README.txt (added)
-
tools/browser-audit/audit.cjs (added)
-
tools/browser-audit/cache-probe.cjs (added)
-
tools/browser-audit/compare-cache.cjs (added)
-
tools/browser-audit/compare.cjs (added)
-
tools/browser-audit/package.json (added)
-
tools/browser-audit/recommend.cjs (added)
-
uninstall.php (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
indiatvdna-turbo-cache-lite/trunk/assets/admin.css
r3729643 r3763637 1 .itdna-wrap{margin:0 0 0 -20px; background:#f4f7fb;min-height:calc(100vh - 32px);font-family:Inter,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;color:#172033}.itdna-shell{display:grid;grid-template-columns:245px minmax(0,1fr);min-height:calc(100vh - 32px)}.itdna-sidebar{background:#0b1731;color:#fff;padding:24px 14px;position:sticky;top:32px;height:calc(100vh - 32px);box-sizing:border-box;overflow:auto}.itdna-brand{display:flex;gap:11px;align-items:center;padding:0 10px 12px}.itdna-logo{display:grid;place-items:center;width:42px;height:42px;border-radius:13px;background:linear-gradient(135deg,#ffb000,#ff5c00);box-shadow:0 10px 24px rgba(255,122,0,.25);font-size:22px}.itdna-brand div{display:flex;flex-direction:column;line-height:1.15}.itdna-brand b{font-size:11px;letter-spacing:.12em;color:#8ba6d4;text-transform:uppercase}.itdna-brand strong{font-size:18px}.itdna-version{margin:0 10px 20px;padding:8px 10px;border-radius:8px;background:#102447;color:#93abd0;font-size:11px}.itdna-sidebar nav{display:flex;flex-direction:column;gap:4px}.itdna-sidebar nav a{display:flex;gap:10px;align-items:center;color:#aebfda;text-decoration:none;padding:10px 11px;border-radius:9px;font-size:13px;font-weight:600;transition:.15s}.itdna-sidebar nav a:hover,.itdna-sidebar nav a.active{background:#152b52;color:#fff}.itdna-sidebar nav a.active{box-shadow:inset 3px 0 #5aa3ff}.itdna-sidebar nav a span{width:18px;text-align:center}.itdna-side-status{margin:18px 10px 0;padding:11px;border-top:1px solid #21365c;color:#9fb2ce;font-size:12px}.dot{display:inline-block;width:8px;height:8px;border-radius:50%;background:#6b7891;margin-right:6px}.dot.on{background:#30d59d;box-shadow:0 0 0 4px rgba(48,213,157,.12)}.itdna-main{padding:28px 34px 90px;max-width:1250px;width:100%;box-sizing:border-box}.itdna-top{display:flex;justify-content:space-between;align-items:center;margin-bottom:20px}.itdna-top h1{font-size:29px;margin:0;color:#121a2c}.itdna-top p{margin:6px 0 0;color:#71809a}.itdna-inline-form{display:inline-block;margin:0 6px 6px 0}.itdna-notice{padding:12px 15px;border-radius:10px;margin:0 0 18px;border:1px solid}.itdna-notice.success{background:#edfff7;border-color:#b6efd6;color:#11653f}.itdna-notice.error{background:#fff1f1;border-color:#ffc9c9;color:#9c2828}.itdna-grid-4{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:14px;margin-bottom:16px}.itdna-metric,.itdna-card{background:#fff;border:1px solid #e3e9f2;border-radius:14px;box-shadow:0 4px 18px rgba(35,55,90,.045)}.itdna-metric{padding:17px 18px}.itdna-metric span{font-size:12px;color:#8090aa;font-weight:700;text-transform:uppercase;letter-spacing:.04em}.itdna-metric strong{display:block;font-size:23px;margin:7px 0 3px;color:#15213a}.itdna-metric small{color:#7f8ca2}.itdna-card{margin-bottom:16px}.itdna-card-head{padding:18px 20px;border-bottom:1px solid #edf1f6}.itdna-card-head h2{font-size:17px;margin:0;color:#17233b}.itdna-card-head p{margin:5px 0 0;color:#7c89a0;font-size:13px}.itdna-card-body{padding:18px 20px}.itdna-toggle-row{display:flex;justify-content:space-between;gap:20px;align-items:center;padding:13px 0;border-bottom:1px solid #eff3f7}.itdna-toggle-row:last-child{border-bottom:0}.itdna-toggle-row span:first-child{display:flex;flex-direction:column;gap:4px}.itdna-toggle-row strong,.itdna-field strong{font-size:14px;color:#17233b}.itdna-toggle-row small,.itdna-field small{display:block;color:#8290a7;font-size:12px;font-weight:400;line-height:1.4}.itdna-risk{font-style:normal;font-size:10px;font-weight:700;color:#a76300;background:#fff4d7;border:1px solid #ffe5a0;border-radius:999px;padding:2px 7px;width:max-content}.itdna-switch{position:relative;min-width:44px;height:24px}.itdna-switch input{position:absolute;opacity:0}.itdna-switch i{position:absolute;inset:0;background:#c8d1df;border-radius:999px;cursor:pointer;transition:.2s}.itdna-switch i:after{content:"";position:absolute;width:18px;height:18px;left:3px;top:3px;background:#fff;border-radius:50%;box-shadow:0 2px 4px rgba(0,0,0,.2);transition:.2s}.itdna-switch input:checked+i{background:#2f80ed}.itdna-switch input:checked+i:after{transform:translateX(20px)}.itdna-field{margin:0 0 15px}.itdna-field label{display:block}.itdna-field input[type=text],.itdna-field input[type=url],.itdna-field input[type=password],.itdna-field input[type=number],.itdna-field textarea,.itdna-field select{margin-top:8px;width:100%;max-width:760px;border:1px solid #cfd8e6;border-radius:8px;min-height:40px;padding:8px 10px;background:#fff;box-shadow:none}.itdna-field textarea{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px}.itdna-checklist{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px}.itdna-checklist div{padding:11px 12px;border-radius:9px;background:#f6fbff;color:#365273;border:1px solid #e4f1ff}.itdna-actions{display:flex;flex-wrap:wrap;gap:4px}.itdna-help,.itdna-info{color:#738198;font-size:12px}.itdna-db-row{display:flex;align-items:center;gap:10px;padding:12px 4px;border-bottom:1px solid #edf1f6}.itdna-db-row input{margin:0}.itdna-db-row span{display:flex;gap:7px;align-items:baseline}.itdna-db-row small{color:#8896ac}.itdna-savebar{position:sticky;bottom:0;display:flex;justify-content:space-between;align-items:center;padding:12px 16px;background:rgba(255,255,255,.96);backdrop-filter:blur(8px);border:1px solid #dfe7f1;border-radius:12px;box-shadow:0 -4px 20px rgba(29,44,73,.08);z-index:20}.itdna-savebar span{color:#748198;font-size:12px}.itdna-diagnostic{display:grid;grid-template-columns:12px minmax(180px,1fr) minmax(220px,2fr);align-items:center;gap:10px;padding:11px 2px;border-bottom:1px solid #edf1f6}.itdna-diagnostic .status{width:9px;height:9px;border-radius:50%;background:#abb5c6}.itdna-diagnostic .status.ok{background:#26bf83}.itdna-diagnostic .status.warn{background:#ffb020}.itdna-diagnostic .status.bad{background:#ef5b5b}.itdna-diagnostic small{color:#8290a7}@media(max-width:1000px){.itdna-shell{grid-template-columns:190px 1fr}.itdna-main{padding:22px}.itdna-grid-4{grid-template-columns:repeat(2,1fr)}.itdna-checklist{grid-template-columns:1fr}}@media(max-width:782px){.itdna-wrap{margin-left:-10px}.itdna-shell{display:block}.itdna-sidebar{position:relative;top:auto;height:auto}.itdna-sidebar nav{display:grid;grid-template-columns:repeat(2,1fr)}.itdna-main{padding:16px}.itdna-top{align-items:flex-start;gap:10px}.itdna-grid-4{grid-template-columns:1fr}.itdna-diagnostic{grid-template-columns:12px 1fr}.itdna-diagnostic small{grid-column:2}.itdna-savebar{bottom:0}.itdna-checklist{grid-template-columns:1fr}}1 .itdna-wrap{margin:0 0 0 -20px;padding:10px 0 0 10px;background:#f4f7fb;min-height:calc(100vh - 32px);box-sizing:border-box;font-family:Inter,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;color:#172033}.itdna-shell{display:grid;grid-template-columns:245px minmax(0,1fr);column-gap:10px;min-height:calc(100vh - 42px)}.itdna-sidebar{background:linear-gradient(180deg,#0b1731 0%,#0a1630 100%);color:#fff;padding:24px 14px;position:sticky;top:42px;height:calc(100vh - 52px);box-sizing:border-box;overflow:auto;border-radius:16px;box-shadow:0 10px 28px rgba(16,34,66,.12);border:1px solid rgba(255,255,255,.06)}.itdna-brand{display:flex;gap:11px;align-items:center;padding:0 10px 12px}.itdna-logo{display:grid;place-items:center;width:42px;height:42px;border-radius:13px;background:linear-gradient(135deg,#ffb000,#ff5c00);box-shadow:0 10px 24px rgba(255,122,0,.25);font-size:22px}.itdna-brand div{display:flex;flex-direction:column;line-height:1.15}.itdna-brand b{font-size:11px;letter-spacing:.12em;color:#8ba6d4;text-transform:uppercase}.itdna-brand strong{font-size:18px}.itdna-version{margin:0 10px 20px;padding:8px 10px;border-radius:8px;background:#102447;color:#93abd0;font-size:11px}.itdna-sidebar nav{display:flex;flex-direction:column;gap:4px}.itdna-sidebar nav a{display:flex;gap:10px;align-items:center;color:#aebfda;text-decoration:none;padding:10px 11px;border-radius:9px;font-size:13px;font-weight:600;transition:.15s}.itdna-sidebar nav a:hover,.itdna-sidebar nav a.active{background:#152b52;color:#fff}.itdna-sidebar nav a.active{box-shadow:inset 3px 0 #5aa3ff}.itdna-sidebar nav a span{width:18px;text-align:center}.itdna-side-status{margin:18px 10px 0;padding:11px;border-top:1px solid #21365c;color:#9fb2ce;font-size:12px}.dot{display:inline-block;width:8px;height:8px;border-radius:50%;background:#6b7891;margin-right:6px}.dot.on{background:#30d59d;box-shadow:0 0 0 4px rgba(48,213,157,.12)}.itdna-main{padding:28px 34px 90px;max-width:1250px;width:100%;box-sizing:border-box}.itdna-top{display:flex;justify-content:space-between;align-items:center;margin-bottom:20px}.itdna-top h1{font-size:29px;margin:0;color:#121a2c}.itdna-top p{margin:6px 0 0;color:#71809a}.itdna-inline-form{display:inline-block;margin:0 6px 6px 0}.itdna-notice{padding:12px 15px;border-radius:10px;margin:0 0 18px;border:1px solid}.itdna-notice.success{background:#edfff7;border-color:#b6efd6;color:#11653f}.itdna-notice.error{background:#fff1f1;border-color:#ffc9c9;color:#9c2828}.itdna-grid-4{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:14px;margin-bottom:16px}.itdna-metric,.itdna-card{background:#fff;border:1px solid #e3e9f2;border-radius:14px;box-shadow:0 4px 18px rgba(35,55,90,.045)}.itdna-metric{padding:17px 18px}.itdna-metric span{font-size:12px;color:#8090aa;font-weight:700;text-transform:uppercase;letter-spacing:.04em}.itdna-metric strong{display:block;font-size:23px;margin:7px 0 3px;color:#15213a}.itdna-metric small{color:#7f8ca2}.itdna-card{margin-bottom:16px}.itdna-card-head{padding:18px 20px;border-bottom:1px solid #edf1f6}.itdna-card-head h2{font-size:17px;margin:0;color:#17233b}.itdna-card-head p{margin:5px 0 0;color:#7c89a0;font-size:13px}.itdna-card-body{padding:18px 20px}.itdna-toggle-row{display:flex;justify-content:space-between;gap:20px;align-items:center;padding:13px 0;border-bottom:1px solid #eff3f7}.itdna-toggle-row:last-child{border-bottom:0}.itdna-toggle-row span:first-child{display:flex;flex-direction:column;gap:4px}.itdna-toggle-row strong,.itdna-field strong{font-size:14px;color:#17233b}.itdna-toggle-row small,.itdna-field small{display:block;color:#8290a7;font-size:12px;font-weight:400;line-height:1.4}.itdna-risk{font-style:normal;font-size:10px;font-weight:700;color:#a76300;background:#fff4d7;border:1px solid #ffe5a0;border-radius:999px;padding:2px 7px;width:max-content}.itdna-switch{position:relative;min-width:44px;height:24px}.itdna-switch input{position:absolute;opacity:0}.itdna-switch i{position:absolute;inset:0;background:#c8d1df;border-radius:999px;cursor:pointer;transition:.2s}.itdna-switch i:after{content:"";position:absolute;width:18px;height:18px;left:3px;top:3px;background:#fff;border-radius:50%;box-shadow:0 2px 4px rgba(0,0,0,.2);transition:.2s}.itdna-switch input:checked+i{background:#2f80ed}.itdna-switch input:checked+i:after{transform:translateX(20px)}.itdna-field{margin:0 0 15px}.itdna-field label{display:block}.itdna-field input[type=text],.itdna-field input[type=url],.itdna-field input[type=password],.itdna-field input[type=number],.itdna-field textarea,.itdna-field select{margin-top:8px;width:100%;max-width:760px;border:1px solid #cfd8e6;border-radius:8px;min-height:40px;padding:8px 10px;background:#fff;box-shadow:none}.itdna-field textarea{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px}.itdna-checklist{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px}.itdna-checklist div{padding:11px 12px;border-radius:9px;background:#f6fbff;color:#365273;border:1px solid #e4f1ff}.itdna-actions{display:flex;flex-wrap:wrap;gap:4px}.itdna-help,.itdna-info{color:#738198;font-size:12px}.itdna-db-row{display:flex;align-items:center;gap:10px;padding:12px 4px;border-bottom:1px solid #edf1f6}.itdna-db-row input{margin:0}.itdna-db-row span{display:flex;gap:7px;align-items:baseline}.itdna-db-row small{color:#8896ac}.itdna-savebar{position:sticky;bottom:0;display:flex;justify-content:space-between;align-items:center;padding:12px 16px;background:rgba(255,255,255,.96);backdrop-filter:blur(8px);border:1px solid #dfe7f1;border-radius:12px;box-shadow:0 -4px 20px rgba(29,44,73,.08);z-index:20}.itdna-savebar span{color:#748198;font-size:12px}.itdna-diagnostic{display:grid;grid-template-columns:12px minmax(180px,1fr) minmax(220px,2fr);align-items:center;gap:10px;padding:11px 2px;border-bottom:1px solid #edf1f6}.itdna-diagnostic .status{width:9px;height:9px;border-radius:50%;background:#abb5c6}.itdna-diagnostic .status.ok{background:#26bf83}.itdna-diagnostic .status.info{background:#6f86a8}.itdna-diagnostic .status.warn{background:#ffb020}.itdna-diagnostic .status.bad{background:#ef5b5b}.itdna-diagnostic small{color:#8290a7}@media(max-width:1000px){.itdna-wrap{padding-left:8px;padding-top:8px}.itdna-shell{grid-template-columns:190px 1fr;column-gap:8px}.itdna-sidebar{top:40px;height:calc(100vh - 48px)}.itdna-main{padding:22px}.itdna-grid-4{grid-template-columns:repeat(2,1fr)}.itdna-checklist{grid-template-columns:1fr}}@media(max-width:782px){.itdna-wrap{margin-left:-10px;padding-left:6px;padding-top:6px}.itdna-shell{display:block}.itdna-sidebar{position:relative;top:auto;height:auto;border-radius:14px}.itdna-sidebar nav{display:grid;grid-template-columns:repeat(2,1fr)}.itdna-main{padding:16px}.itdna-top{align-items:flex-start;gap:10px}.itdna-grid-4{grid-template-columns:1fr}.itdna-diagnostic{grid-template-columns:12px 1fr}.itdna-diagnostic small{grid-column:2}.itdna-savebar{bottom:0}.itdna-checklist{grid-template-columns:1fr}} 2 2 3 3 .itdna-engine-note{padding:12px 14px;border-radius:10px;background:#f6f9ff;border:1px solid #e2ebfa;color:#52627a}.itdna-diagnostic strong{font-weight:700}.itdna-diagnostic small{line-height:1.45}.itdna-card .button-primary{box-shadow:0 5px 14px rgba(47,128,237,.14)} … … 189 189 190 190 191 192 /* Lite-only Full-style upgrade presentation */ 193 .itdna-sidebar nav a{position:relative} 194 .itdna-sidebar nav a.is-pro-tab b{margin-left:auto;font-size:8px;line-height:1;padding:4px 5px;border-radius:999px;background:#eef2ff;color:#4f46e5;letter-spacing:.05em} 195 .itdna-sidebar nav a.is-pro-tab.active b{background:rgba(255,255,255,.18);color:#fff} 196 .itdna-mini-pro{display:inline-flex;margin-left:5px;padding:2px 5px;border-radius:999px;background:#fff2cd;color:#936400;font-size:9px;line-height:1;font-weight:800} 197 .itdna-metric.is-pro{border-color:#ead9aa;background:linear-gradient(180deg,#fffdf7,#fff)} 198 .itdna-pro-preview-head{display:flex;align-items:center;justify-content:space-between;gap:22px;padding:20px 22px;margin-bottom:12px;border-radius:14px;background:linear-gradient(135deg,#071a38,#173b69);box-shadow:0 8px 26px rgba(22,43,75,.08);color:#fff} 199 .itdna-pro-preview-head h2{margin:5px 0 7px;color:#fff;font-size:20px!important;line-height:1.2!important}.itdna-pro-preview-head p{margin:0;max-width:780px;color:#c8d8ec;font-size:12px!important;line-height:1.5!important} 200 .itdna-pro-badge{display:inline-flex;padding:5px 9px;border-radius:999px;background:#ffbd2e;color:#3a2a00;font-size:10px;font-weight:900;letter-spacing:.08em} 201 .itdna-preview-note{margin:0 0 15px;padding:11px 14px;border:1px solid #f0d99b;border-radius:10px;background:#fff9e8;color:#6e581c;font-size:11.5px;line-height:1.45} 202 .itdna-card-title-row{display:flex;align-items:center;justify-content:space-between;gap:14px}.itdna-pro-pill{display:inline-flex;padding:4px 8px;border-radius:999px;background:#171f2e;color:#fff;font-size:9px;font-weight:900;letter-spacing:.08em}.itdna-pro-card{border-top:3px solid #dca928} 203 .itdna-feature-list{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px}.itdna-feature-list>div{display:flex;gap:9px;align-items:flex-start;padding:11px 12px;border:1px solid #e7ebf0;border-radius:9px;background:#fafbfd}.itdna-feature-list>div>span{width:20px;height:20px;border-radius:50%;display:grid;place-items:center;flex:none;background:#dff6e9;color:#168154;font-weight:900}.itdna-feature-list p{margin:1px 0 0;color:#4d5c70;font-size:12px;line-height:1.45} 204 .itdna-card-upgrade{display:flex;align-items:center;justify-content:space-between;gap:14px;margin-top:16px;padding:12px 14px;border-radius:10px;background:#f7f9fc;border:1px solid #e4e9f0}.itdna-card-upgrade span{font-weight:700;color:#45536a;font-size:12px} 205 .itdna-comparison{display:grid;grid-template-columns:1fr 1fr;gap:14px}.itdna-plan-box{border:1px solid #dfe5ed;border-radius:12px;padding:18px;background:#fff}.itdna-plan-box.featured{border:2px solid #2271b1;background:#f7fbff}.itdna-plan-label{display:inline-flex;padding:4px 8px;border-radius:999px;background:#edf1f5;color:#56677d;font-size:10px;font-weight:900;letter-spacing:.08em}.itdna-plan-box.featured .itdna-plan-label{background:#2271b1;color:#fff}.itdna-plan-box h3{font-size:16px!important;margin:10px 0}.itdna-plan-box ul{margin:0 0 16px 18px}.itdna-plan-box li{font-size:12px;line-height:1.45;margin:6px 0;color:#4f6075} 206 .itdna-impact-disclaimer{margin:0 0 14px;padding:10px 12px;border:1px solid #d8e7f6;border-radius:9px;background:#f6fbff;color:#4b627c;font-size:11.5px;line-height:1.5}.itdna-impact{margin-top:14px;padding:10px 12px;border-radius:9px;background:#eff8f3;border:1px solid #cce8d8;color:#285b42;font-size:11.5px;line-height:1.45} 207 .itdna-upgrade-hint{display:grid;grid-template-columns:auto minmax(0,1fr) auto;gap:9px;align-items:start;margin:8px 0 12px;padding:9px 11px;border:1px solid #eadfb7;border-radius:9px;background:#fffaf0;color:#5a4b1f;font-size:11.5px;line-height:1.45}.itdna-upgrade-hint .itdna-mini-pro{margin:1px 0 0}.itdna-upgrade-hint a{font-weight:700;text-decoration:none;white-space:nowrap}.itdna-upgrade-hint small{font-size:11px;color:#756738} 208 .itdna-pro-setting>a{flex:0 0 auto}.itdna-pro-db-row{opacity:.82}.itdna-result-banner{display:flex;flex-direction:column;gap:3px;margin:10px 0;padding:10px 12px;border:1px solid #dfe7f0;border-radius:9px;background:#f7f9fc}.itdna-result-banner.ok{background:#effcf6;border-color:#c9efdd;color:#155f42}.itdna-result-banner.warn{background:#fff8e9;border-color:#f4dfac;color:#7c5900}.itdna-result-banner small{font-size:11.5px;line-height:1.45} 209 @media(max-width:900px){.itdna-pro-preview-head{display:block}.itdna-pro-preview-head .button{margin-top:14px}.itdna-feature-list,.itdna-comparison{grid-template-columns:1fr}.itdna-card-upgrade{align-items:flex-start;flex-direction:column}} 210 @media(max-width:782px){.itdna-upgrade-hint{grid-template-columns:auto 1fr}.itdna-upgrade-hint>a{grid-column:2}} 191 /* v2.5.34 AR-6 asset-report visual hierarchy */ 192 .itdna-asset-report{display:grid;gap:14px;margin:14px 0 2px} 193 .itdna-asset-section{overflow:hidden;border:1px solid #e2e9f2;border-radius:12px;background:#fff} 194 .itdna-asset-section-head{display:flex;align-items:center;justify-content:space-between;gap:14px;padding:13px 15px;border-bottom:1px solid #e9eef5;background:#f8fafc} 195 .itdna-asset-section-head>div{min-width:0} 196 .itdna-asset-kicker{display:block;margin-bottom:2px;color:#75849a;font-size:9.5px;font-weight:800;letter-spacing:.075em;text-transform:uppercase} 197 .itdna-asset-section-head h3{margin:0;color:#17233b;font-size:14px;line-height:1.3;font-weight:650} 198 .itdna-integrity-badge{display:inline-flex;align-items:center;gap:6px;flex:0 0 auto;padding:5px 8px;border:1px solid;border-radius:999px;font-size:10px;line-height:1.2;font-weight:700;white-space:nowrap} 199 .itdna-integrity-badge span{font-weight:600;opacity:.76} 200 .itdna-integrity-badge strong{font-size:10px!important;line-height:1.2!important;font-weight:800!important;letter-spacing:.03em!important} 201 .itdna-integrity-badge.is-pass{border-color:#b9ead5;background:#effbf5;color:#177451} 202 .itdna-integrity-badge.is-fail{border-color:#ffcaca;background:#fff1f1;color:#a12f2f} 203 .itdna-integrity-badge.is-pending{border-color:#d8e1ec;background:#f5f7fa;color:#66758a} 204 .itdna-asset-grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:8px;padding:10px} 205 .itdna-asset-stat{min-width:0;min-height:78px;padding:10px 11px;border:1px solid #e4ebf3;border-radius:9px;background:#fbfdff;box-sizing:border-box} 206 .itdna-asset-stat-label{display:block;color:#50617a;font-size:11px;line-height:1.35;font-weight:650} 207 .itdna-asset-stat-value{display:block!important;margin:5px 0 2px!important;color:#17345e!important;font-size:18px!important;line-height:1.05!important;font-weight:600!important;letter-spacing:-.01em!important} 208 .itdna-asset-stat small{display:block;color:#8693a6;font-size:10px;line-height:1.35} 209 .itdna-asset-stat.is-secondary{background:#fcfdff} 210 .itdna-asset-stat.is-pending .itdna-asset-stat-value{color:#98a3b3!important} 211 .itdna-asset-stat.is-zero{border-color:#e8edf3;background:#fafbfc} 212 .itdna-asset-stat.is-zero .itdna-asset-stat-value{color:#8b98aa!important;font-weight:500!important} 213 .itdna-asset-stat.is-zero .itdna-asset-stat-label,.itdna-asset-stat.is-zero small{color:#8a96a7} 214 .itdna-asset-summary{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px} 215 .itdna-asset-summary>div{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:11px 13px;border:1px solid #dce8f5;border-radius:10px;background:#f5f9ff} 216 .itdna-asset-summary span{color:#51637c;font-size:11px;font-weight:650} 217 .itdna-asset-summary strong{color:#17345e!important;font-size:16px!important;line-height:1.1!important;font-weight:600!important;white-space:nowrap} 218 @media(max-width:1100px){.itdna-asset-grid{grid-template-columns:repeat(2,minmax(0,1fr))}} 219 @media(max-width:650px){.itdna-asset-section-head{align-items:flex-start}.itdna-asset-grid,.itdna-asset-summary{grid-template-columns:1fr}.itdna-asset-stat{min-height:0}.itdna-asset-summary>div{align-items:flex-start;flex-direction:column;gap:4px}} 220 .itdna-asset-explainer{display:grid;gap:5px;margin:10px 0 12px;padding:10px 12px;border:1px solid #e4ebf3;border-radius:9px;background:#fafcff;color:#718098;font-size:11px;line-height:1.45} 221 .itdna-asset-explainer span{display:block} 222 .itdna-asset-explainer b{color:#465870;font-size:inherit!important;line-height:inherit!important;font-weight:700} 223 .itdna-info strong,.itdna-help strong{display:inline!important;font-size:inherit!important;line-height:inherit!important;font-weight:700!important;letter-spacing:0!important} 224 225 226 /* v2.5.36 compact optimizer ownership / compatibility status */ 227 .itdna-compat-status-grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:8px;margin-top:12px} 228 .itdna-compat-status{min-width:0;padding:10px 11px;border:1px solid #e4ebf3;border-radius:9px;background:#fbfdff} 229 .itdna-compat-label{display:block;margin-bottom:7px;color:#50617a;font-size:11px;line-height:1.3;font-weight:650} 230 .itdna-compat-badge{display:inline-flex;align-items:center;min-height:22px;padding:3px 8px;border:1px solid;border-radius:999px;font-size:10px;line-height:1.2;font-weight:750;white-space:nowrap} 231 .itdna-compat-badge.is-muted{border-color:#dfe5ed;background:#f5f7fa;color:#6f7d90} 232 .itdna-compat-badge.is-active{border-color:#b9ead5;background:#effbf5;color:#177451} 233 .itdna-compat-badge.is-owner{border-color:#c8ddf7;background:#f1f7ff;color:#255b9b} 234 .itdna-compat-badge.is-external{border-color:#ffe0a3;background:#fff8e8;color:#96620b} 235 .itdna-compat-status small{display:block;margin-top:6px;color:#8a96a7;font-size:10px;line-height:1.35} 236 @media(max-width:1000px){.itdna-compat-status-grid{grid-template-columns:repeat(2,minmax(0,1fr))}} 237 @media(max-width:560px){.itdna-compat-status-grid{grid-template-columns:1fr}} 238 /* v2.21 Safe Auto Settings */ 239 .itdna-plan-row small{display:block;opacity:.72;font-size:11px;font-weight:700;margin-bottom:3px;letter-spacing:.02em}.itdna-auto-hero-actions{gap:8px;flex-wrap:wrap}.itdna-diagnostic .status.ok{background:#22c55e}.itdna-diagnostic .status.warn{background:#f59e0b} 240 241 /* v2.23 Optimization Ownership Manager */ 242 .itdna-toggle-row.itdna-toggle-standby{border-color:#f0d49a;background:#fffdf7} 243 .itdna-owner-standby-badge{display:inline-flex!important;align-items:center;margin-top:6px!important;padding:3px 7px!important;border:1px solid #f2d08a!important;border-radius:999px!important;background:#fff7df!important;color:#8a5a09!important;font-size:9.5px!important;line-height:1.2!important;font-style:normal!important;font-weight:800!important;letter-spacing:.035em!important} 244 .itdna-owner-inline{display:grid;gap:7px;margin:-3px 0 12px;padding:10px 12px;border:1px solid #f1d59b;border-left:4px solid #e5a72f;border-radius:9px;background:#fffaf0;font-size:11px;line-height:1.45;color:#59677a} 245 .itdna-owner-inline strong{font-size:11px!important;line-height:1.4!important;color:#2d3b4f!important;font-weight:750!important} 246 .itdna-owner-inline-main,.itdna-owner-inline-why{display:block} 247 .itdna-owner-inline-why{padding-top:6px;border-top:1px dashed #ecd9b3} 248 .itdna-owner-inline-actions{display:flex;align-items:center;gap:10px;flex-wrap:wrap;padding-top:2px} 249 .itdna-owner-inline-actions .button{font-size:11px!important;min-height:28px!important;line-height:26px!important;padding:0 10px!important} 250 .itdna-owner-inline-actions small{flex:1;min-width:220px;color:#7b8798;font-size:10px!important;line-height:1.4!important} 251 .itdna-owner-situation{display:grid;gap:5px;margin:12px 0 4px;padding:10px 12px;border:1px solid #d8e5f4;border-radius:9px;background:#f7fbff;color:#52647d;font-size:11px;line-height:1.45} 252 .itdna-owner-situation>strong{font-size:11.5px!important;color:#214d82!important} 253 .itdna-owner-situation b{font-size:inherit!important;line-height:inherit!important;color:#34465d!important} 254 .itdna-owner-restore{margin-top:3px} 255 @media(max-width:650px){.itdna-owner-inline-actions{align-items:flex-start;flex-direction:column}.itdna-owner-inline-actions small{min-width:0}.itdna-owner-inline-actions .button{width:100%;text-align:center}} 256 257 .itdna-server-badge{display:inline-flex;align-items:center;margin:6px 6px 0 0;padding:3px 8px;border-radius:999px;font-size:10px;font-weight:800;letter-spacing:.03em;background:#eef2f7;color:#334155} 258 .itdna-server-recommended_on{background:#dcfce7;color:#166534}.itdna-server-background_only{background:#fef3c7;color:#92400e}.itdna-server-adaptive_off{background:#f1f5f9;color:#475569}.itdna-server-default_off{background:#f1f5f9;color:#475569}.itdna-server-conditional{background:#e0f2fe;color:#075985}.itdna-server-standby{background:#fef3c7;color:#92400e}.itdna-server-optional{background:#e0f2fe;color:#075985} 259 260 .itdna-server-advisory{margin:8px 0 14px;padding:10px 12px;border-radius:10px;font-size:12px;line-height:1.45;background:#fff7ed;border:1px solid #fed7aa;color:#7c2d12}.itdna-server-advisory.default_off,.itdna-server-advisory.adaptive_off{background:#f8fafc;border-color:#e2e8f0;color:#475569}.itdna-server-advisory.conditional{background:#f0f9ff;border-color:#bae6fd;color:#075985}.itdna-server-advisory.standby{background:#fffbeb;border-color:#fde68a;color:#92400e}.itdna-server-advisory.recommended_on{background:#f0fdf4;border-color:#bbf7d0;color:#166534} 261 262 .itdna-server-profile-card{border:1px solid #dbeafe}.itdna-server-profile-card .itdna-card-head{background:linear-gradient(135deg,#eff6ff,#f8fafc)} 263 264 265 /* v2.33.12 two-choice Auto Best launcher */ 266 body.itdna-modal-open{overflow:hidden} 267 .itdna-auto-choice-modal[hidden]{display:none!important}.itdna-auto-choice-modal{position:fixed;inset:0;z-index:100000;display:flex;align-items:center;justify-content:center;padding:24px;box-sizing:border-box}.itdna-auto-choice-backdrop{position:absolute;inset:0;background:rgba(8,20,42,.62);backdrop-filter:blur(3px)}.itdna-auto-choice-dialog{position:relative;z-index:1;width:min(920px,96vw);max-height:90vh;overflow:auto;background:#fff;border:1px solid #d9e3ef;border-radius:18px;box-shadow:0 24px 80px rgba(8,28,62,.28);padding:22px;box-sizing:border-box}.itdna-auto-choice-x{position:absolute;right:14px;top:12px;border:0;background:transparent;color:#64748b;font-size:28px;line-height:1;cursor:pointer}.itdna-auto-choice-head{padding:2px 32px 16px 2px}.itdna-auto-choice-head h2{margin:4px 0 7px;font-size:22px;line-height:1.25;color:#14213d}.itdna-auto-choice-head p{margin:0;color:#66758a;font-size:13px;line-height:1.55}.itdna-auto-choice-grid{display:grid;grid-template-columns:1fr 1fr;gap:14px}.itdna-auto-choice-card{appearance:none;width:100%;min-height:330px;text-align:left;border-radius:15px;padding:18px;border:2px solid;background:#fff;cursor:pointer;transition:transform .16s ease,box-shadow .16s ease,border-color .16s ease;display:flex;flex-direction:column;gap:10px;font-family:inherit}.itdna-auto-choice-card:hover{transform:translateY(-2px);box-shadow:0 10px 28px rgba(24,52,91,.12)}.itdna-auto-choice-card.is-green{border-color:#86d9ad;background:linear-gradient(180deg,#f1fcf6 0,#fff 54%)}.itdna-auto-choice-card.is-red{border-color:#f1aaaa;background:linear-gradient(180deg,#fff4f4 0,#fff 54%)}.itdna-auto-choice-card.is-green:hover{border-color:#22a45c}.itdna-auto-choice-card.is-red:hover{border-color:#d64d4d}.itdna-auto-choice-badge{display:inline-flex;align-self:flex-start;padding:4px 8px;border-radius:999px;font-size:10px;font-weight:850;letter-spacing:.04em}.is-green .itdna-auto-choice-badge{background:#d7f7e4;color:#13703c}.is-red .itdna-auto-choice-badge{background:#ffe0e0;color:#a72424}.itdna-auto-choice-card>strong{font-size:17px!important;line-height:1.3!important;color:#14213d!important}.itdna-auto-choice-card>p{margin:0;color:#526176;font-size:12.5px;line-height:1.55}.itdna-auto-choice-facts{display:grid;gap:5px;padding:10px 11px;border:1px solid #cfead9;border-radius:10px;background:#fff;color:#40536a;font-size:11px;line-height:1.42}.itdna-auto-choice-facts b{color:#193c2a}.itdna-auto-choice-warning{padding:11px 12px;border:1px solid #f4c3c3;border-radius:10px;background:#fff7f7;color:#8f2929;font-size:11.5px;line-height:1.5}.itdna-auto-choice-card em{margin-top:auto;color:#6b788a;font-size:10.5px;line-height:1.45;font-style:normal}.itdna-auto-choice-foot{display:flex;align-items:center;gap:12px;margin-top:16px;padding-top:14px;border-top:1px solid #e8edf3}.itdna-auto-choice-foot small{color:#7c899a;font-size:11px}.itdna-auto-choice-foot .button{margin-left:auto} 268 @media(max-width:760px){.itdna-auto-choice-modal{padding:10px}.itdna-auto-choice-dialog{padding:16px}.itdna-auto-choice-grid{grid-template-columns:1fr}.itdna-auto-choice-card{min-height:0}.itdna-auto-choice-foot{align-items:flex-start;flex-direction:column}.itdna-auto-choice-foot .button{margin-left:0;width:100%}} 269 .itdna-performance-flow-status{display:inline-flex;align-items:center;min-height:32px;color:#71809a;font-size:12px;margin-left:8px}.itdna-performance-flow-progress{margin-top:10px;height:6px;background:#e7edf7;border-radius:999px;overflow:hidden}.itdna-performance-flow-progress[hidden]{display:none}.itdna-performance-flow-progress>div{height:100%;width:0;background:#2f80ed;border-radius:999px;transition:width .3s ease} 270 271 /* v2.33.17 Zero-Touch Easy Auto Setup */ 272 .itdna-easy-setup{margin:0 0 16px;padding:18px;border:1px solid #d7e4f2;border-radius:14px;background:linear-gradient(180deg,#f8fbff,#fff);box-shadow:0 4px 18px rgba(24,52,91,.05)} 273 .itdna-easy-head{display:flex;align-items:flex-start;justify-content:space-between;gap:18px}.itdna-easy-head h2{margin:4px 0 6px;color:#14213d;font-size:20px;line-height:1.25}.itdna-easy-head p{max-width:940px;margin:0;color:#617089;font-size:12.5px;line-height:1.55}.itdna-easy-badge{flex:0 0 auto;padding:6px 9px;border-radius:999px;background:#e9f3ff;color:#215992;font-size:10px;font-weight:800;letter-spacing:.035em}.itdna-easy-setup[data-status="running"] .itdna-easy-badge{background:#e6f8ee;color:#167047}.itdna-easy-setup[data-status="complete"] .itdna-easy-badge{background:#dff7e9;color:#12683f}.itdna-easy-setup[data-status="attention"] .itdna-easy-badge,.itdna-easy-setup[data-status="superseded"] .itdna-easy-badge{background:#fff1db;color:#8a5700} 274 .itdna-easy-progress{height:8px;margin:14px 0 10px;overflow:hidden;border-radius:999px;background:#e8eef6}.itdna-easy-progress i{display:block;height:100%;border-radius:999px;background:linear-gradient(90deg,#2d6cdf,#36a56f);transition:width .35s ease} 275 .itdna-easy-status{display:grid;grid-template-columns:auto auto 1fr;align-items:center;gap:9px;color:#52647d}.itdna-easy-status>strong{color:#1d3558;font-size:12px!important}.itdna-easy-status>span{padding:2px 7px;border-radius:999px;background:#edf3fb;color:#315a8e;font-size:10px;font-weight:800}.itdna-easy-status>p{grid-column:1/-1;margin:0;color:#6b788a;font-size:11.5px;line-height:1.45} 276 .itdna-easy-steps{display:grid;grid-template-columns:repeat(5,minmax(0,1fr));gap:7px;margin:12px 0}.itdna-easy-steps span{padding:7px 8px;border:1px solid #e1e8f1;border-radius:8px;background:#fbfdff;color:#617089;font-size:10px;font-weight:650;text-align:center} 277 .itdna-easy-compare{overflow:hidden;border:1px solid #e1e8f1;border-radius:10px;background:#fff}.itdna-easy-compare-head,.itdna-easy-compare-row{display:grid;grid-template-columns:1.5fr 1fr 1fr;gap:12px;align-items:center;padding:9px 11px}.itdna-easy-compare-head{background:#f6f9fd;border-bottom:1px solid #e1e8f1;color:#64748b;font-size:10px;font-weight:800;text-transform:uppercase;letter-spacing:.04em}.itdna-easy-compare-row{border-bottom:1px solid #edf1f6;color:#52647d;font-size:11px}.itdna-easy-compare-row:last-child{border-bottom:0}.itdna-easy-compare-row>strong{color:#193c68!important;font-size:12px!important;font-weight:750!important} 278 .itdna-easy-verdict{margin-top:12px;padding:10px 12px;border-radius:9px;font-size:11.5px;line-height:1.45}.itdna-easy-verdict.ok{border:1px solid #bfe8cf;background:#effaf4;color:#176b45}.itdna-easy-verdict.error{border:1px solid #f1c5c5;background:#fff4f4;color:#9b2d2d}.itdna-easy-verdict.info{border:1px solid #d8e3ef;background:#f7faff;color:#56687f}.itdna-easy-verdict[hidden]{display:none} 279 .itdna-easy-limitations{margin-top:10px;padding:10px 12px;border:1px solid #f0d6a6;border-radius:9px;background:#fffaf0;color:#74541b;font-size:11px;line-height:1.5}.itdna-easy-limitations>strong{display:block;margin-bottom:4px;color:#704b0a!important;font-size:11.5px!important}.itdna-easy-limitations[hidden]{display:none} 280 .itdna-easy-footer{display:flex;align-items:center;justify-content:space-between;gap:16px;margin-top:12px}.itdna-easy-footer small{max-width:980px;color:#7a8798;font-size:10px;line-height:1.45}.itdna-easy-footer .button{flex:0 0 auto} 281 @media(max-width:800px){.itdna-easy-head,.itdna-easy-footer{align-items:flex-start;flex-direction:column}.itdna-easy-steps{grid-template-columns:1fr 1fr}.itdna-easy-compare-head,.itdna-easy-compare-row{grid-template-columns:1.25fr 1fr 1fr}.itdna-easy-footer .button{width:100%}} 282 283 /* v2.33.19 honest Easy Setup outcome summary */ 284 .itdna-easy-outcome-grid{display:grid;grid-template-columns:repeat(6,minmax(0,1fr));gap:8px;margin:10px 0 12px}.itdna-easy-outcome-grid>div{padding:10px;border:1px solid #e1e8f1;border-radius:9px;background:#fff}.itdna-easy-outcome-grid span{display:block;color:#71809a;font-size:9.5px;font-weight:800;text-transform:uppercase;letter-spacing:.035em}.itdna-easy-outcome-grid strong{display:block;margin:5px 0 2px;color:#183b66;font-size:14px;line-height:1.2}.itdna-easy-outcome-grid small{display:block;color:#8a96a8;font-size:9.5px;line-height:1.3} 285 @media(max-width:1050px){.itdna-easy-outcome-grid{grid-template-columns:repeat(3,minmax(0,1fr))}}@media(max-width:650px){.itdna-easy-outcome-grid{grid-template-columns:repeat(2,minmax(0,1fr))}} 286 287 .itdna-easy-result-details{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-top:10px}.itdna-easy-result-details>div{padding:10px 12px;border:1px solid #dfe8f3;border-radius:9px;background:#f9fbfe;color:#5d6e84;font-size:10.5px;line-height:1.5}.itdna-easy-result-details strong{display:block;margin-bottom:4px;color:#26486f;font-size:11px}.itdna-easy-result-details[hidden]{display:none}@media(max-width:750px){.itdna-easy-result-details{grid-template-columns:1fr}} 288 289 290 /* v2.35.17 — Unified non-Dashboard admin UI 291 * Dashboard is intentionally excluded. This layer normalizes typography, spacing, 292 * controls and the visual palette across every other Turbo Cache screen without 293 * changing any runtime/performance setting, JS hook, form name or module behavior. 294 */ 295 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]){ 296 --itdna-ui-text:#17233b; 297 --itdna-ui-body:#52627a; 298 --itdna-ui-muted:#7c89a0; 299 --itdna-ui-border:#e3e9f2; 300 --itdna-ui-border-soft:#edf1f6; 301 --itdna-ui-surface:#fff; 302 --itdna-ui-soft:#f7f9fc; 303 --itdna-ui-blue:#2f80ed; 304 --itdna-ui-blue-soft:#edf5ff; 305 --itdna-ui-green:#11653f; 306 --itdna-ui-green-soft:#edfff7; 307 --itdna-ui-amber:#8a5a09; 308 --itdna-ui-amber-soft:#fff7df; 309 --itdna-ui-red:#9c2828; 310 --itdna-ui-red-soft:#fff1f1; 311 color:var(--itdna-ui-body); 312 font-size:13px!important; 313 line-height:1.5!important; 314 } 315 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) :where(button,input,select,textarea,.button){font-family:inherit!important} 316 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) :where(p,li,td,th,label){line-height:1.5} 317 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) :where(.itdna-card,.itdna-auto-type,.itdna-easy-setup,.itdna-v20-engine,.itdna-asset-section,.itdna-auto-choice-dialog){border-color:var(--itdna-ui-border)!important} 318 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) :where(.itdna-card-head,.itdna-asset-section-head,.itdna-v20-summary,.itdna-v20-note){border-color:var(--itdna-ui-border-soft)!important} 319 320 /* One readable type scale for all non-Dashboard screens. */ 321 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-card-head h2{font-size:16px!important;line-height:1.35!important;font-weight:650!important;color:var(--itdna-ui-text)!important} 322 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-card-head p{font-size:12.5px!important;line-height:1.5!important;color:var(--itdna-ui-muted)!important} 323 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) :where(.itdna-toggle-row strong,.itdna-field strong,.itdna-field-row strong,.itdna-diagnostic strong,.itdna-manual-check strong,.itdna-detect-card strong,.itdna-plugin-row strong,.itdna-plan-row strong,.itdna-asset-stat-label,.itdna-compat-label){font-size:13.5px!important;line-height:1.4!important;font-weight:650!important;color:var(--itdna-ui-text)!important} 324 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) :where(.itdna-toggle-row small,.itdna-field small,.itdna-field-row small,.itdna-diagnostic small,.itdna-manual-check small,.itdna-detect-card small,.itdna-plugin-row small,.itdna-plan-row small,.itdna-compat-status small,.itdna-help,.itdna-info){font-size:12px!important;line-height:1.5!important;color:var(--itdna-ui-muted)!important} 325 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) :where(.itdna-kicker,.itdna-asset-kicker,.itdna-plugin-row.head,.itdna-plan-row.head,.itdna-v20-summary span,.itdna-easy-outcome-grid span,.itdna-auto-choice-badge,.itdna-easy-badge){font-size:11px!important;line-height:1.35!important;letter-spacing:.045em!important} 326 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) :where(.itdna-risk,.itdna-role,.itdna-value,.itdna-integrity-badge,.itdna-integrity-badge strong,.itdna-compat-badge,.itdna-owner-standby-badge,.itdna-server-badge){font-size:11px!important;line-height:1.3!important} 327 328 /* Controls use the same dimensions and font everywhere. */ 329 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) :where(.itdna-top-actions .button,.itdna-actions .button,.itdna-card .button,.itdna-auto-hero-actions .button,.itdna-v20-actions .button,.itdna-inline-help .button,.itdna-owner-inline-actions .button,.itdna-easy-footer .button,.itdna-auto-choice-foot .button){min-height:34px!important;height:auto!important;padding:6px 12px!important;border-radius:7px!important;font-size:13px!important;line-height:1.4!important;font-weight:600!important} 330 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .button.button-large{min-height:38px!important;padding:7px 14px!important;font-size:13.5px!important} 331 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) :where(.itdna-field input[type=text],.itdna-field input[type=url],.itdna-field input[type=password],.itdna-field input[type=number],.itdna-field input[type=email],.itdna-field select,.itdna-field textarea,.itdna-field-row select){min-height:40px!important;padding:8px 10px!important;border:1px solid #cfd8e6!important;border-radius:8px!important;background:#fff!important;color:var(--itdna-ui-text)!important;font-size:13px!important;line-height:1.45!important;box-shadow:none!important} 332 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-field textarea{min-height:104px!important;font-family:inherit!important;font-size:13px!important} 333 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) :where(input,select,textarea):focus{border-color:#86b7f3!important;box-shadow:0 0 0 1px #86b7f3!important;outline:0!important} 334 335 /* Consistent cards, rows and neutral surfaces. */ 336 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-card{border-radius:12px!important;box-shadow:0 4px 18px rgba(35,55,90,.045)!important} 337 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-card-head{padding:15px 18px!important;background:#fff!important} 338 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-card-body{padding:15px 18px 17px!important} 339 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) :where(.itdna-toggle-row,.itdna-field-row,.itdna-diagnostic,.itdna-db-row,.itdna-manual-check,.itdna-v20-step){border-color:var(--itdna-ui-border-soft)!important} 340 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-toggle-row{padding:12px 0!important;gap:18px!important} 341 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-field{margin-bottom:15px!important} 342 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) :where(.itdna-engine-note,.itdna-inline-help,.itdna-plan-reasons,.itdna-manual-note,.itdna-step-list,.itdna-owner-situation,.itdna-asset-explainer){font-size:12.5px!important;line-height:1.5!important;color:var(--itdna-ui-body)!important;border-color:#dfe8f3!important;background:#f7faff!important} 343 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-inline-help strong{font-size:13.5px!important;color:var(--itdna-ui-text)!important} 344 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-checklist div{font-size:12.5px!important;line-height:1.5!important;color:#365273!important;background:#f6fbff!important;border-color:#e4f1ff!important} 345 346 /* Auto Optimize / optimizer engine. */ 347 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) :where(.itdna-auto-hero,.itdna-v20-head,.itdna-pro-preview-head){padding:21px 23px!important;border-radius:14px!important;background:linear-gradient(135deg,#0b1731,#16335f)!important} 348 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) :where(.itdna-auto-hero h2,.itdna-v20-head h2,.itdna-pro-preview-head h2){font-size:21px!important;line-height:1.25!important;font-weight:650!important} 349 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) :where(.itdna-auto-hero p,.itdna-v20-head p,.itdna-pro-preview-head p){font-size:13px!important;line-height:1.55!important;color:#c6d4ea!important} 350 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-auto-type{padding:15px 18px!important;border-radius:12px!important} 351 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-type-main>span{font-size:11px!important;color:var(--itdna-ui-muted)!important} 352 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-type-main strong{font-size:20px!important;line-height:1.25!important;color:var(--itdna-ui-text)!important} 353 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-type-main small{font-size:12px!important;color:var(--itdna-ui-muted)!important} 354 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-chip{font-size:11.5px!important;background:var(--itdna-ui-blue-soft)!important;border-color:#d8e9ff!important;color:#275486!important} 355 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-detect-card{padding:11px 12px!important;border-radius:9px!important;background:#fbfcfe!important;border-color:var(--itdna-ui-border)!important} 356 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-detect-card.ok{background:#f5fffa!important;border-color:#d8f2e6!important} 357 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) :where(.itdna-plugin-row,.itdna-plan-row){font-size:12.5px!important;padding:11px 13px!important;border-color:var(--itdna-ui-border-soft)!important} 358 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) :where(.itdna-plugin-row.head,.itdna-plan-row.head){background:var(--itdna-ui-soft)!important;color:#6f7e95!important;font-weight:800!important} 359 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-role{background:#eef3f8!important;color:#4f6078!important} 360 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-value{background:#eef7ff!important;color:#2a5d92!important;padding:4px 8px!important} 361 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-infra-strip span{font-size:12px!important;color:#607089!important;border-color:var(--itdna-ui-border)!important;background:var(--itdna-ui-soft)!important} 362 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-v20-summary span{color:var(--itdna-ui-muted)!important} 363 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-v20-summary strong{font-size:14.5px!important;color:var(--itdna-ui-text)!important} 364 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-v20-progress small{font-size:12px!important;color:var(--itdna-ui-muted)!important} 365 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-v20-step strong{font-size:13.5px!important;color:var(--itdna-ui-text)!important} 366 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-v20-step small{font-size:12px!important;color:var(--itdna-ui-muted)!important} 367 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-v20-results>div{font-size:12.5px!important;background:var(--itdna-ui-soft)!important;border-color:var(--itdna-ui-border)!important} 368 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-v20-note{font-size:12px!important;color:#63728a!important;background:#f8fbff!important} 369 370 /* Asset / compatibility / ownership reports. */ 371 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-asset-section-head h3{font-size:14.5px!important;color:var(--itdna-ui-text)!important} 372 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-asset-stat{min-height:82px!important;border-color:var(--itdna-ui-border)!important;border-radius:9px!important;background:#fbfdff!important} 373 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-asset-stat-value{font-size:18px!important;color:#17345e!important} 374 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-asset-stat small{font-size:11.5px!important;line-height:1.4!important;color:var(--itdna-ui-muted)!important} 375 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) :where(.itdna-asset-summary span,.itdna-compat-label){font-size:12px!important;color:#51637c!important} 376 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-asset-summary strong{font-size:16px!important} 377 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-compat-status{border-color:var(--itdna-ui-border)!important;background:#fbfdff!important} 378 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) :where(.itdna-owner-inline,.itdna-owner-situation){font-size:12.5px!important;line-height:1.5!important;border-radius:9px!important} 379 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-owner-inline strong{font-size:13px!important;color:var(--itdna-ui-text)!important} 380 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-owner-inline-actions small{font-size:12px!important;line-height:1.45!important;color:var(--itdna-ui-muted)!important} 381 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-owner-situation>strong{font-size:13px!important} 382 383 /* Easy Setup and choice modal use the same typography as the rest when shown outside Dashboard. */ 384 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-easy-head h2{font-size:19px!important;color:var(--itdna-ui-text)!important} 385 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-easy-head p{font-size:12.5px!important;color:#617089!important} 386 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-easy-status>strong{font-size:13px!important} 387 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-easy-status>span{font-size:11px!important} 388 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-easy-status>p{font-size:12px!important} 389 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-easy-steps span{font-size:11.5px!important} 390 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) :where(.itdna-easy-compare-head,.itdna-easy-compare-row){font-size:12px!important} 391 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-easy-compare-row>strong{font-size:13px!important} 392 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) :where(.itdna-easy-verdict,.itdna-easy-limitations,.itdna-easy-result-details>div){font-size:12px!important;line-height:1.5!important} 393 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-easy-outcome-grid strong{font-size:14.5px!important} 394 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-easy-outcome-grid small{font-size:11.5px!important;color:var(--itdna-ui-muted)!important} 395 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-auto-choice-head h2{font-size:20px!important;color:var(--itdna-ui-text)!important} 396 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-auto-choice-head p{font-size:13px!important;color:#66758a!important} 397 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-auto-choice-card>strong{font-size:16px!important;color:var(--itdna-ui-text)!important} 398 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-auto-choice-card>p{font-size:12.5px!important;color:var(--itdna-ui-body)!important} 399 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-auto-choice-facts{font-size:12px!important;color:#40536a!important} 400 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-auto-choice-warning{font-size:12px!important} 401 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-auto-choice-card em,.itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-auto-choice-foot small{font-size:11.5px!important;color:var(--itdna-ui-muted)!important} 402 403 /* State colors are limited to one shared green / amber / red family. */ 404 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-notice.success{background:var(--itdna-ui-green-soft)!important;border-color:#b6efd6!important;color:var(--itdna-ui-green)!important} 405 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-notice.error{background:var(--itdna-ui-red-soft)!important;border-color:#ffc9c9!important;color:var(--itdna-ui-red)!important} 406 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) :where(.itdna-server-recommended_on,.itdna-compat-badge.is-active,.itdna-integrity-badge.is-pass){background:#effbf5!important;border-color:#b9ead5!important;color:#177451!important} 407 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) :where(.itdna-server-background_only,.itdna-server-standby,.itdna-owner-standby-badge){background:var(--itdna-ui-amber-soft)!important;border-color:#f2d08a!important;color:var(--itdna-ui-amber)!important} 408 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) :where(.itdna-server-adaptive_off,.itdna-server-default_off,.itdna-compat-badge.is-muted,.itdna-integrity-badge.is-pending){background:#f5f7fa!important;border-color:#dfe5ed!important;color:#66758a!important} 409 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) :where(.itdna-server-conditional,.itdna-server-optional,.itdna-compat-badge.is-owner){background:#f1f7ff!important;border-color:#c8ddf7!important;color:#255b9b!important} 410 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) :where(.itdna-integrity-badge.is-fail){background:var(--itdna-ui-red-soft)!important;border-color:#ffcaca!important;color:#a12f2f!important} 411 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-server-advisory{font-size:12.5px!important;line-height:1.5!important} 412 413 /* Mobile keeps the same type scale; only layout changes. */ 414 @media(max-width:782px){ 415 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-card-head{padding:14px 15px!important} 416 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-card-body{padding:14px 15px 16px!important} 417 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) :where(.itdna-auto-hero,.itdna-v20-head,.itdna-pro-preview-head){padding:18px!important} 418 } 419 420 /* v2.35.18 — external cache ownership is a coexistence state, not a false error. */ 421 .itdna-notice.info{background:#eef6ff;border-color:#c8ddff;color:#24538a} 422 .itdna-notice.warning{background:#fff8e8;border-color:#f3d79a;color:#7a5511} 423 .itdna-external-control{padding:12px 14px;border:1px solid #d8e5f5;border-radius:10px;background:#f7fbff} 424 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-notice.info{background:#eef6ff!important;border-color:#c8ddff!important;color:#24538a!important} 425 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-notice.warning{background:#fff8e8!important;border-color:#f3d79a!important;color:#7a5511!important} 426 427 /* v2.35.19 — shell-stable partial navigation + honest real-speed evidence. */ 428 .itdna-main{position:relative} 429 .itdna-main.itdna-nav-loading{cursor:progress} 430 .itdna-main.itdna-nav-loading::before{content:"";position:absolute;left:0;right:0;top:0;height:3px;z-index:70;background:linear-gradient(90deg,#2f80ed 0%,#62a8ff 45%,#2f80ed 100%);background-size:180% 100%;animation:itdnaNavProgress .8s linear infinite;border-radius:0 0 3px 3px;pointer-events:none} 431 .itdna-main.itdna-nav-loading .itdna-top-actions{pointer-events:none} 432 @keyframes itdnaNavProgress{0%{background-position:100% 0}100%{background-position:-80% 0}} 433 @media (prefers-reduced-motion:reduce){.itdna-main.itdna-nav-loading::before{animation:none}} 434 435 .itdna-real-speed-note{margin:12px 0 14px;padding:12px 14px;border:1px solid #c9def8;border-radius:10px;background:#f4f9ff;color:#2c507a;font-size:12.5px;line-height:1.55} 436 .itdna-real-speed-note strong{color:#173c68} 437 .itdna-browser-proof{margin:14px 0;border:1px solid #dfe7f1;border-radius:12px;background:#fff;overflow:hidden} 438 .itdna-browser-proof-head{padding:13px 15px;border-bottom:1px solid #edf1f6;display:flex;gap:8px;flex-direction:column} 439 .itdna-browser-proof-head strong{font-size:14px;color:#17233b} 440 .itdna-browser-proof-head span{font-size:12px;color:#71809a} 441 .itdna-browser-proof-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:0} 442 .itdna-browser-proof-card{padding:14px 15px;min-width:0;border-right:1px solid #edf1f6} 443 .itdna-browser-proof-card:last-child{border-right:0} 444 .itdna-browser-proof-card>span{display:block;font-size:11px;text-transform:uppercase;letter-spacing:.04em;font-weight:750;color:#73839c} 445 .itdna-browser-proof-card>strong{display:block;margin:5px 0 4px;font-size:18px;color:#1a2942} 446 .itdna-browser-proof-card>small{display:block;font-size:11.5px;line-height:1.45;color:#75839a} 447 .itdna-browser-proof-card.improved{background:#f5fff9} 448 .itdna-browser-proof-card.improved>strong{color:#147348} 449 .itdna-browser-proof-card.regressed{background:#fff6f6} 450 .itdna-browser-proof-card.regressed>strong{color:#a12f2f} 451 .itdna-browser-proof-card.neutral{background:#fffbf2} 452 .itdna-browser-proof-card.neutral>strong{color:#7b5a12} 453 @media(max-width:782px){.itdna-browser-proof-grid{grid-template-columns:1fr}.itdna-browser-proof-card{border-right:0;border-bottom:1px solid #edf1f6}.itdna-browser-proof-card:last-child{border-bottom:0}} 454 .itdna-side-status small{display:block;margin:4px 0 0 14px;color:#7890b5;font-size:10.5px;line-height:1.35} 455 \n\n/* v2.35.20 — Compact contextual admin density. 456 * Dashboard remains intentionally untouched. The adaptive recommendation now 457 * belongs visually to its own option row, while cards/forms/notices use space 458 * according to information importance rather than one oversized default. 459 */ 460 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]){ 461 --itdna-density-title:13.5px; 462 --itdna-density-body:11.75px; 463 --itdna-density-meta:10.5px; 464 } 465 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-top{margin-bottom:13px!important} 466 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-top h1{font-size:25px!important;line-height:1.2!important;letter-spacing:-.015em!important} 467 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-top p{margin-top:4px!important;font-size:12px!important;line-height:1.4!important} 468 469 /* Cards: compact shell, still roomy enough to scan. */ 470 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-card{margin-bottom:12px!important;border-radius:11px!important} 471 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-card-head{padding:12px 16px 11px!important} 472 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-card-head h2{font-size:15px!important;line-height:1.3!important;font-weight:650!important} 473 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-card-head p{margin:3px 0 0!important;font-size:11.75px!important;line-height:1.4!important} 474 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-card-body{padding:8px 16px 11px!important} 475 476 /* Each option is one visual unit: name + chips, explanation, policy, switch. */ 477 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-toggle-row{align-items:center!important;gap:14px!important;padding:10px 0!important} 478 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-toggle-row>.itdna-toggle-copy{display:flex!important;flex:1 1 auto!important;min-width:0!important;flex-direction:column!important;gap:3px!important;padding-right:8px!important} 479 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-toggle-titleline{display:flex!important;flex-direction:row!important;align-items:center!important;flex-wrap:wrap!important;gap:5px!important;min-width:0!important} 480 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-toggle-titleline>strong{display:inline!important;font-size:var(--itdna-density-title)!important;line-height:1.28!important;font-weight:650!important;margin:0 2px 0 0!important;color:var(--itdna-ui-text)!important} 481 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-toggle-desc{display:block!important;margin:0!important;max-width:980px!important;font-size:var(--itdna-density-body)!important;line-height:1.4!important;color:#74839a!important} 482 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) :where(.itdna-risk,.itdna-server-badge,.itdna-owner-standby-badge){display:inline-flex!important;align-items:center!important;width:auto!important;margin:0!important;padding:2px 6px!important;border-radius:999px!important;font-size:9.75px!important;line-height:1.25!important;font-weight:750!important;letter-spacing:.015em!important;white-space:nowrap!important} 483 484 /* Replaces the old detached full-width server advisory banner. */ 485 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-toggle-policy{display:flex!important;flex-direction:row!important;align-items:baseline!important;gap:4px!important;width:auto!important;max-width:980px!important;margin:1px 0 0!important;padding:0 0 0 7px!important;border:0!important;border-left:2px solid #cbd5e1!important;border-radius:0!important;background:transparent!important;font-size:10.75px!important;line-height:1.38!important;color:#64748b!important} 486 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-toggle-policy b{flex:0 0 auto!important;font-size:10.75px!important;font-weight:700!important;color:#475569!important} 487 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-toggle-policy>span{display:inline!important;min-width:0!important} 488 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-policy-recommended_on{border-left-color:#86d6aa!important;color:#397054!important} 489 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-policy-recommended_on b{color:#17623f!important} 490 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-policy-conditional{border-left-color:#8bc9ec!important;color:#406d88!important} 491 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-policy-standby,.itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-policy-background_only{border-left-color:#e7c66d!important;color:#765d22!important} 492 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-policy-adaptive_off,.itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-policy-default_off{border-left-color:#cbd5e1!important;color:#64748b!important} 493 494 /* Switch stays compact and aligned with its own option. */ 495 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-switch{flex:0 0 40px!important;width:40px!important;min-width:40px!important;height:22px!important;margin:0!important} 496 497 /* Forms and free-text fields: consistent but not oversized. */ 498 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-field{margin-bottom:11px!important} 499 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) :where(.itdna-field strong,.itdna-field-row strong){font-size:13px!important;line-height:1.35!important;font-weight:650!important} 500 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) :where(.itdna-field small,.itdna-field-row small){margin-top:2px!important;font-size:11.5px!important;line-height:1.4!important} 501 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) :where(.itdna-field input[type=text],.itdna-field input[type=url],.itdna-field input[type=password],.itdna-field input[type=number],.itdna-field input[type=email],.itdna-field select,.itdna-field-row select){min-height:36px!important;padding:6px 9px!important;border-radius:7px!important;font-size:12.5px!important} 502 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-field textarea{min-height:86px!important;padding:7px 9px!important;font-size:12px!important;line-height:1.4!important} 503 504 /* Notices/help should inform, not dominate the screen. */ 505 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-notice{margin:0 0 10px!important;padding:8px 11px!important;border-radius:8px!important;font-size:11.75px!important;line-height:1.42!important} 506 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) :where(.itdna-engine-note,.itdna-inline-help,.itdna-plan-reasons,.itdna-manual-note,.itdna-step-list,.itdna-owner-situation,.itdna-asset-explainer){padding:8px 10px!important;font-size:11.75px!important;line-height:1.42!important;border-radius:8px!important} 507 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-info{margin:7px 0!important;font-size:11.5px!important;line-height:1.4!important} 508 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-owner-inline{margin:6px 0 9px!important;padding:8px 10px!important;border-radius:8px!important;font-size:11.5px!important;line-height:1.4!important} 509 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-owner-inline-actions{margin-top:6px!important;gap:7px!important} 510 511 /* Tables / diagnostics / metric tiles use the same compact rhythm. */ 512 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) :where(.itdna-diagnostic,.itdna-db-row,.itdna-manual-check,.itdna-v20-step){padding-top:8px!important;padding-bottom:8px!important} 513 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) :where(.itdna-plugin-row,.itdna-plan-row){padding:8px 11px!important;font-size:11.75px!important} 514 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-asset-stat{min-height:68px!important;padding-top:10px!important;padding-bottom:10px!important} 515 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-checklist{gap:7px!important} 516 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-checklist div{padding:8px 10px!important;font-size:11.75px!important;line-height:1.4!important} 517 518 @media(max-width:782px){ 519 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-card-head{padding:11px 13px 10px!important} 520 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-card-body{padding:7px 13px 10px!important} 521 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-toggle-row{gap:10px!important;padding:9px 0!important} 522 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-toggle-policy{display:block!important;padding-left:6px!important} 523 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-toggle-policy b{display:inline!important;margin-right:3px!important} 524 } 525 526 /* v2.35.22 — Compact Adaptive Server Profiler. The markup always used 527 itdna-mini-grid; this supplies the missing layout so capability values do not 528 stack into a very tall single column. Scoped to Auto Optimize/server profiler. */ 529 .itdna-main[data-itdna-tab="autooptimize"] .itdna-server-profile-card{margin-top:12px!important} 530 .itdna-main[data-itdna-tab="autooptimize"] .itdna-server-profile-card .itdna-card-head{padding:10px 14px!important} 531 .itdna-main[data-itdna-tab="autooptimize"] .itdna-server-profile-card .itdna-card-head h2{font-size:15px!important;line-height:1.25!important;margin:0!important} 532 .itdna-main[data-itdna-tab="autooptimize"] .itdna-server-profile-card .itdna-card-head p{font-size:11.25px!important;line-height:1.38!important;margin:3px 0 0!important;max-width:1050px} 533 .itdna-main[data-itdna-tab="autooptimize"] .itdna-server-profile-card .itdna-card-body{padding:11px 14px 12px!important} 534 .itdna-main[data-itdna-tab="autooptimize"] .itdna-server-profile-card .itdna-mini-grid{display:grid!important;grid-template-columns:repeat(3,minmax(0,1fr))!important;gap:7px!important;margin:0!important} 535 .itdna-main[data-itdna-tab="autooptimize"] .itdna-server-profile-card .itdna-mini-grid>div{min-width:0;padding:7px 9px!important;border:1px solid #e2e8f0;border-radius:7px;background:#fbfdff;display:flex!important;flex-direction:column!important;gap:2px!important} 536 .itdna-main[data-itdna-tab="autooptimize"] .itdna-server-profile-card .itdna-mini-grid>div>span{font-size:10.25px!important;line-height:1.2!important;font-weight:650!important;color:#7a8799!important;margin:0!important;text-transform:none!important;letter-spacing:0!important} 537 .itdna-main[data-itdna-tab="autooptimize"] .itdna-server-profile-card .itdna-mini-grid>div>strong{font-size:12.25px!important;line-height:1.3!important;font-weight:700!important;color:#42536c!important;margin:0!important;overflow-wrap:anywhere} 538 .itdna-main[data-itdna-tab="autooptimize"] .itdna-server-profile-card .itdna-server-reasons{margin:8px 0 0!important;padding:0!important;background:#f8fbff!important;border:1px solid #e2eaf4!important;border-radius:7px!important;overflow:hidden} 539 .itdna-main[data-itdna-tab="autooptimize"] .itdna-server-profile-card .itdna-server-reasons>summary{cursor:pointer;list-style:none;padding:7px 9px!important;font-size:11px!important;line-height:1.3!important;color:#445872!important;display:flex;align-items:center;gap:6px} 540 .itdna-main[data-itdna-tab="autooptimize"] .itdna-server-profile-card .itdna-server-reasons>summary::-webkit-details-marker{display:none} 541 .itdna-main[data-itdna-tab="autooptimize"] .itdna-server-profile-card .itdna-server-reasons>summary:before{content:'›';font-size:16px;line-height:1;transition:transform .15s ease;color:#64748b} 542 .itdna-main[data-itdna-tab="autooptimize"] .itdna-server-profile-card .itdna-server-reasons[open]>summary:before{transform:rotate(90deg)} 543 .itdna-main[data-itdna-tab="autooptimize"] .itdna-server-profile-card .itdna-server-reasons>summary span{font-size:10px;font-weight:600;color:#8795a8} 544 .itdna-main[data-itdna-tab="autooptimize"] .itdna-server-profile-card .itdna-server-reason-list{padding:0 9px 7px 26px!important} 545 .itdna-main[data-itdna-tab="autooptimize"] .itdna-server-profile-card .itdna-server-reason-list>div{font-size:10.75px!important;line-height:1.38!important;margin:3px 0!important;color:#607087!important} 546 .itdna-main[data-itdna-tab="autooptimize"] .itdna-server-profile-card .itdna-actions{margin-top:8px!important} 547 .itdna-main[data-itdna-tab="autooptimize"] .itdna-server-profile-card .itdna-actions .button{min-height:30px!important;height:30px!important;padding:0 10px!important;font-size:11.5px!important} 548 .itdna-main[data-itdna-tab="autooptimize"] .itdna-server-profile-card .itdna-help{margin:7px 0 0!important;padding:0!important;font-size:10.5px!important;line-height:1.35!important;color:#8190a3!important;background:transparent!important;border:0!important} 549 .itdna-main[data-itdna-tab="autooptimize"] .itdna-server-profile-card .itdna-info{margin:8px 0 0!important;padding:7px 9px!important;font-size:10.75px!important;line-height:1.35!important} 550 @media(max-width:1100px){.itdna-main[data-itdna-tab="autooptimize"] .itdna-server-profile-card .itdna-mini-grid{grid-template-columns:repeat(2,minmax(0,1fr))!important}} 551 @media(max-width:640px){.itdna-main[data-itdna-tab="autooptimize"] .itdna-server-profile-card .itdna-mini-grid{grid-template-columns:1fr!important}.itdna-main[data-itdna-tab="autooptimize"] .itdna-server-profile-card .itdna-card-head,.itdna-main[data-itdna-tab="autooptimize"] .itdna-server-profile-card .itdna-card-body{padding-left:10px!important;padding-right:10px!important}} 552 553 554 /* v2.35.25 — category-wise single-open accordions for non-dashboard pages */ 555 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-accordion-card{overflow:hidden} 556 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-accordion-head{display:grid!important;grid-template-columns:minmax(0,1fr) auto;align-items:center;column-gap:12px;cursor:pointer;user-select:none;transition:background-color .16s ease,border-color .16s ease} 557 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-accordion-head h2,.itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-accordion-head p{grid-column:1} 558 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-accordion-head:focus-visible{outline:2px solid #2563eb;outline-offset:-2px} 559 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-accordion-indicator{grid-column:2;grid-row:1 / span 2;display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;border-radius:999px;border:1px solid #d7e3f4;background:#f7fbff;color:#284d8f;font-size:20px;line-height:1;font-weight:700;box-shadow:inset 0 1px 0 rgba(255,255,255,.8)} 560 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-accordion-card.itdna-acc-open>.itdna-card-head{background:linear-gradient(180deg,#f8fbff 0%,#ffffff 100%)!important;border-bottom-color:#e2ebf7!important} 561 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-accordion-card.itdna-acc-collapsed>.itdna-card-head{border-bottom:0!important} 562 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-accordion-card.itdna-acc-collapsed>.itdna-card-body{display:none!important} 563 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-accordion-card.itdna-acc-open{box-shadow:0 8px 24px rgba(34,56,96,.08)!important;border-color:#d8e5f7!important} 564 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-accordion-card.itdna-acc-collapsed{box-shadow:0 2px 12px rgba(35,55,90,.04)!important} 565 @media (max-width:782px){ 566 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-accordion-indicator{width:26px;height:26px;font-size:18px} 567 } 568 569 570 /* v2.35.27 — true nested category view: all headers visible, one section open at a time. */ 571 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-category-host>.itdna-card-body{display:block!important;padding:10px 12px 12px!important} 572 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-category-host>.itdna-card-head{background:#fff!important;border-bottom:1px solid #edf1f6!important;cursor:default!important} 573 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-category-stack{display:grid;gap:7px} 574 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-option-category{border:1px solid #dfe7f2;border-radius:10px;background:#fff;overflow:hidden;box-shadow:0 2px 8px rgba(31,48,78,.035)} 575 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-option-category-trigger{appearance:none;-webkit-appearance:none;width:100%;border:0;margin:0;padding:10px 12px;background:#f8fafc;color:#17233b;display:grid;grid-template-columns:minmax(0,1fr) 28px;gap:12px;align-items:center;text-align:left;cursor:pointer;font:inherit;transition:background-color .15s ease,box-shadow .15s ease} 576 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-option-category-trigger:hover{background:#f2f7ff} 577 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-option-category-trigger:focus-visible{outline:2px solid #2563eb;outline-offset:-2px} 578 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-option-category-copy{min-width:0;display:block} 579 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-option-category-copy>strong{display:block;font-size:13.5px;line-height:1.25;font-weight:700;color:#17233b} 580 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-option-category-copy>small{display:block;margin-top:2px;font-size:11px;line-height:1.3;color:#77869d;white-space:nowrap;overflow:hidden;text-overflow:ellipsis} 581 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-option-category-icon{width:26px;height:26px;border:1px solid #d5e2f4;border-radius:999px;display:inline-flex;align-items:center;justify-content:center;background:#fff;color:#31588f;font-size:18px;font-weight:700;line-height:1} 582 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-option-category-body{padding:5px 13px 9px;background:#fff;border-top:1px solid #e7edf5} 583 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-option-category-body[hidden]{display:none!important} 584 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-option-category.itdna-category-open{border-color:#bdd3f3;box-shadow:0 7px 20px rgba(42,74,120,.075)} 585 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-option-category.itdna-category-open>.itdna-option-category-trigger{background:#f2f7ff} 586 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-category-host .itdna-toggle-row{padding:9px 0!important} 587 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-category-host .itdna-field{margin-bottom:10px!important} 588 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-category-host .itdna-info{margin:8px 0!important} 589 @media(max-width:782px){ 590 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-category-host>.itdna-card-body{padding:8px!important} 591 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-option-category-trigger{padding:10px;grid-template-columns:minmax(0,1fr) 26px} 592 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-option-category-copy>small{white-space:normal;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical} 593 .itdna-main[data-itdna-tab]:not([data-itdna-tab="dashboard"]) .itdna-option-category-body{padding:4px 10px 8px} 594 } 595 596 /* v2.35.30 — Easy Auto Setup primary action sits directly after live progress/status. */ 597 .itdna-easy-primary-action{display:flex;align-items:center;justify-content:flex-start;margin:10px 0 12px} 598 .itdna-easy-primary-action .button{min-height:36px;padding:4px 16px;font-weight:650} 599 .itdna-easy-primary-action .button[hidden]{display:none!important} 600 @media(max-width:782px){.itdna-easy-primary-action .button{width:100%;justify-content:center}} 601 602 603 /* v2.35.33 — Cloudflare connection/status unified card */ 604 .itdna-main[data-itdna-tab="cloudflare"] .itdna-cf-status-block{padding:0 0 10px;margin:0 0 10px;border-bottom:1px solid #e8eef6} 605 .itdna-main[data-itdna-tab="cloudflare"] .itdna-cf-status-block .itdna-notice,.itdna-main[data-itdna-tab="cloudflare"] .itdna-cf-status-block .itdna-engine-note{margin-bottom:8px!important} 606 .itdna-main[data-itdna-tab="cloudflare"] .itdna-cf-section-title{display:flex;flex-direction:column;gap:2px;padding:2px 0 8px} 607 .itdna-main[data-itdna-tab="cloudflare"] .itdna-cf-section-title>strong{font-size:13.5px;color:#17233b} 608 .itdna-main[data-itdna-tab="cloudflare"] .itdna-cf-section-title>small{font-size:11.5px;line-height:1.4;color:#7c89a0} 609 610 611 /* v2.35.34 — immediate action feedback for slow shared-host admin requests */ 612 .itdna-global-busy{position:fixed;top:44px;right:20px;z-index:100500;display:flex;align-items:center;gap:9px;max-width:min(390px,calc(100vw - 32px));padding:10px 13px;border:1px solid #d6e3f5;border-radius:10px;background:#fff;color:#1d3557;box-shadow:0 10px 30px rgba(20,43,80,.18);font:600 12.5px/1.35 Inter,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;opacity:0;transform:translateY(-8px);pointer-events:none;transition:opacity .14s ease,transform .14s ease} 613 .itdna-global-busy.show{opacity:1;transform:translateY(0)} 614 .itdna-busy-spinner{width:15px;height:15px;flex:0 0 15px;border:2px solid #cfe0f6;border-top-color:#2f6feb;border-radius:50%;animation:itdnaBusySpin .7s linear infinite} 615 .itdna-is-working{pointer-events:none!important;opacity:.78!important;cursor:progress!important} 616 @keyframes itdnaBusySpin{to{transform:rotate(360deg)}} 617 @media(max-width:782px){.itdna-global-busy{top:52px;right:10px;left:10px;max-width:none}} 618 @media(prefers-reduced-motion:reduce){.itdna-busy-spinner{animation:none}.itdna-global-busy{transition:none}} 619 620 /* v2.35.35 — make homepage-origin vs browser/PageSpeed scope explicit */ 621 .itdna-measurement-scope{display:flex;gap:8px;align-items:flex-start;padding:10px 12px;margin:8px 0 12px;border:1px solid #cfe0f7;border-radius:9px;background:#f6faff;color:#35506f;font-size:12px;line-height:1.45}.itdna-measurement-scope strong{color:#17365d;white-space:nowrap}.itdna-measurement-scope span{min-width:0}@media(max-width:782px){.itdna-measurement-scope{display:block}.itdna-measurement-scope strong{display:block;margin-bottom:3px;white-space:normal}} 622 623 /* v2.35.39 — Performance Doctor summary merged into the engine card. */ 624 .itdna-main[data-itdna-tab="doctor"] .itdna-doctor-summary-grid{margin:0 0 12px!important;grid-template-columns:repeat(4,minmax(0,1fr))!important} 625 .itdna-main[data-itdna-tab="doctor"] .itdna-doctor-summary-grid .itdna-metric{box-shadow:none!important;background:#f8fafc!important;border-color:#e4eaf2!important;padding:13px 14px!important} 626 @media(max-width:1000px){.itdna-main[data-itdna-tab="doctor"] .itdna-doctor-summary-grid{grid-template-columns:repeat(2,minmax(0,1fr))!important}} 627 @media(max-width:640px){.itdna-main[data-itdna-tab="doctor"] .itdna-doctor-summary-grid{grid-template-columns:1fr!important}} 628 629 630 /* v2.35.41 — Cache Analytics unified default-open card */ 631 .itdna-main[data-itdna-tab="analytics"] .itdna-in-card-metrics{margin:0 0 14px!important} 632 .itdna-main[data-itdna-tab="analytics"] .itdna-in-card-metrics .itdna-metric{box-shadow:none!important;background:#f8fbff!important} 633 634 /* v1.3.51: top-of-dashboard scheduler controls and measured host load. */ 635 .itdna-speed-console{background:#fff;border:1px solid #dbe5f2;border-radius:14px;box-shadow:0 5px 18px rgba(28,47,83,.06);padding:17px 20px 13px;margin:-2px 0 20px} 636 .itdna-speed-heading{display:flex;flex-wrap:wrap;align-items:flex-start;justify-content:space-between;gap:10px;margin-bottom:14px} 637 .itdna-speed-heading h2{margin:0 0 5px;font-size:17px;line-height:1.25;color:#182746} 638 .itdna-speed-heading p{margin:0;color:#6d7e98;font-size:12px;line-height:1.45} 639 .itdna-speed-chip{background:#edfdf6;border:1px solid #bcebd4;color:#197647;border-radius:99px;font-size:11px;font-weight:750;padding:5px 11px;white-space:nowrap} 640 .itdna-speed-form{display:grid;grid-template-columns:minmax(150px,1fr) minmax(170px,1fr) minmax(220px,1.25fr) auto;gap:12px;align-items:end;margin:0 0 13px} 641 .itdna-speed-field{display:flex;flex-direction:column;gap:5px;font-size:13px;min-width:0} 642 .itdna-speed-field strong{color:#253958;font-size:13px} 643 .itdna-speed-field span{color:#7a889e;min-height:16px;font-size:11px} 644 .itdna-speed-field select{width:100%;max-width:none;min-height:38px;border:1px solid #cfdbeb;border-radius:8px;color:#1e2e48;background:#fafdff;padding:5px 10px;font-weight:650} 645 .itdna-speed-health{min-height:37px;display:flex;flex-direction:column;justify-content:center;gap:2px;padding:7px 10px;border-radius:9px;border:1px solid #b9e8cf;background:#edfbf3;color:#176342;box-sizing:border-box} 646 .itdna-speed-health strong{font-size:12px;line-height:1.3} 647 .itdna-speed-health small{font-size:10px;line-height:1.3;opacity:.86} 648 .itdna-speed-health.is-warm{background:#fff9e9;border-color:#f1d8a1;color:#9e5a0a} 649 .itdna-speed-health.is-hot{background:#fff0f0;border-color:#ffc1c1;color:#a82432} 650 .itdna-speed-health.is-ice{background:#edf7ff;border-color:#c5dfff;color:#296394} 651 .itdna-speed-save.button.button-primary{height:38px!important;min-height:38px!important;margin:0!important;padding:5px 15px!important;white-space:nowrap;font-weight:700!important} 652 .itdna-speed-load{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:10px;border-top:1px solid #e8eef7;padding-top:12px} 653 .itdna-speed-load>div{display:flex;flex-direction:column;min-width:0;gap:4px;padding:10px 12px;background:#f7f9fe;border:1px solid #ebf0f8;border-radius:9px} 654 .itdna-speed-load span{font-size:11px;font-weight:650;color:#637691} 655 .itdna-speed-load strong{font-size:18px;color:#193656;line-height:1.2} 656 .itdna-speed-load small{font-size:10.5px;color:#7b879a;overflow-wrap:anywhere;line-height:1.35} 657 .itdna-speed-footnote{color:#7b879a;font-size:11px!important;line-height:1.5;margin:11px 0 0!important} 658 @media(max-width:1100px){.itdna-speed-form{grid-template-columns:repeat(2,minmax(0,1fr))}.itdna-speed-health{min-height:42px}} 659 @media(max-width:600px){.itdna-speed-console{padding:14px 12px}.itdna-speed-form,.itdna-speed-load{grid-template-columns:1fr}.itdna-speed-field span{min-height:0}.itdna-speed-save.button.button-primary{width:100%}} 660 661 /* v1.3.52 — primary Smart Speed Slider; manual controls in expandable panel. */ 662 .itdna-speed-form.itdna-smart-form{display:grid;grid-template-columns:minmax(0,1fr) minmax(210px,270px);gap:14px;align-items:stretch;margin:0 0 15px} 663 .itdna-smart-main{min-width:0;padding:15px 17px;border:1px solid #dfe8f5;border-radius:12px;background:#f9fbff} 664 .itdna-smart-label{display:flex;justify-content:space-between;align-items:center;gap:14px} 665 .itdna-smart-label label{display:flex;flex-direction:column;gap:5px} 666 .itdna-smart-label strong{font-size:15px;color:#1f3457} 667 .itdna-smart-label small{font-size:11px;color:#697c98} 668 .itdna-smart-label output{font-size:25px;font-weight:800;color:#1955d5;white-space:nowrap} 669 .itdna-smart-main input[type=range]{display:block;width:100%;max-width:none;margin:19px 0 9px;accent-color:#345ce4;cursor:pointer} 670 .itdna-smart-endpoints{display:flex;align-items:center;justify-content:space-between;gap:7px;font-size:10.5px;color:#6c7b92;margin-bottom:13px} 671 .itdna-speed-radio{display:flex;align-items:center;gap:7px;font-size:12px;font-weight:600;color:#344b68} 672 .itdna-speed-radio input{margin:0!important} 673 .itdna-smart-sidebar{display:flex;flex-direction:column;gap:10px;justify-content:space-between} 674 .itdna-smart-sidebar .itdna-speed-health{flex:1;padding:12px 13px} 675 .itdna-smart-sidebar .itdna-speed-health strong{font-size:13px} 676 .itdna-smart-sidebar .itdna-speed-health small{font-size:11px} 677 .itdna-effective-stats{display:flex;flex-wrap:wrap;justify-content:space-between;gap:6px;padding:8px 10px;border-radius:8px;background:#f4f7fc;border:1px solid #e5ebf5;color:#435978;font-size:11px} 678 .itdna-effective-stats span{white-space:nowrap} 679 .itdna-effective-stats strong{color:#1b3568} 680 .itdna-smart-sidebar .itdna-speed-save{width:100%;justify-content:center} 681 .itdna-speed-advanced{grid-column:1/-1;border:1px solid #e6edf5;border-radius:10px;padding:10px 14px;background:#fcfdff} 682 .itdna-speed-advanced summary{font-size:12px;font-weight:700;color:#435a76;cursor:pointer} 683 .itdna-speed-advanced p{font-size:11px;color:#6f7e97;line-height:1.45;margin:9px 0} 684 .itdna-speed-advanced-fields{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px;margin-top:11px} 685 @media(max-width:850px){.itdna-speed-form.itdna-smart-form{grid-template-columns:1fr}.itdna-speed-advanced{grid-column:1}.itdna-smart-sidebar{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center}.itdna-smart-sidebar .itdna-speed-save{grid-column:1/-1}.itdna-smart-sidebar .itdna-effective-stats{min-width:190px}} 686 @media(max-width:600px){.itdna-smart-main{padding:12px}.itdna-smart-endpoints{font-size:9px}.itdna-smart-sidebar{display:flex}.itdna-speed-advanced-fields{grid-template-columns:1fr}} 687 688 /* v1.3.53 — hosting guard, force-lock warning, real protection status */ 689 .itdna-host-power-save-form{display:none} 690 .itdna-hosting-guard{grid-column:1/-1;background:#f7faff;border:1px solid #d4e2f5;border-radius:11px;padding:14px 16px;display:grid;gap:10px} 691 .itdna-hosting-guard h3{margin:0;font-size:15px;color:#1c3654} 692 .itdna-hosting-guard p{margin:0;font-size:12px;line-height:1.5} 693 .itdna-hosting-select{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap} 694 .itdna-hosting-select label{display:flex;flex-direction:column;gap:4px;max-width:560px} 695 .itdna-hosting-select strong{font-size:12px} 696 .itdna-hosting-select small{font-size:11px;color:#5a6981} 697 .itdna-hosting-select select{max-width:280px;min-height:37px} 698 .itdna-host-warning{color:#8a4f03;background:#fff3d8;border:1px solid #f5cb76;border-radius:8px;padding:9px 11px} 699 .itdna-host-warning.is-danger,.itdna-host-emergency{background:#fff0ef!important;border:1px solid #f4a6a6!important;color:#9c1924!important;padding:9px 11px;border-radius:8px} 700 .itdna-host-explain{color:#697e9a;font-size:11px;line-height:1.4} 701 .itdna-host-confirm{font-size:11px;color:#854321} 702 .itdna-host-status{padding:10px 12px;border-radius:9px;background:#f3f8ff;border:1px solid #dce7f5;font-size:12px;margin-bottom:10px} 703 .itdna-host-log{margin-top:10px;border-top:1px solid #e5e9ef;padding-top:8px;font-size:11px} 704 .itdna-host-log summary{cursor:pointer;font-weight:650} 705 .itdna-host-log li{margin:4px 0} 706 .itdna-host-reset{margin:9px 0} 707 708 709 /* v1.3.54: clear, accessible ON/OFF for adaptive background hosting speed. */ 710 .itdna-host-top{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:12px} 711 .itdna-host-top h3{margin:0 0 4px} 712 .itdna-host-toggle-wrap{display:flex;align-items:center;gap:12px;flex-wrap:wrap} 713 .itdna-host-power-state{border:1px solid #86d2ae;background:#e9fcf0;color:#08633f;padding:6px 12px;border-radius:99px;font-size:12px;font-weight:800;letter-spacing:.02em} 714 .itdna-host-power-state.is-off{border-color:#bbc6d3;background:#eef1f5;color:#526170} 715 .itdna-host-power-switch{border:1px solid #bfd2df;background:white;border-radius:99px;padding:6px 13px 6px 7px;display:inline-flex;align-items:center;gap:9px;min-height:41px;font-size:12px;font-weight:800;cursor:pointer;color:#2b4158;transition:box-shadow .15s ease,border-color .15s ease} 716 .itdna-host-power-switch:hover{box-shadow:0 3px 13px rgba(25,58,76,.14)} 717 .itdna-host-power-switch:focus-visible{outline:3px solid #2271b1;outline-offset:3px} 718 .itdna-host-power-switch:disabled{opacity:.65;cursor:wait} 719 .itdna-host-power-track{display:inline-flex;align-items:center;width:46px;height:25px;padding:3px;box-sizing:border-box;border-radius:99px;background:#aab6c3;transition:background .17s ease} 720 .itdna-host-power-knob{display:block;width:19px;height:19px;background:#fff;border-radius:50%;box-shadow:0 1px 3px rgba(10,30,50,.2);transform:translateX(0);transition:transform .17s ease} 721 .itdna-host-power-switch.is-on .itdna-host-power-track{background:#139b61} 722 .itdna-host-power-switch.is-on .itdna-host-power-knob{transform:translateX(21px)} 723 .itdna-host-toggle-help{color:#506881!important;font-size:11px!important;line-height:1.45} 724 .itdna-hosting-guard.itdna-host-off{background:#f6f8fa;border-color:#d9e0e8} 725 .itdna-hosting-guard.itdna-host-off .itdna-hosting-select,.itdna-hosting-guard.itdna-host-off .itdna-host-lock,.itdna-hosting-guard.itdna-host-off .itdna-host-confirm{opacity:.55} 726 @media(max-width:650px){.itdna-host-toggle-wrap{justify-content:flex-start;width:100%}.itdna-host-power-switch{min-width:140px;justify-content:space-between}} 727 @media(prefers-reduced-motion:reduce){.itdna-host-power-knob,.itdna-host-power-switch,.itdna-host-power-track{transition:none}} 728 729 /* v1.3.62 adaptive scheduler control */ 730 .itdna-pacing-choice{display:flex;flex-wrap:wrap;gap:10px;align-items:center;border:1px solid #d7e5fc;background:#f3f7fe;border-radius:12px;padding:12px;margin:12px 0}.itdna-pacing-choice label{display:flex;flex-direction:column;gap:3px;flex:1;min-width:180px;color:#183661}.itdna-pacing-choice label small{font-weight:400;color:#596e91}.itdna-pacing-choice select{min-width:260px;max-width:100%;border-radius:8px;border:1px solid #b5ccef}.itdna-pacing-choice .description{flex-basis:100%;margin:0;font-size:12px;color:#5b6f92} 731 732 /* v1.3.63 verified-capacity dashboard */ 733 .itdna-capacity-grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:10px;margin:12px 0} 734 .itdna-capacity-cell{border:1px solid #d7e2f4;background:#fff;border-radius:10px;padding:11px 12px;display:flex;flex-direction:column;gap:6px} 735 .itdna-capacity-cell small{color:#637693;font-size:11px;font-weight:600} 736 .itdna-capacity-cell strong{color:#1f4bd4;font-size:22px} 737 .itdna-capacity-note{color:#566784;font-size:12px;line-height:1.6} 738 @media(max-width:650px){.itdna-capacity-grid{grid-template-columns:repeat(2,minmax(0,1fr))}} 739 740 /* v1.3.74 Dashboard Master Power. Scoped: does not alter Hosting Guard. */ 741 .itdna-master-heading{display:flex;align-items:center;gap:16px;flex-wrap:wrap} 742 .itdna-master-heading h1{margin:0} 743 .itdna-master-header-switch{display:inline-flex;align-items:center;gap:9px;flex-wrap:wrap} 744 .itdna-master-toggle-form{display:inline-flex;margin:0} 745 .itdna-master-header-switch .itdna-host-power-switch{min-height:37px} 746 .itdna-master-paused-page{max-width:1100px;padding:10px 8px 30px} 747 .itdna-master-paused-top{background:#fff;border:1px solid #d5e1ec;padding:20px 24px;border-radius:13px;margin:18px 0} 748 .itdna-master-paused-top p{color:#576779;margin:9px 0 0} 749 .itdna-master-paused-panel{background:#fff;border:1px solid #d5e1ec;border-left:4px solid #6e859c;border-radius:9px;padding:22px 24px;line-height:1.7;max-width:950px} 750 .itdna-master-paused-panel h2{margin-top:0} 751 @media(max-width:620px){.itdna-master-heading{align-items:flex-start;flex-direction:column;gap:9px}} 752 753 /* v1.3.76: four guarded speed sliders */ 754 .itdna-speed-console-v2 .itdna-speed-form{display:block} 755 .itdna-speed-v2-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:14px;margin-top:16px} 756 .itdna-speed-v2-control{background:#f7f9fd;border:1px solid #d9e2ef;border-radius:12px;padding:15px;min-width:0} 757 .itdna-speed-v2-control label{display:block;padding-right:60px}.itdna-speed-v2-control label strong{display:block;font-size:14px;color:#183153}.itdna-speed-v2-control label small{display:block;margin:6px 0;color:#526985;font-size:11px;line-height:1.45} 758 .itdna-speed-v2-control{position:relative}.itdna-speed-v2-number{position:absolute;right:15px;top:13px;display:flex;align-items:center;gap:8px;font-size:22px;color:#1c4df0;font-weight:800} 759 .itdna-speed-v2-control input[type=range]{width:100%;display:block;cursor:pointer;margin:16px 0 5px;accent-color:#3459e8} 760 .itdna-speed-v2-range{display:flex;justify-content:space-between;font-size:11px;color:#62758f}.itdna-speed-v2-risk{font-size:12px}.itdna-speed-v2-risk.risk-low{color:#139b56}.itdna-speed-v2-risk.risk-mid{color:#e5a100}.itdna-speed-v2-risk.risk-high{color:#cf3030} 761 .itdna-speed-v2-footer{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:12px;margin:15px 0}.itdna-speed-v2-footer .itdna-speed-health{flex:1;min-width:220px}.itdna-speed-v2-buttons{display:flex;flex-direction:column;gap:8px}.itdna-speed-v2-buttons .button{white-space:normal;min-height:36px} 762 .itdna-speed-v2-notice{background:#f6f8fc;border-left:3px solid #2a53da;border-radius:4px;padding:11px 13px;line-height:1.6;color:#3e526d;font-size:12px} 763 @media(max-width:800px){.itdna-speed-v2-grid{grid-template-columns:1fr}.itdna-speed-v2-footer{display:block}.itdna-speed-v2-buttons{margin-top:12px}} 764 765 /* v1.3.77: visual speed risk and scoped CPU/RAM at each slider */ 766 .itdna-speed-v2-control input[type=range].risk-low{accent-color:#169957} 767 .itdna-speed-v2-control input[type=range].risk-mid{accent-color:#d58b00} 768 .itdna-speed-v2-control input[type=range].risk-high{accent-color:#d33535} 769 .itdna-speed-v2-load{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:4px 12px;border-top:1px solid #d9e2ef;margin-top:9px;padding-top:8px;font-size:11px} 770 .itdna-speed-v2-load span.risk-low{color:#126f43;font-weight:700} 771 .itdna-speed-v2-load span.risk-mid{color:#955900;font-weight:700} 772 .itdna-speed-v2-load span.risk-high{color:#b3222c;font-weight:700} 773 .itdna-speed-v2-load small{color:#4a5870;font-size:10px} 774 775 /* v1.3.79: Dashboard single-open accordion, first section open by default. */ 776 .itdna-main[data-itdna-tab="dashboard"] .itdna-accordion-card{overflow:hidden} 777 .itdna-main[data-itdna-tab="dashboard"] .itdna-accordion-head{display:grid!important;grid-template-columns:minmax(0,1fr) auto;align-items:center;column-gap:12px;cursor:pointer;user-select:none} 778 .itdna-main[data-itdna-tab="dashboard"] .itdna-accordion-head>h2,.itdna-main[data-itdna-tab="dashboard"] .itdna-accordion-head>p{grid-column:1} 779 .itdna-main[data-itdna-tab="dashboard"] .itdna-accordion-head .itdna-accordion-indicator{grid-column:2;grid-row:1 / span 2;display:inline-flex;align-items:center;justify-content:center;width:28px;height:28px;border-radius:999px;border:1px solid #d7e3f4;background:#f7fbff;color:#284d8f;font-size:20px;line-height:1;font-weight:700} 780 .itdna-main[data-itdna-tab="dashboard"] .itdna-accordion-head:focus-visible{outline:2px solid #2563eb;outline-offset:-2px} 781 .itdna-main[data-itdna-tab="dashboard"] .itdna-accordion-card.itdna-acc-collapsed>.itdna-card-body{display:none!important} 782 .itdna-main[data-itdna-tab="dashboard"] .itdna-accordion-card.itdna-acc-collapsed>.itdna-card-head{border-bottom:0!important} 783 .itdna-main[data-itdna-tab="dashboard"] .itdna-accordion-card.itdna-acc-open>.itdna-card-head{background:#f8fbff!important} 784 .itdna-main[data-itdna-tab="dashboard"] .itdna-speed-console{padding:0!important} 785 .itdna-main[data-itdna-tab="dashboard"] .itdna-speed-console>.itdna-speed-heading{padding:15px 20px!important;margin:0!important;grid-template-columns:minmax(0,1fr) auto 28px!important;gap:10px!important} 786 .itdna-main[data-itdna-tab="dashboard"] .itdna-speed-console>.itdna-speed-heading>div{grid-column:1;min-width:0} 787 .itdna-main[data-itdna-tab="dashboard"] .itdna-speed-console>.itdna-speed-heading>.itdna-speed-chip{grid-column:2;grid-row:1} 788 .itdna-main[data-itdna-tab="dashboard"] .itdna-speed-console>.itdna-speed-heading>.itdna-accordion-indicator{grid-column:3;grid-row:1} 789 .itdna-main[data-itdna-tab="dashboard"] .itdna-speed-console>.itdna-speed-body{padding:14px 20px 16px!important} 790 .itdna-speed-effective{border:1px solid #fed7aa;background:#fff7ed;color:#92400e;padding:9px 12px;border-radius:9px;font-size:12px;line-height:1.6;margin-bottom:12px} 791 @media(max-width:600px){.itdna-main[data-itdna-tab="dashboard"] .itdna-speed-console>.itdna-speed-heading{padding:12px 14px!important;grid-template-columns:minmax(0,1fr) 26px!important}.itdna-main[data-itdna-tab="dashboard"] .itdna-speed-console>.itdna-speed-heading>.itdna-speed-chip{display:none}.itdna-main[data-itdna-tab="dashboard"] .itdna-speed-console>.itdna-speed-heading>.itdna-accordion-indicator{grid-column:2}.itdna-main[data-itdna-tab="dashboard"] .itdna-speed-console>.itdna-speed-body{padding:12px 14px!important}} 792 793 /* 1.3.96: One universal serial background worker and one millisecond control. */ 794 .itdna-single-worker-console .itdna-card-body{padding:20px 24px} 795 .itdna-single-speed-choice{display:flex;align-items:center;justify-content:space-between;gap:16px;flex-wrap:wrap;margin:12px 0 22px} 796 .itdna-single-speed-choice strong{font-size:15px} 797 .itdna-single-speed-choice output{font-weight:800;font-size:24px;color:#284dea} 798 .itdna-single-gap-range{display:block;width:100%;max-width:900px;accent-color:#2856ee;cursor:pointer} 799 .itdna-single-gap-options{max-width:900px;display:flex;justify-content:space-between;gap:6px;font-size:12px;color:#68768c;margin:8px 0 18px} 800 .itdna-single-gap-note{max-width:900px;font-size:13px;line-height:1.6;color:#4b5563} 801 .itdna-single-gap-actions{display:flex;flex-wrap:wrap;gap:10px;margin-top:20px} 802 803 .itdna-single-gap-options{max-width:900px;display:grid;grid-template-columns:repeat(11,minmax(48px,1fr));gap:2px;overflow-x:auto;white-space:nowrap;scrollbar-width:thin} 804 .itdna-single-gap-options span{font-size:11px;text-align:center;padding:4px 0} 805 @media(max-width:800px){.itdna-single-gap-options{grid-template-columns:repeat(11,minmax(58px,1fr))}} 806 807 /* 1.3.99: speed-selection guidance, never a fabricated CPU/RAM utilisation indicator. */ 808 .itdna-single-speed-form[data-speed-risk="green"]{--itdna-speed-risk:#199454;--itdna-speed-risk-bg:#e7f8ed;--itdna-speed-risk-border:#b2e2c2} 809 .itdna-single-speed-form[data-speed-risk="yellow"]{--itdna-speed-risk:#b67705;--itdna-speed-risk-bg:#fff7e2;--itdna-speed-risk-border:#f0d396} 810 .itdna-single-speed-form[data-speed-risk="red"]{--itdna-speed-risk:#c62336;--itdna-speed-risk-bg:#fff0f1;--itdna-speed-risk-border:#ffc0c7} 811 .itdna-single-speed-form .itdna-single-gap-range{accent-color:var(--itdna-speed-risk,#199454)} 812 .itdna-single-speed-form .itdna-single-speed-choice output{color:var(--itdna-speed-risk,#199454)} 813 .itdna-single-speed-warning{max-width:900px;padding:10px 12px;border:1px solid var(--itdna-speed-risk-border,#b2e2c2);border-left:4px solid var(--itdna-speed-risk,#199454);border-radius:7px;background:var(--itdna-speed-risk-bg,#e7f8ed);color:#304056;font-size:12px;line-height:1.5;margin:12px 0} 814 815 /* v1.4.00: unmistakable live speed colours across WP themes and browsers. */ 816 .itdna-main .itdna-single-speed-form input.itdna-single-gap-range[type="range"]{ 817 -webkit-appearance:none!important;appearance:none!important; 818 background:var(--itdna-speed-risk,#199454)!important; 819 accent-color:var(--itdna-speed-risk,#199454)!important; 820 height:8px!important;border:0!important;border-radius:99px!important; 821 padding:0!important;box-shadow:none!important;outline-offset:5px; 822 } 823 .itdna-single-speed-form input.itdna-single-gap-range[type="range"]::-webkit-slider-runnable-track{ 824 height:8px!important;background:var(--itdna-speed-risk,#199454)!important;border-radius:99px!important; 825 } 826 .itdna-single-speed-form input.itdna-single-gap-range[type="range"]::-webkit-slider-thumb{ 827 -webkit-appearance:none!important;appearance:none!important;width:17px;height:17px; 828 background:var(--itdna-speed-risk,#199454)!important;border:3px solid #fff!important; 829 border-radius:50%!important;margin-top:-4.5px;box-shadow:0 0 0 1px var(--itdna-speed-risk,#199454); 830 } 831 .itdna-single-speed-form input.itdna-single-gap-range[type="range"]::-moz-range-track{ 832 background:var(--itdna-speed-risk,#199454)!important;height:8px!important;border:0;border-radius:99px; 833 } 834 .itdna-single-speed-form input.itdna-single-gap-range[type="range"]::-moz-range-thumb{ 835 background:var(--itdna-speed-risk,#199454)!important;border:3px solid #fff!important; 836 width:13px;height:13px;border-radius:50%!important; 837 } 838 .itdna-main .itdna-single-speed-form .itdna-single-speed-choice output{color:var(--itdna-speed-risk,#199454)!important} 839 .itdna-main .itdna-single-speed-form .itdna-single-speed-warning{ 840 background:var(--itdna-speed-risk-bg,#e7f8ed)!important; 841 border-color:var(--itdna-speed-risk-border,#b2e2c2)!important; 842 border-left-color:var(--itdna-speed-risk,#199454)!important; 843 } 844 845 846 /* v1.4.01: time gap uses the identical server-side risk thresholds as speed. */ 847 .itdna-single-speed-current{display:flex;align-items:flex-end;flex-direction:column;gap:7px;max-width:100%} 848 .itdna-single-speed-time{display:inline-flex;align-items:center;flex-wrap:wrap;gap:7px;border:2px solid currentColor;border-radius:11px;padding:7px 11px;background:var(--itdna-speed-risk-bg,#e7f8ed);color:var(--itdna-speed-risk,#199454);font-size:13px;font-weight:700;line-height:1.35;transition:background-color .12s,color .12s,border-color .12s} 849 .itdna-single-speed-time strong{font-size:17px;font-variant-numeric:tabular-nums;white-space:nowrap} 850 .itdna-single-speed-time [data-event-gap-severity]{font-size:10px;font-weight:850;border-radius:5px;padding:3px 6px;background:var(--itdna-speed-risk,#199454);color:#fff;letter-spacing:.04em} 851 .itdna-main .itdna-single-speed-form[data-speed-risk="red"] .itdna-single-speed-time,.itdna-main .itdna-single-speed-form[data-speed-risk="red"] .itdna-single-speed-choice output{color:#c62336!important;background-color:#fff0f1} 852 .itdna-main .itdna-single-speed-form[data-speed-risk="yellow"] .itdna-single-speed-time,.itdna-main .itdna-single-speed-form[data-speed-risk="yellow"] .itdna-single-speed-choice output{color:#946000!important;background-color:#fff7e2} 853 .itdna-main .itdna-single-speed-form[data-speed-risk="green"] .itdna-single-speed-time,.itdna-main .itdna-single-speed-form[data-speed-risk="green"] .itdna-single-speed-choice output{color:#14783f!important;background-color:#e7f8ed} 854 .itdna-main .itdna-single-speed-form .itdna-single-speed-choice output{padding:3px 7px;border-radius:6px} 855 .itdna-single-speed-form .itdna-single-gap-options span{color:#65768a} 856 .itdna-single-speed-form .itdna-single-gap-options span.itdna-gap-active{color:var(--itdna-speed-risk,#199454);font-weight:800;box-shadow:inset 0 -3px 0 var(--itdna-speed-risk,#199454)} 857 @media(max-width:600px){.itdna-single-speed-current{align-items:flex-start;width:100%}.itdna-single-speed-choice{align-items:flex-start;flex-direction:column}.itdna-single-speed-time{max-width:100%;box-sizing:border-box}} 858 859 .itdna-self-test-intro{font-size:13px;line-height:1.6} 860 .itdna-self-test-checks{display:grid;grid-template-columns:repeat(auto-fit,minmax(250px,1fr));gap:10px;margin:12px 0} 861 .itdna-self-test-check{padding:11px 13px;border:1px solid #d2d9e2;border-radius:9px;min-width:0;background:#f8fafc} 862 .itdna-self-test-check-head{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:7px} 863 .itdna-self-test-check-head strong{font-size:13px} 864 .itdna-self-test-check-head span{font-size:11px;font-weight:800;white-space:nowrap} 865 .itdna-self-test-check small{display:block;font-size:11px;line-height:1.5;overflow-wrap:anywhere;margin-top:5px} 866 .itdna-self-test-green{border-left:4px solid #199454;background:#f1faf5} 867 .itdna-self-test-red{border-left:4px solid #c62336;background:#fff6f6} 868 .itdna-self-test-neutral{border-left:4px solid #64748b;background:#f8fafc} 869 .itdna-self-test-green .itdna-self-test-check-head span{color:#14783f} 870 .itdna-self-test-red .itdna-self-test-check-head span{color:#c62336} 871 872 873 /* v1.4.04 — intuitive left-to-right speed controller; user-facing levels only. 874 * The real scheduler, gap table, concurrency and security layers are not changed. */ 875 .itdna-single-worker-console .itdna-single-speed-form{--itdna-speed-tone:#138f61;--itdna-speed-soft:#edf9f3;--itdna-speed-border:#b8e8d1} 876 .itdna-single-worker-console .itdna-single-speed-form[data-speed-risk="yellow"]{--itdna-speed-tone:#b47b0c;--itdna-speed-soft:#fff9e8;--itdna-speed-border:#f4dda0} 877 .itdna-single-worker-console .itdna-single-speed-form[data-speed-risk="red"]{--itdna-speed-tone:#cc304a;--itdna-speed-soft:#fff0f3;--itdna-speed-border:#ffc2cb} 878 .itdna-main .itdna-single-worker-console .itdna-card-body{padding:21px 24px 20px!important} 879 .itdna-speed-control-header{display:flex;align-items:center;justify-content:space-between;gap:16px;flex-wrap:wrap;background:linear-gradient(112deg,#f7fbff 0%,#f4f8ff 58%,#fff 100%);padding:15px 18px;border:1px solid #e0eafa;border-radius:15px;margin:1px 0 20px} 880 .itdna-speed-selected{display:flex;min-width:0;flex-direction:column;gap:6px} 881 .itdna-speed-overline{color:#607187;letter-spacing:.09em;font-size:10px;font-weight:800} 882 .itdna-main .itdna-single-worker-console .itdna-speed-selected output{background:transparent!important;color:var(--itdna-speed-tone)!important;font-size:clamp(19px,2vw,25px);line-height:1.25;letter-spacing:-.02em;font-weight:850;padding:0!important;border-radius:0!important} 883 .itdna-speed-subline{font-size:11px;color:#65768b;line-height:1.45} 884 .itdna-speed-indicator{display:flex;flex-direction:column;align-items:flex-end;gap:6px} 885 .itdna-speed-pill{display:inline-flex;gap:7px;align-items:center;padding:8px 12px;border-radius:999px;border:1px solid var(--itdna-speed-border);background:var(--itdna-speed-soft);color:var(--itdna-speed-tone);font-size:11px;line-height:1.25;font-weight:850;letter-spacing:.035em;white-space:nowrap;transition:background-color .15s,color .15s,border-color .15s} 886 .itdna-speed-pill i{display:block;width:8px;height:8px;background:currentColor;border-radius:999px;box-shadow:0 0 0 3px rgba(120,135,150,.09);flex:0 0 8px} 887 .itdna-speed-indicator small{color:#6c7c91;font-weight:750;font-size:10px;letter-spacing:.08em;font-variant-numeric:tabular-nums} 888 .itdna-speed-direction{display:flex;justify-content:space-between;align-items:center;gap:12px;margin:6px 2px 14px;letter-spacing:.055em;font-size:12px;font-weight:850;color:#53667c} 889 .itdna-speed-direction>span:last-child{color:#c32e48;text-align:right} 890 .itdna-speed-direction small{font-weight:650;font-size:11px;letter-spacing:0;margin-left:4px;color:#75869a} 891 .itdna-speed-rail{position:relative;height:30px;max-width:100%;display:flex;align-items:center;margin:0 0 1px;--itdna-speed-progress:60%;isolation:isolate} 892 .itdna-speed-rail::before,.itdna-speed-rail::after{content:'';position:absolute;left:0;top:50%;height:12px;transform:translateY(-50%);border-radius:999px;pointer-events:none} 893 .itdna-speed-rail::before{right:0;border:1px solid #d6e2ed;background:linear-gradient(90deg,#edf3f9,#e4ebf4);box-shadow:inset 0 2px 3px rgba(20,35,55,.08)} 894 .itdna-speed-rail::after{width:var(--itdna-speed-progress);max-width:100%;background:linear-gradient(90deg,#149968 0%,var(--itdna-speed-tone) 100%);box-shadow:inset 0 1px 1px rgba(255,255,255,.2),0 2px 6px rgba(20,60,50,.11);transition:width .1s ease,background-color .15s ease;z-index:1} 895 .itdna-main .itdna-single-worker-console input.itdna-single-gap-range[type="range"]{position:relative!important;z-index:2!important;display:block!important;direction:ltr!important;-webkit-appearance:none!important;appearance:none!important;width:100%!important;max-width:100%!important;min-width:0!important;height:30px!important;margin:0!important;padding:0!important;border:0!important;border-radius:0!important;box-shadow:none!important;background:transparent!important;cursor:pointer!important;outline:none!important;accent-color:var(--itdna-speed-tone)!important;touch-action:pan-y} 896 .itdna-main .itdna-single-worker-console input.itdna-single-gap-range[type="range"]::-webkit-slider-runnable-track{height:12px!important;background:transparent!important;border:0!important;border-radius:999px!important} 897 .itdna-main .itdna-single-worker-console input.itdna-single-gap-range[type="range"]::-moz-range-track{height:12px!important;background:transparent!important;border:0!important;border-radius:999px!important} 898 .itdna-main .itdna-single-worker-console input.itdna-single-gap-range[type="range"]::-webkit-slider-thumb{-webkit-appearance:none!important;appearance:none!important;position:relative!important;width:26px!important;height:26px!important;border:4px solid #fff!important;border-radius:50%!important;margin-top:-7px!important;background:var(--itdna-speed-tone)!important;box-shadow:0 0 0 2px var(--itdna-speed-tone),0 3px 13px rgba(20,37,61,.22)!important;transition:box-shadow .15s ease,transform .15s ease} 899 .itdna-main .itdna-single-worker-console input.itdna-single-gap-range[type="range"]::-moz-range-thumb{width:18px!important;height:18px!important;border:4px solid #fff!important;border-radius:50%!important;background:var(--itdna-speed-tone)!important;box-shadow:0 0 0 2px var(--itdna-speed-tone),0 3px 13px rgba(20,37,61,.22)!important} 900 .itdna-main .itdna-single-worker-console input.itdna-single-gap-range[type="range"]:focus-visible{outline:3px solid #2563eb!important;outline-offset:5px!important;border-radius:999px!important} 901 .itdna-single-worker-console .itdna-single-gap-options{display:grid!important;grid-template-columns:repeat(11,minmax(0,1fr))!important;column-gap:1px!important;max-width:none!important;margin:6px 0 17px!important;overflow:visible!important;white-space:normal!important;align-items:start} 902 .itdna-single-worker-console .itdna-single-gap-options span{min-width:0;padding:6px 1px 8px!important;text-align:center!important;font-size:10px!important;line-height:1.3!important;font-weight:600;color:#718298!important;box-shadow:none!important;border-bottom:2px solid transparent} 903 .itdna-single-worker-console .itdna-single-gap-options span.itdna-gap-active{color:var(--itdna-speed-tone)!important;font-weight:850!important;background:var(--itdna-speed-soft);border-bottom:2px solid var(--itdna-speed-tone);border-radius:6px 6px 0 0;box-shadow:none!important} 904 .itdna-main .itdna-single-worker-console .itdna-single-speed-warning{max-width:none!important;margin:10px 0 0!important;padding:12px 14px!important;border:1px solid var(--itdna-speed-border)!important;border-left:4px solid var(--itdna-speed-tone)!important;border-radius:10px!important;background:var(--itdna-speed-soft)!important;color:#273a50!important;font-size:12.5px!important;line-height:1.6!important} 905 .itdna-main .itdna-single-worker-console .itdna-single-gap-note{max-width:none!important;color:#62758c!important;font-size:11.5px!important;line-height:1.6!important;margin:11px 0 0!important} 906 .itdna-speed-preview-note{display:flex;align-items:center;gap:4px;color:#925b06;background:#fff7e7;border:1px solid #f3dfae;padding:9px 12px;border-radius:8px;margin:10px 0 0;font-size:12px;font-weight:650} 907 .itdna-speed-preview-note[hidden]{display:none!important} 908 .itdna-single-worker-console .itdna-single-gap-actions{margin-top:17px;gap:10px} 909 .itdna-main .itdna-single-worker-console .itdna-single-gap-actions .button{border-radius:9px!important;min-height:38px!important;padding:8px 16px!important;font-weight:750!important;box-shadow:0 3px 8px rgba(27,65,96,.06)} 910 .itdna-main .itdna-single-worker-console .itdna-single-gap-actions .button-primary{background:#214ed5!important;color:#fff!important;border-color:#214ed5!important} 911 @media(max-width:760px){.itdna-speed-control-header{padding:14px;gap:12px}.itdna-single-worker-console .itdna-single-gap-options span{font-size:9px!important}.itdna-single-worker-console .itdna-single-gap-options span:nth-child(2),.itdna-single-worker-console .itdna-single-gap-options span:nth-child(3),.itdna-single-worker-console .itdna-single-gap-options span:nth-child(4),.itdna-single-worker-console .itdna-single-gap-options span:nth-child(5),.itdna-single-worker-console .itdna-single-gap-options span:nth-child(6),.itdna-single-worker-console .itdna-single-gap-options span:nth-child(8),.itdna-single-worker-console .itdna-single-gap-options span:nth-child(9),.itdna-single-worker-console .itdna-single-gap-options span:nth-child(10){visibility:hidden}.itdna-single-worker-console .itdna-single-gap-options span.itdna-gap-active{visibility:visible!important}} 912 @media(max-width:490px){.itdna-main .itdna-single-worker-console .itdna-card-body{padding:14px!important}.itdna-speed-direction{font-size:11px}.itdna-speed-direction small{display:block;margin:3px 0 0;font-size:10px}.itdna-speed-overline{font-size:9px}.itdna-speed-control-header{align-items:flex-start}.itdna-speed-indicator{align-items:flex-start}.itdna-speed-pill{padding:7px 9px;font-size:10px}.itdna-main .itdna-single-worker-console .itdna-speed-selected output{font-size:19px!important}} 913 @media(prefers-reduced-motion:reduce){.itdna-speed-rail::after,.itdna-speed-pill{transition:none!important}} 914 915 /* v1.4.06 - Easy Setup is a one-time default; user overrides are explicitly explained. */ 916 .itdna-easy-manual-note{margin:8px 0 0!important;color:#31516e;font-size:12px;line-height:1.65;max-width:800px}.itdna-easy-manual-note strong{color:#155e75} 917 918 /* v1.4.17: Search across every Turbo Cache admin tab. Read-only; no user settings are modified. */ 919 .itdna-sidebar .itdna-global-search{position:relative;margin:0 3px 14px;padding:10px 9px 9px;border:1px solid rgba(117,161,225,.29);border-radius:11px;background:rgba(255,255,255,.055);color:#e8f0ff;box-sizing:border-box} 920 .itdna-global-search>label{display:flex;justify-content:space-between;gap:6px;align-items:center;font-size:12px;font-weight:700;margin-bottom:7px;color:#f2f7ff} 921 .itdna-global-search>label span{font-size:10px;color:#adc5ee;font-weight:600;padding:2px 5px;border:1px solid #4c6588;border-radius:5px;white-space:nowrap} 922 .itdna-search-input-wrap{display:flex;align-items:center;gap:5px;background:#fff;border-radius:8px;border:2px solid transparent;padding:0 7px;min-height:39px;box-sizing:border-box} 923 .itdna-search-input-wrap:focus-within{border-color:#6eafff;box-shadow:0 0 0 2px rgba(77,149,255,.16)} 924 .itdna-search-input-wrap>span{color:#5e789e;font-size:21px;line-height:1} 925 .itdna-search-input-wrap input[type=search]{display:block;min-width:0;width:100%;height:35px;min-height:0;margin:0!important;padding:5px 2px!important;color:#193357!important;border:0!important;outline:none!important;box-shadow:none!important;background:#fff!important;font-size:12px!important} 926 .itdna-search-input-wrap input[type=search]::-webkit-search-cancel-button{-webkit-appearance:none;appearance:none} 927 .itdna-search-input-wrap button{flex:0 0 19px;background:none;border:0;padding:1px;color:#526b8e;cursor:pointer;font-size:20px;line-height:1} 928 .itdna-search-input-wrap button[hidden],.itdna-search-results[hidden]{display:none!important} 929 .itdna-search-hint{font-size:10.5px;color:#a8bedc;margin:6px 2px 0;line-height:1.4} 930 .itdna-search-results{display:flex;flex-direction:column;max-height:300px;overflow:auto;overscroll-behavior:contain;margin-top:8px;padding:4px;background:#0f2647;border:1px solid #365577;border-radius:9px;box-shadow:0 10px 22px rgba(0,0,0,.17)} 931 .itdna-search-result{display:flex;flex-direction:column;gap:3px;text-decoration:none!important;padding:8px;border-radius:6px;color:#e8f3ff!important;border-bottom:1px solid rgba(255,255,255,.06)} 932 .itdna-search-result:hover,.itdna-search-result:focus-visible,.itdna-search-result[aria-selected=true]{background:#254c78!important;color:#fff!important;outline:1px solid rgba(255,255,255,.22)} 933 .itdna-search-result-title{font-weight:700;font-size:11.5px;line-height:1.3;overflow-wrap:anywhere} 934 .itdna-search-result small{font-size:10px;color:#b6d1ee;line-height:1.35;overflow-wrap:anywhere} 935 .itdna-search-empty{color:#d0ddeb;padding:11px 8px;font-size:11px;line-height:1.5} 936 .itdna-search-more{width:100%;min-height:32px;padding:7px;background:#173b64;border:1px solid #3c6896;border-radius:6px;color:#e6f2ff;font-size:11px;cursor:pointer} 937 .itdna-search-more:hover{background:#2b547d} 938 .itdna-main .itdna-search-focus{outline:3px solid #ffba49!important;outline-offset:3px;background-color:#fff8df!important;border-radius:8px;scroll-margin:100px} 939 .itdna-main .itdna-card.itdna-search-focus{outline-offset:2px} 940 @media (max-width:782px){.itdna-sidebar .itdna-global-search{max-width:none}.itdna-search-results{max-height:230px}} 941 942 /* v1.4.18: pending self-test probes are not safety failures or verified passes. */ 943 .itdna-self-test-pending{border-left:4px solid #d69e1f;background:#fff9e9} 944 .itdna-self-test-pending .itdna-self-test-check-head span{color:#905b00} 945 946 /* v1.4.54: compact one-line sidebar navigation, layout-only change. */ 947 /* Give long tab labels room without reducing the text size or touching page content. */ 948 .itdna-shell{grid-template-columns:270px minmax(0,1fr)!important} 949 .itdna-sidebar nav a{white-space:nowrap!important;overflow:hidden!important;text-overflow:ellipsis!important;min-width:0!important;min-height:18px!important} 950 .itdna-sidebar nav a>span{flex:0 0 17px!important;width:17px!important} 951 @media (max-width:1100px) and (min-width:901px){.itdna-shell{grid-template-columns:255px minmax(0,1fr)!important}} 952 @media (max-width:900px) and (min-width:783px){.itdna-shell{grid-template-columns:245px minmax(0,1fr)!important}} 953 @media (max-width:782px){.itdna-shell{display:block!important}.itdna-sidebar nav{grid-template-columns:repeat(auto-fit,minmax(230px,1fr))!important}} 954 955 /* v1.4.64: Turbo 10x settings IA — scoped to this tab; no other UI is changed. */ 956 #itdna-turbo-10x-duper-speed>.itdna-card-body{padding:16px!important} 957 #itdna-turbo-10x-duper-speed .itdna-wsa-section{ 958 border:1px solid #e0e7f0;border-radius:11px;padding:16px 18px; 959 margin:0 0 14px;box-sizing:border-box;min-width:0;overflow-wrap:anywhere; 960 background:#fafcff;box-shadow:0 1px 2px rgba(28,49,84,.022) 961 } 962 #itdna-turbo-10x-duper-speed .itdna-wsa-section-status{background:#f3f8ff;border-color:#dce8f8} 963 #itdna-turbo-10x-duper-speed .itdna-wsa-section-connection{background:#f5fbf7;border-color:#d9ebdf} 964 #itdna-turbo-10x-duper-speed .itdna-wsa-section-sync{background:#fffaf3;border-color:#f0e6d3} 965 #itdna-turbo-10x-duper-speed .itdna-wsa-section-delivery{background:#f5f9ff;border-color:#dfe9f7} 966 #itdna-turbo-10x-duper-speed .itdna-wsa-section-cache{background:#f7f8fd;border-color:#e2e4f1} 967 #itdna-turbo-10x-duper-speed .itdna-wsa-section-oauth{background:#f8f7fc;border-color:#e6e1f0} 968 #itdna-turbo-10x-duper-speed .itdna-wsa-section-cleanup{background:#fffafa;border-color:#f0e1e1} 969 #itdna-turbo-10x-duper-speed .itdna-wsa-section>h3{ 970 margin:0 0 8px!important;padding:0 0 9px!important; 971 border-bottom:1px solid rgba(62,83,122,.12); 972 color:#1e3354!important;font-size:15px!important;font-weight:700!important; 973 line-height:1.4!important;letter-spacing:0!important 974 } 975 #itdna-turbo-10x-duper-speed .itdna-wsa-section>h3 small{font-weight:400;color:#657792;font-size:11.5px} 976 #itdna-turbo-10x-duper-speed .itdna-wsa-section-intro{margin:2px 0 14px;color:#63728b;font-size:12px;line-height:1.65} 977 #itdna-turbo-10x-duper-speed .itdna-wsa-section .itdna-grid-4{ 978 display:grid!important;grid-template-columns:repeat(auto-fit,minmax(205px,1fr))!important; 979 gap:11px!important;margin:10px 0 14px!important;align-items:stretch!important 980 } 981 #itdna-turbo-10x-duper-speed .itdna-wsa-section .itdna-grid-4>.itdna-field{ 982 min-width:0!important;max-width:none!important;margin:0!important;padding:11px 12px!important; 983 background:rgba(255,255,255,.9);border:1px solid #e2e9f2;border-radius:9px; 984 color:#274268!important;line-height:1.55!important;box-sizing:border-box 985 } 986 #itdna-turbo-10x-duper-speed .itdna-wsa-section .itdna-grid-4>.itdna-field strong{ 987 display:block;margin-bottom:5px!important;font-size:12.5px!important;line-height:1.4!important 988 } 989 #itdna-turbo-10x-duper-speed .itdna-wsa-section .itdna-grid-4 input{ 990 width:100%!important;min-width:0!important;max-width:100%!important;margin-top:6px!important 991 } 992 #itdna-turbo-10x-duper-speed .itdna-wsa-section .description{ 993 color:#596a82!important;line-height:1.65!important;font-size:12px!important 994 } 995 #itdna-turbo-10x-duper-speed .itdna-wsa-section .itdna-info{ 996 background:rgba(255,255,255,.88)!important;border:1px solid #e2e9f2; 997 border-radius:9px;padding:12px!important;line-height:1.75!important; 998 margin:10px 0!important;overflow-wrap:anywhere 999 } 1000 #itdna-turbo-10x-duper-speed .itdna-wsa-section .itdna-warn{ 1001 border:1px solid #f0d5bc;background:#fff8ee;padding:11px 12px;border-radius:8px; 1002 overflow-wrap:anywhere 1003 } 1004 #itdna-turbo-10x-duper-speed .itdna-wsa-section code{white-space:normal;overflow-wrap:anywhere} 1005 #itdna-turbo-10x-duper-speed .itdna-wsa-section .itdna-actions{ 1006 gap:8px!important;margin:12px 0 8px!important;align-items:center!important 1007 } 1008 #itdna-turbo-10x-duper-speed .itdna-wsa-section button{white-space:normal!important;text-align:center!important} 1009 #itdna-turbo-10x-duper-speed .itdna-wsa-subdetails{ 1010 margin:10px 0 2px;background:rgba(255,255,255,.88); 1011 border:1px solid #e0e7f1;border-radius:9px;padding:0 12px;min-width:0 1012 } 1013 #itdna-turbo-10x-duper-speed .itdna-wsa-subdetails>summary{ 1014 display:list-item;cursor:pointer;padding:12px 4px;color:#284e86; 1015 font-weight:650;font-size:12.5px;line-height:1.5 1016 } 1017 #itdna-turbo-10x-duper-speed .itdna-wsa-subdetails[open]{padding-bottom:12px} 1018 #itdna-turbo-10x-duper-speed .itdna-wsa-subdetails>summary:focus-visible{outline:2px solid #4387dc;outline-offset:2px} 1019 #itdna-turbo-10x-duper-speed .itdna-wsa-section>p>label{line-height:1.7} 1020 #itdna-turbo-10x-duper-speed .itdna-wsa-section-cache .itdna-info{margin:10px 0!important} 1021 /* Guide is a separate lower accordion; each language's steps are legible rows. */ 1022 #itdna-workers-setup-guide>.itdna-card-body{padding:17px!important} 1023 #itdna-workers-setup-guide .itdna-wsa-guide-hi, 1024 #itdna-workers-setup-guide .itdna-wsa-guide-en{min-width:0;line-height:1.7;font-size:12.5px;overflow-wrap:anywhere} 1025 #itdna-workers-setup-guide .itdna-wsa-guide-hi>p, 1026 #itdna-workers-setup-guide .itdna-wsa-guide-en>p{ 1027 margin-bottom:12px!important;padding:11px 13px!important; 1028 background:#f4f9ff;border:1px solid #deebf8;border-radius:8px;line-height:1.7 1029 } 1030 #itdna-workers-setup-guide .itdna-wsa-guide-hi>h3, 1031 #itdna-workers-setup-guide .itdna-wsa-guide-en>h3{font-size:14px!important;color:#1e3354;margin:17px 0 12px!important} 1032 #itdna-workers-setup-guide .itdna-wsa-guide-hi>ol, 1033 #itdna-workers-setup-guide .itdna-wsa-guide-en>ol{ 1034 display:grid;gap:10px;list-style:decimal!important; 1035 padding:0 0 0 26px!important;margin:12px 0 14px!important 1036 } 1037 #itdna-workers-setup-guide .itdna-wsa-guide-hi>ol>li, 1038 #itdna-workers-setup-guide .itdna-wsa-guide-en>ol>li{ 1039 padding:12px 14px!important;margin:0!important;border:1px solid #e0e7f0; 1040 border-radius:9px;line-height:1.72;background:#f5f9ff 1041 } 1042 #itdna-workers-setup-guide .itdna-wsa-guide-hi>ol>li:nth-child(even), 1043 #itdna-workers-setup-guide .itdna-wsa-guide-en>ol>li:nth-child(even){background:#f6faf7;border-color:#dce9df} 1044 #itdna-workers-setup-guide .itdna-wsa-guide-hi>ol>li::marker, 1045 #itdna-workers-setup-guide .itdna-wsa-guide-en>ol>li::marker{font-weight:700;color:#325da0} 1046 #itdna-workers-setup-guide a{overflow-wrap:anywhere} 1047 @media (max-width:800px){ 1048 #itdna-turbo-10x-duper-speed>.itdna-card-body{padding:10px!important} 1049 #itdna-turbo-10x-duper-speed .itdna-wsa-section{padding:12px!important;margin-bottom:11px} 1050 #itdna-turbo-10x-duper-speed .itdna-wsa-section .itdna-grid-4{grid-template-columns:1fr!important} 1051 #itdna-workers-setup-guide>.itdna-card-body{padding:11px!important} 1052 } 1053 1054 /* v1.4.84: borderline cache-probe regressions stay amber, never false red. */ 1055 .itdna-easy-verdict.warn{border:1px solid #edcd80;background:#fffbeb;color:#80550b} 1056 1057 /* Free edition · native in-row premium preview without changing settings layout. */ 1058 .itdna-wrap .itdna-pro-badge{display:inline-flex;align-items:center;margin:0 5px;padding:2px 7px;border-radius:6px;background:#ede9fe;color:#5b21b6;font-size:10px;line-height:1.4;font-weight:800;letter-spacing:.08em;vertical-align:middle} 1059 .itdna-wrap .itdna-pro-link{display:inline;font-size:12px;font-weight:700;color:#5b21b6;text-decoration:none} 1060 .itdna-wrap .itdna-pro-link:hover{text-decoration:underline} 1061 .itdna-wrap .itdna-field input:disabled,.itdna-wrap .itdna-field select:disabled{opacity:.75;cursor:not-allowed} -
indiatvdna-turbo-cache-lite/trunk/assets/admin.js
r3729643 r3763637 1 (function () { 2 'use strict'; 3 if (!window.itdnaTcLite) return; 4 5 function findMetric(label) { 6 var cards = document.querySelectorAll('#itdna-live-stats .itdna-metric'); 7 for (var i = 0; i < cards.length; i++) { 8 var first = cards[i].querySelector('span'); 9 if (first && first.textContent.replace(/PRO/g, '').trim() === label) return cards[i]; 1 (function(){ 2 'use strict'; 3 if (window.__itdnaTurboAdminLoaded) return; 4 window.__itdnaTurboAdminLoaded = true; 5 window.ITDNA_TC_ADMIN_GEN=window.ITDNA_TC_ADMIN_GEN||0; 6 var itdnaBusyHideTimer=null; 7 function itdnaBusyNotice(message){ 8 var el=document.getElementById('itdna-global-busy'); 9 if(!el){ 10 el=document.createElement('div');el.id='itdna-global-busy';el.className='itdna-global-busy';el.setAttribute('role','status');el.setAttribute('aria-live','polite'); 11 el.innerHTML='<span class="itdna-busy-spinner" aria-hidden="true"></span><span class="itdna-busy-text"></span>'; 12 document.body.appendChild(el); 13 } 14 if(itdnaBusyHideTimer){clearTimeout(itdnaBusyHideTimer);itdnaBusyHideTimer=null;} 15 var label=el.querySelector('.itdna-busy-text');if(label)label.textContent=message||'Working…'; 16 el.classList.add('show'); 17 } 18 function itdnaBusyClear(delay){ 19 var run=function(){var el=document.getElementById('itdna-global-busy');if(el)el.classList.remove('show');}; 20 if(delay){itdnaBusyHideTimer=setTimeout(run,delay);}else run(); 21 } 22 function itdnaWorkingText(label){ 23 var t=String(label||'').trim(); 24 if(/self[- ]?test|test/i.test(t))return 'Testing…'; 25 if(/purge|clear/i.test(t))return 'Purging…'; 26 if(/save|apply/i.test(t))return 'Saving…'; 27 if(/scan|analy/i.test(t))return 'Analyzing…'; 28 if(/preload|warm/i.test(t))return 'Starting…'; 29 return 'Working…'; 30 } 31 function itdnaBindGlobalActionFeedback(){ 32 if(window.__itdnaActionFeedbackBound)return;window.__itdnaActionFeedbackBound=1; 33 document.addEventListener('click',function(e){ 34 if(e.defaultPrevented||e.button!==0)return; 35 var link=e.target&&e.target.closest?e.target.closest('a.itdna-action-link, #wp-admin-bar-itdna-turbo-cache-purge > a'):null; 36 if(!link)return; 37 if(link.getAttribute('data-itdna-working')==='1'){e.preventDefault();return;} 38 var original=String(link.textContent||'').trim(); 39 link.setAttribute('data-itdna-working','1');link.setAttribute('aria-busy','true');link.classList.add('itdna-is-working'); 40 if(!link.getAttribute('data-itdna-original-label'))link.setAttribute('data-itdna-original-label',original); 41 var working=itdnaWorkingText(original);link.textContent=working;itdnaBusyNotice(working+' Please wait — the request is running.'); 42 }); 43 document.addEventListener('submit',function(e){ 44 if(e.defaultPrevented)return; 45 var form=e.target;if(!form||!form.closest||!form.closest('.itdna-wrap'))return; 46 if(form.getAttribute('data-itdna-submitting')==='1'){e.preventDefault();return;} 47 form.setAttribute('data-itdna-submitting','1'); 48 var btn=(e.submitter&&e.submitter.matches&&e.submitter.matches('button,input[type=submit]'))?e.submitter:form.querySelector('button[type=submit],input[type=submit]'); 49 if(btn){ 50 var old=(btn.value||btn.textContent||'Save'); 51 btn.setAttribute('data-itdna-original-label',old); 52 // A disabled submitter is not a successful form control. Preserve its exact 53 // name/value before disabling it so named actions such as Cloudflare 54 // verify/detect, CDN test and LiteSpeed verify still reach PHP. 55 var submitName=btn.getAttribute('name'); 56 if(submitName){ 57 var mirror=document.createElement('input'); 58 mirror.type='hidden';mirror.name=submitName;mirror.value=btn.value||''; 59 mirror.setAttribute('data-itdna-submit-mirror','1'); 60 form.appendChild(mirror); 61 } 62 btn.disabled=true; 63 if(btn.tagName==='INPUT')btn.value='Saving…';else btn.textContent='Saving…'; 64 } 65 itdnaBusyNotice('Saving… Please wait — your changes are being applied.'); 66 }); 67 } 68 function itdnaDedupeNotices(){ 69 var nodes=Array.prototype.slice.call(document.querySelectorAll('.itdna-main .itdna-notice, #wpbody-content .notice')); 70 var seen={}; 71 nodes.forEach(function(n){ 72 var key=String(n.textContent||'').replace(/\s+/g,' ').trim();if(!key)return; 73 var isSelf=/^Cache self-test\s*[—-]/i.test(key); 74 var failed=isSelf&&/(FAILED BYPASS|NOT VERIFIED|\bFAILED\b|\bERROR\b)/i.test(key); 75 if(failed){n.classList.remove('success','notice-success');n.classList.add('error');if(n.classList.contains('notice'))n.classList.add('notice-error');} 76 if(!isSelf && !n.classList.contains('itdna-notice'))return; 77 var rank=(n.classList.contains('error')||n.classList.contains('notice-error'))?3:((n.classList.contains('warning')||n.classList.contains('notice-warning'))?2:1); 78 if(!seen[key]){seen[key]={node:n,rank:rank};return;} 79 if(rank>seen[key].rank){if(seen[key].node&&seen[key].node.parentNode)seen[key].node.parentNode.removeChild(seen[key].node);seen[key]={node:n,rank:rank};} 80 else if(n.parentNode)n.parentNode.removeChild(n); 81 }); 82 } 83 function itdnaInitAdminMain(){ 84 var gen=++window.ITDNA_TC_ADMIN_GEN; 85 var viewMain=document.querySelector('.itdna-main'); 86 if(!viewMain)return; 87 itdnaDedupeNotices(); 88 var gapPanel=viewMain.querySelector('[data-itdna-single-speed]'); 89 if(gapPanel){ 90 // The slider now progresses naturally: LEFT = lower speed, RIGHT = higher speed. 91 // Reverse ONLY its presentation. Saved scheduler milliseconds remain the same. 92 var gapValues=[2000,1000,900,800,700,600,500,400,300,200,100]; 93 var speedNames=['Minimum Speed','Eco','Eco Plus','Gentle','Steady','Smooth','Balanced · Best','Very Fast','Ultra Fast','Extreme','Max Speed']; 94 var slider=gapPanel.querySelector('[data-event-gap-slider]'); 95 var stored=gapPanel.querySelector('[data-event-gap-value]'); 96 var output=gapPanel.querySelector('[data-event-gap-output]'); 97 var riskForm=gapPanel.querySelector('[data-speed-risk]'); 98 var riskNote=gapPanel.querySelector('[data-speed-risk-note]'); 99 var status=gapPanel.querySelector('[data-event-gap-severity]'); 100 var level=gapPanel.querySelector('[data-speed-level]'); 101 var rail=gapPanel.querySelector('.itdna-speed-rail'); 102 var preview=gapPanel.querySelector('[data-speed-preview-note]'); 103 var gapTicks=gapPanel.querySelectorAll('.itdna-single-gap-options span'); 104 function syncGap(){ 105 if(!slider||!stored)return; 106 var index=Math.max(0,Math.min(10,Number(slider.value)||0)); 107 stored.value=String(gapValues[index]); 108 if(output)output.textContent=speedNames[index]; 109 slider.setAttribute('aria-valuetext',speedNames[index]); 110 var risk=index>=8?'red':(index===7?'yellow':'green'); 111 if(riskForm)riskForm.setAttribute('data-speed-risk',risk); 112 if(rail)rail.style.setProperty('--itdna-speed-progress',String(index*10)+'%'); 113 if(status)status.textContent=risk==='red'?'HIGH INTENSITY':(risk==='yellow'?'USE WITH CARE':(index===6?'RECOMMENDED':'LOWER ACTIVITY')); 114 if(level)level.textContent='LEVEL '+String(index+1)+' / 11'; 115 Array.prototype.forEach.call(gapTicks,function(tick,i){tick.classList.toggle('itdna-gap-active',i===index);}); 116 if(riskNote)riskNote.textContent=risk==='red' 117 ? '⚠ High-speed setting. Background jobs may start more frequently. Watch your hosting CPU/RAM and PHP errors.' 118 : (risk==='yellow' 119 ? '⚠ Faster processing selected. Check hosting resource usage during heavy background work.' 120 : (index===6 121 ? '✓ Recommended balance for most sites. A good starting point for background optimization.' 122 : '✓ Lower background activity selected. Jobs may start less frequently.')); 123 var initial=riskForm?Number(riskForm.getAttribute('data-original-speed-step')):index; 124 if(preview)preview.hidden=(index===initial); 125 } 126 if(slider){slider.addEventListener('input',syncGap);slider.addEventListener('change',syncGap);syncGap();} 127 } 128 function alive(){return gen===window.ITDNA_TC_ADMIN_GEN&&viewMain.isConnected;} 129 viewMain.querySelectorAll('input[type=password]').forEach(function(el){ 130 var wrap=document.createElement('div');wrap.className='itdna-password-wrap'; 131 el.parentNode.insertBefore(wrap,el);wrap.appendChild(el); 132 var b=document.createElement('button');b.type='button';b.className='button';b.textContent='Show';b.style.marginLeft='8px'; 133 b.addEventListener('click',function(){var show=el.type==='password';el.type=show?'text':'password';b.textContent=show?'Hide':'Show';});wrap.appendChild(b); 134 }); 135 viewMain.querySelectorAll('[data-itdna-speed-restore]').forEach(function(btn){ 136 btn.addEventListener('click',function(ev){ 137 if(!window.confirm('Restore recommended background speed? Existing cache and media will not be cleared.'))ev.preventDefault(); 138 }); 139 }); 140 viewMain.querySelectorAll('button, a.itdna-action-link').forEach(function(btn){ 141 if(!btn.hasAttribute('data-itdna-speed-restore') && /purge|cleanup|reset/i.test(btn.textContent))btn.addEventListener('click',function(e){ 142 if(/reset/i.test(btn.textContent)&&!window.confirm('Restore safe defaults and clear local cache?'))e.preventDefault(); 143 }); 144 }); 145 146 147 function itdnaBindCategoryAccordions(root){ 148 if(!root) return; 149 var tab=(root.getAttribute('data-itdna-tab')||'').toLowerCase(); 150 // The Dashboard uses the same single-open accordion as other tabs. 151 // Its first section (Smart Background Speed) is expanded by default. 152 153 var cards=Array.prototype.slice.call(root.querySelectorAll('.itdna-card')).filter(function(card){ 154 if(card.closest('[data-itdna-auto-choice]')) return false; 155 if(card.classList.contains('itdna-category-host') || card.querySelector(':scope > .itdna-card-body > .itdna-category-stack')) return false; 156 return card.querySelector(':scope > .itdna-card-head') && card.querySelector(':scope > .itdna-card-body'); 157 }); 158 var categories=Array.prototype.slice.call(root.querySelectorAll('.itdna-option-category')); 159 160 function setCard(card,open){ 161 var head=card.querySelector(':scope > .itdna-card-head'); 162 var body=card.querySelector(':scope > .itdna-card-body'); 163 var indicator=head?head.querySelector('.itdna-accordion-indicator'):null; 164 if(!head||!body)return; 165 card.classList.toggle('itdna-acc-open',!!open); 166 card.classList.toggle('itdna-acc-collapsed',!open); 167 head.setAttribute('aria-expanded',open?'true':'false'); 168 if(indicator)indicator.textContent=open?'−':'+'; 169 body.hidden=!open; 170 } 171 function setCategory(cat,open){ 172 var trigger=cat.querySelector(':scope > .itdna-option-category-trigger'); 173 var body=cat.querySelector(':scope > .itdna-option-category-body'); 174 var icon=trigger?trigger.querySelector('.itdna-option-category-icon'):null; 175 if(!trigger||!body)return; 176 cat.classList.toggle('itdna-category-open',!!open); 177 trigger.setAttribute('aria-expanded',open?'true':'false'); 178 if(icon)icon.textContent=open?'−':'+'; 179 body.hidden=!open; 180 } 181 function closeEverything(except){ 182 cards.forEach(function(card){if(card!==except)setCard(card,false);}); 183 categories.forEach(function(cat){if(cat!==except)setCategory(cat,false);}); 184 } 185 function toggleUnit(unit,type){ 186 var open=type==='card'?unit.classList.contains('itdna-acc-open'):unit.classList.contains('itdna-category-open'); 187 if(open){ 188 if(type==='card')setCard(unit,false);else setCategory(unit,false); 189 var stack=unit.closest('.itdna-category-stack')||unit.parentElement; 190 if(stack)window.requestAnimationFrame(function(){try{stack.scrollIntoView({block:'nearest',behavior:'smooth'});}catch(err){}}); 191 return; 192 } 193 closeEverything(unit); 194 if(type==='card')setCard(unit,true);else setCategory(unit,true); 195 window.requestAnimationFrame(function(){try{unit.scrollIntoView({block:'nearest',behavior:'smooth'});}catch(err){}}); 196 } 197 198 cards.forEach(function(card){ 199 var head=card.querySelector(':scope > .itdna-card-head'); 200 if(!head)return; 201 if(card.getAttribute('data-itdna-accordion-ready')!=='1'){ 202 card.setAttribute('data-itdna-accordion-ready','1'); 203 card.classList.add('itdna-accordion-card'); 204 head.setAttribute('role','button');head.setAttribute('tabindex','0');head.classList.add('itdna-accordion-head'); 205 var indicator=document.createElement('span');indicator.className='itdna-accordion-indicator';indicator.setAttribute('aria-hidden','true');head.appendChild(indicator); 206 head.addEventListener('click',function(e){if(e.target&&e.target.closest('a,button,input,select,textarea,label'))return;toggleUnit(card,'card');}); 207 head.addEventListener('keydown',function(e){if(e.key==='Enter'||e.key===' '){e.preventDefault();toggleUnit(card,'card');}}); 208 } 209 setCard(card,false); 210 }); 211 212 categories.forEach(function(cat){ 213 var trigger=cat.querySelector(':scope > .itdna-option-category-trigger'); 214 if(!trigger)return; 215 if(cat.getAttribute('data-itdna-category-ready')!=='1'){ 216 cat.setAttribute('data-itdna-category-ready','1'); 217 trigger.addEventListener('click',function(){toggleUnit(cat,'category');}); 218 } 219 setCategory(cat,false); 220 }); 221 222 // A page may nominate one primary section to be visible immediately. 223 // Opening any other section closes it; once closed it behaves like every 224 // other accordion and shows the + affordance until the user reopens it. 225 // On Workers Save/Test/Run return to the dedicated tab, expand the 226 // Workers accordion so its notice and fields remain visible. 227 var r2Return=tab==='turbo10x' && window.location.hash==='#itdna-turbo-10x-duper-speed' 228 ? root.querySelector('#itdna-turbo-10x-duper-speed.itdna-card') : null; 229 var defaultOpen=r2Return || (tab==='dashboard' ? (cards.length?cards[0]:null) : root.querySelector('.itdna-card.itdna-default-open, .itdna-option-category.itdna-default-open')); 230 if(defaultOpen){ 231 closeEverything(defaultOpen); 232 if(defaultOpen.classList.contains('itdna-card'))setCard(defaultOpen,true); 233 else setCategory(defaultOpen,true); 234 } 235 } 236 237 itdnaBindCategoryAccordions(viewMain); 238 239 /* 240 * Live cache dashboard: lightweight admin-only polling. This intentionally 241 * uses AJAX instead of WebSockets so it works on ordinary shared hosting. 242 * It pauses when the admin tab is hidden and never touches public requests. 243 */ 244 /* 245 * Intelligent v2.5 optimizer. Each stage is one authenticated AJAX request; 246 * this makes progress visible and prevents a single long admin request from 247 * attempting every optimization at once. 248 */ 249 var autoRoot=viewMain.querySelector('[data-itdna-auto-engine]'); 250 if(autoRoot && window.ITDNA_TC_LIVE && ITDNA_TC_LIVE.ajaxUrl && ITDNA_TC_LIVE.autoNonce){ 251 var autoJobId=''; 252 var autoBusy=false; 253 var autoTimer=null; 254 var autoNextDelay=10000; 255 var autoStart=autoRoot.querySelector('[data-itdna-auto-start]'); 256 var autoRollback=autoRoot.querySelector('[data-itdna-auto-rollback]'); 257 var autoStatus=autoRoot.querySelector('[data-itdna-auto-status]'); 258 var autoSite=autoRoot.querySelector('[data-itdna-auto-site]'); 259 var autoProfile=autoRoot.querySelector('[data-itdna-auto-profile]'); 260 var autoRisk=autoRoot.querySelector('[data-itdna-auto-risk]'); 261 var autoBar=autoRoot.querySelector('[data-itdna-auto-progress]'); 262 var autoProgressText=autoRoot.querySelector('[data-itdna-auto-progress-text]'); 263 var autoSteps=autoRoot.querySelector('[data-itdna-auto-steps]'); 264 var autoResults=autoRoot.querySelector('[data-itdna-auto-results]'); 265 var autoChoice=document.querySelector('[data-itdna-auto-choice]'); 266 var autoChoiceButtons=autoChoice?autoChoice.querySelectorAll('[data-itdna-auto-mode]'):[]; 267 var autoChoiceClose=autoChoice?autoChoice.querySelectorAll('[data-itdna-auto-choice-close]'):[]; 268 269 function openAutoChoice(){if(!autoChoice)return;autoChoice.hidden=false;document.body.classList.add('itdna-modal-open');} 270 function closeAutoChoice(){if(!autoChoice)return;autoChoice.hidden=true;document.body.classList.remove('itdna-modal-open');} 271 function startAutoMode(mode){ 272 if(autoBusy)return; 273 closeAutoChoice(); autoStart.disabled=true; autoSetStatus(mode==='aggressive'?'Starting Max Load…':'Starting Hosting-Aware…'); 274 if(autoProgressText)autoProgressText.textContent=mode==='aggressive'?'Preparing the Aggressive Max Load plan with safety guards…':'Fresh-detecting hosting resources and preparing the recommended plan…'; 275 autoPost('itdna_tc_auto_start',{mode:mode}).then(function(d){autoJobId=d.id||'';autoRender(d);autoPoll();}).catch(function(e){autoStart.disabled=false;autoSetStatus('Error');if(autoProgressText)autoProgressText.textContent=e.message||'Could not start Auto Optimize.';}); 276 } 277 278 function autoPost(action,extra){ 279 var body=new URLSearchParams(); body.set('action',action); body.set('nonce',ITDNA_TC_LIVE.autoNonce||''); 280 Object.keys(extra||{}).forEach(function(k){body.set(k,extra[k]);}); 281 return fetch(ITDNA_TC_LIVE.ajaxUrl,{method:'POST',credentials:'same-origin',headers:{'Content-Type':'application/x-www-form-urlencoded; charset=UTF-8'},body:body.toString(),cache:'no-store'}).then(function(r){if(!r.ok)throw new Error('HTTP '+r.status);return r.json();}).then(function(j){if(!j||!j.success)throw new Error((j&&j.data&&j.data.message)||'Auto optimizer request failed');return j.data;}); 282 } 283 function autoSetStatus(text){if(autoStatus)autoStatus.textContent=text;} 284 function autoRender(d){ 285 if(!d)return; 286 autoJobId=d.id||autoJobId; 287 var serverDelay=parseInt(d.next_delay_ms||0,10); 288 if(serverDelay>0)autoNextDelay=Math.max(1000,Math.min(120000,serverDelay)); 289 if(autoSite&&d.site_type)autoSite.textContent=d.site_type; 290 if(autoProfile&&d.profile)autoProfile.textContent=d.profile.charAt(0).toUpperCase()+d.profile.slice(1); 291 if(autoRisk&&d.risk_score!==null&&d.risk_score!==undefined&&d.confidence!==null&&d.confidence!==undefined&&Number.isFinite(Number(d.risk_score))&&Number.isFinite(Number(d.confidence)))autoRisk.textContent=Number(d.risk_score)+'/100 · '+Number(d.confidence)+'%'; 292 if(autoStart)autoStart.disabled=d.status==='running'; 293 if(autoRollback)autoRollback.disabled=!d.id || d.status==='idle' || d.status==='rolled_back' || d.status==='rollback_failed'; 294 var steps=d.steps||[], done=0, current=-1; 295 steps.forEach(function(st,i){if(st.status==='done'||st.status==='skipped')done++;if(st.status==='running')current=i;}); 296 var pct=steps.length?Math.round((done/steps.length)*100):0; 297 if(d.status==='complete')pct=100; 298 if(autoBar)autoBar.style.width=pct+'%'; 299 if(autoProgressText){ 300 if(d.status==='running'&&d.pause_reason)autoProgressText.textContent=String(d.pause_reason)+' Next safe check in about '+Math.max(1,Math.round(autoNextDelay/1000))+'s.'; 301 else if(d.status==='running')autoProgressText.textContent='Step '+Math.min((d.cursor||0)+1,steps.length)+' of '+steps.length+' · '+(current>=0?(steps[current].label||'working…'):'waiting for the next server-safe stage…')+' · next stage paced by server load'; 302 else if(d.status==='complete')autoProgressText.textContent='Complete · all safe stages finished and verified.'; 303 else if(d.status==='rolled_back')autoProgressText.textContent=(d.rollback||{}).status==='verified'?'Rollback VERIFIED · '+String((d.rollback||{}).matched||0)+' settings match the saved snapshot.':'Rollback reported · saved settings comparison NOT VERIFIED (older report).'; 304 else if(d.status==='rollback_failed')autoProgressText.textContent='ROLLBACK NOT VERIFIED · inspect the reported mismatch before doing anything else.'; 305 else autoProgressText.textContent='Ready. Nothing changes until you press Auto Optimize.'; 306 } 307 if(autoSteps){ 308 autoSteps.innerHTML=''; 309 steps.forEach(function(st,i){ 310 var row=document.createElement('div'); row.className='itdna-v20-step '+(st.status||'pending'); 311 var icon=document.createElement('span'); icon.className='itdna-v20-step-icon'; icon.textContent=st.status==='done'?'✓':(st.status==='running'?'…':(st.status==='failed'?'!':(st.status==='skipped'?'–':'○'))); 312 var wrap=document.createElement('div'); var strong=document.createElement('strong'); strong.textContent=st.label||('Step '+(i+1)); var small=document.createElement('small'); small.textContent=st.detail||''; wrap.appendChild(strong);wrap.appendChild(small);row.appendChild(icon);row.appendChild(wrap);autoSteps.appendChild(row); 313 }); 314 } 315 if(autoResults){ 316 var html=''; 317 if((d.changes||[]).length)html+='<div><strong>'+(d.status==='rolled_back'||d.status==='rollback_failed'?'Attempted before rollback':'Applied')+'</strong><span>'+d.changes.length+' change item(s)</span></div>'; 318 if((d.skipped||[]).length)html+='<div><strong>Skipped safely</strong><span>'+d.skipped.length+' item(s)</span></div>'; 319 if((d.external||[]).length)html+='<div><strong>External integrations</strong><span>'+d.external.length+' item(s)</span></div>'; 320 if((d.verification||{}).message)html+='<div><strong>Verification</strong><span>'+String(d.verification.message).replace(/[<>&]/g,function(c){return {'<':'<','>':'>','&':'&'}[c];})+'</span></div>'; 321 if((d.rollback||{}).status)html+='<div><strong>Rollback</strong><span>'+String(d.rollback.status).toUpperCase()+' · '+String(d.rollback.reason||'').replace(/[<>&]/g,function(c){return {'<':'<','>':'>','&':'&'}[c];})+'</span></div>'; 322 autoResults.innerHTML=html; 323 } 324 if(d.status==='complete')autoSetStatus('Completed ✓'); 325 else if(d.status==='rolled_back')autoSetStatus((d.rollback||{}).status==='verified'?'Rollback verified ✓':'Rolled back · NOT VERIFIED'); 326 else if(d.status==='rollback_failed')autoSetStatus('Rollback NOT VERIFIED'); 327 else if(d.status==='running')autoSetStatus('Running…'); 328 } 329 function autoPoll(){ 330 if(!alive()||autoBusy||!autoJobId)return; 331 autoBusy=true; 332 autoPost('itdna_tc_auto_step',{job_id:autoJobId}).then(function(d){ 333 autoRender(d); 334 if(d.status==='running'){autoTimer=window.setTimeout(autoPoll,Math.max(1000,autoNextDelay));} 335 }).catch(function(e){ 336 autoSetStatus('Error'); 337 if(autoProgressText)autoProgressText.textContent=e.message||'Auto optimizer request failed.'; 338 }).finally(function(){autoBusy=false;}); 339 } 340 if(autoStart)autoStart.addEventListener('click',function(){if(autoBusy)return;openAutoChoice();}); 341 if(autoChoiceButtons&&autoChoiceButtons.length)autoChoiceButtons.forEach(function(btn){btn.addEventListener('click',function(){startAutoMode(btn.getAttribute('data-itdna-auto-mode')==='aggressive'?'aggressive':'server_aware');});}); 342 if(autoChoiceClose&&autoChoiceClose.length)autoChoiceClose.forEach(function(btn){btn.addEventListener('click',closeAutoChoice);}); 343 document.addEventListener('keydown',function(e){if(!alive())return;if(e.key==='Escape'&&autoChoice&&!autoChoice.hidden)closeAutoChoice();}); 344 if(autoRollback)autoRollback.addEventListener('click',function(){ 345 var rollbackMessage=autoJobId 346 ? 'Rollback this Intelligent Auto Optimize run? Current Turbo Cache settings from that run will be restored.' 347 : 'Rollback the last Intelligent Auto Optimize run? Current Turbo Cache settings from that run will be restored.'; 348 if(!window.confirm(rollbackMessage))return; 349 autoRollback.disabled=true;autoSetStatus('Rolling back…'); 350 autoPost('itdna_tc_auto_rollback',{}).then(function(d){autoRender(d);}).catch(function(e){autoRollback.disabled=false;autoSetStatus('Rollback error');if(autoProgressText)autoProgressText.textContent=e.message||'Rollback failed.';}); 351 }); 352 var existing=autoRoot.getAttribute('data-status'); 353 if(existing==='running'){ 354 autoJobId=autoRoot.getAttribute('data-job-id')||''; 355 var existingDelay=parseInt(autoRoot.getAttribute('data-next-delay-ms')||'0',10); 356 if(existingDelay>0)autoNextDelay=Math.max(1000,Math.min(120000,existingDelay)); 357 if(autoJobId){autoTimer=window.setTimeout(autoPoll,Math.max(1000,autoNextDelay));} 358 } 359 } 360 361 /* 362 * Performance Doctor one-click workflow. 363 * Scan and fix are separate authenticated AJAX requests with a browser-side 364 * five-second cooldown between them. PHP is never kept sleeping/blocked. 365 */ 366 var perfRoot=viewMain.querySelector('[data-itdna-performance-flow]'); 367 if(perfRoot && window.ITDNA_TC_LIVE && ITDNA_TC_LIVE.ajaxUrl && ITDNA_TC_LIVE.performanceNonce){ 368 var perfButton=perfRoot.querySelector('[data-itdna-performance-run]'); 369 var perfStatus=perfRoot.querySelector('[data-itdna-performance-status]'); 370 var perfProgress=document.querySelector('[data-itdna-performance-progress]'); 371 var perfBar=perfProgress?perfProgress.querySelector('[data-itdna-performance-bar]'):null; 372 var perfBusy=false; 373 function perfSet(text,pct){ 374 if(perfStatus)perfStatus.textContent=text; 375 if(perfProgress){perfProgress.hidden=false;} 376 if(perfBar&&typeof pct==='number')perfBar.style.width=Math.max(0,Math.min(100,pct))+'%'; 377 } 378 function perfPost(action){ 379 var body=new URLSearchParams(); 380 body.set('action',action);body.set('nonce',ITDNA_TC_LIVE.performanceNonce||''); 381 return fetch(ITDNA_TC_LIVE.ajaxUrl,{method:'POST',credentials:'same-origin',headers:{'Content-Type':'application/x-www-form-urlencoded; charset=UTF-8'},body:body.toString(),cache:'no-store'}) 382 .then(function(r){return r.json().catch(function(){throw new Error('Invalid server response.');}).then(function(j){if(!r.ok||!j||!j.success)throw new Error((j&&j.data&&j.data.message)||('HTTP '+r.status));return j.data;});}); 383 } 384 function perfCountdown(seconds,label,startPct,spanPct){ 385 return new Promise(function(resolve){ 386 var left=seconds,base=typeof startPct==='number'?startPct:35,span=typeof spanPct==='number'?spanPct:20; 387 function tick(){ 388 if(left<=0){resolve();return;} 389 perfSet((label||'Safe cooldown')+' '+left+'s…',base+Math.round(((seconds-left)/seconds)*span)); 390 left--;window.setTimeout(tick,1000); 10 391 } 11 return null; 12 } 13 14 function updateMetric(label, value, note) { 15 var card = findMetric(label); 16 if (!card) return; 17 var strong = card.querySelector('strong'); 18 var small = card.querySelector('small'); 19 if (strong && strong.textContent !== String(value)) { 20 strong.textContent = String(value); 21 strong.classList.add('itdna-live-flash'); 22 window.setTimeout(function () { strong.classList.remove('itdna-live-flash'); }, 500); 392 tick(); 393 }); 394 } 395 if(perfButton)perfButton.addEventListener('click',function(){ 396 if(perfBusy)return; 397 perfBusy=true;perfButton.disabled=true; 398 perfSet('Step 1/3 · Running full performance scan…',10); 399 perfPost('itdna_tc_performance_scan') 400 .then(function(scan){ 401 perfSet('Initial measured scan complete · preparing safe fix…',35); 402 return perfCountdown(5,'Initial scan complete · safe cooldown before frontend fix',35,20); 403 }) 404 .then(function(){ 405 perfSet('Step 2/3 · Applying bounded Frontend Safe Fix…',60); 406 return perfPost('itdna_tc_performance_fix'); 407 }) 408 .then(function(fixed){ 409 if(fixed&&Number(fixed.css_pending||0)===1){ 410 perfSet('Smart CSS repair queued safely · waiting 10s for the governed one-page build…',78); 411 return perfCountdown(10,'Smart CSS repair queued safely · waiting for the governed one-page build',78,12).then(function(){ 412 perfSet('Step 3/3 · Re-checking the homepage after Smart CSS repair…',92); 413 return perfPost('itdna_tc_performance_scan').catch(function(){return null;}); 414 }).then(function(){ 415 perfSet('Verification complete ✓ · refreshing measured results…',100); 416 window.setTimeout(function(){window.location.reload();},900); 417 }); 418 } 419 perfSet('Step 3/3 · Verification complete ✓ · refreshing measured results…',100); 420 window.setTimeout(function(){window.location.reload();},900); 421 }) 422 .catch(function(e){ 423 perfSet('Stopped safely: '+(e&&e.message?e.message:'Performance workflow failed.'),0); 424 perfBusy=false;perfButton.disabled=false; 425 }); 426 }); 427 } 428 429 /* 430 * Zero-touch Easy Auto Setup dashboard. Polling advances at most one due stage; 431 * WP-Cron is the fallback when the dashboard is closed. No page reload or repeated 432 * user clicks are required. 433 */ 434 var easyRoot=viewMain.querySelector('[data-itdna-easy-setup]'); 435 if(easyRoot && window.ITDNA_TC_LIVE && ITDNA_TC_LIVE.ajaxUrl && ITDNA_TC_LIVE.easySetupNonce){ 436 var easyTimer=null,easyBusy=false,easyState={phase:easyRoot.getAttribute('data-phase')||'',target_remaining:0,status:easyRoot.getAttribute('data-status')||''},easyPollErrors=0,easyPendingError=''; 437 var easyStart=easyRoot.querySelector('[data-itdna-easy-start]'); 438 var easyBadge=easyRoot.querySelector('[data-itdna-easy-badge]'); 439 var easyBar=easyRoot.querySelector('[data-itdna-easy-bar]'); 440 var easyPhase=easyRoot.querySelector('[data-itdna-easy-phase]'); 441 var easyPct=easyRoot.querySelector('[data-itdna-easy-progress-text]'); 442 var easyMsg=easyRoot.querySelector('[data-itdna-easy-message]'); 443 var easyVerdict=easyRoot.querySelector('[data-itdna-easy-verdict]'); 444 var easyLimit=easyRoot.querySelector('[data-itdna-easy-limitations]'); 445 var easyIssues=easyRoot.querySelector('[data-itdna-easy-issues]'); 446 function easyPost(action,extra){ 447 var b=new URLSearchParams();b.set('action',action);b.set('nonce',ITDNA_TC_LIVE.easySetupNonce||''); 448 Object.keys(extra||{}).forEach(function(k){b.set(k,String(extra[k]));}); 449 return fetch(ITDNA_TC_LIVE.ajaxUrl,{method:'POST',credentials:'same-origin',headers:{'Content-Type':'application/x-www-form-urlencoded; charset=UTF-8'},body:b.toString(),cache:'no-store'}) 450 .then(function(r){return r.json().catch(function(){throw new Error('Invalid setup response.');}).then(function(j){if(!r.ok||!j||!j.success)throw new Error((j&&j.data&&j.data.message)||('HTTP '+r.status));return j.data;});}); 451 } 452 function easyNum(v){return (v===null||typeof v==='undefined'||v==='')?'—':new Intl.NumberFormat().format(Number(v)||0);} 453 function easyMs(v){return Number(v)>0?easyNum(v)+' ms':'—';} 454 function easyBytes(v){var n=Number(v)||0;if(n<=0)return '—';var u=['B','KB','MB','GB'],i=0;while(n>=1024&&i<u.length-1){n/=1024;i++;}return (i===0?Math.round(n):n.toFixed(n>=10?0:1))+' '+u[i];} 455 function easyTextMetric(obj,key){ 456 if(!obj||!obj.ok)return '—'; 457 if(key==='response_ms')return easyMs(obj.response_ms); 458 if(key==='initial_asset_bytes')return easyBytes(obj.initial_asset_bytes); 459 if(key==='cache')return obj.cache||'NO-HEADER'; 460 if(key==='benchmark_profile_label')return obj.benchmark_profile_label||'—'; 461 if(key==='benchmark_requests')return easyNum(obj.benchmark_requests); 462 return easyNum(obj[key]); 463 } 464 function easyLabel(status){ 465 if(status==='running')return 'RUNNING AUTOMATICALLY'; 466 if(status==='complete')return 'COMPLETE'; 467 if(status==='attention')return 'NEEDS ATTENTION'; 468 if(status==='superseded')return 'STOPPED BY MANUAL ACTION'; 469 if(status==='waiting')return 'WAITING SAFELY'; 470 return 'READY'; 471 } 472 function easyRender(d){ 473 d=d||{};var st=d.status||'ready',pct=Math.max(0,Math.min(100,Number(d.progress)||0)); 474 easyState={phase:d.phase||'ready',target_remaining:Number(d.target_remaining)||0,status:st};easyPollErrors=0; 475 easyRoot.setAttribute('data-status',st); 476 if(easyBadge)easyBadge.textContent=easyLabel(st); 477 if(easyBar)easyBar.style.width=pct+'%'; 478 if(easyPct)easyPct.textContent='Workflow '+Math.round(pct)+'%'; 479 if(easyPhase)easyPhase.textContent=String(d.phase||'ready').replace(/_/g,' ').replace(/\b\w/g,function(c){return c.toUpperCase();}); 480 if(easyMsg){var msg=d.message||'';if(st==='running'&&easyState.phase==='settling'&&easyState.target_remaining>0){var sec=Math.max(0,Math.round(easyState.target_remaining)),min=Math.floor(sec/60);msg+=' Final check in '+min+'m '+(sec%60)+'s.';}easyMsg.textContent=msg;} 481 var before=d.baseline||{},current=d.current||{}; 482 easyRoot.querySelectorAll('[data-itdna-easy-before]').forEach(function(el){el.textContent=easyTextMetric(before,el.getAttribute('data-itdna-easy-before'));}); 483 easyRoot.querySelectorAll('[data-itdna-easy-current]').forEach(function(el){el.textContent=easyTextMetric(current,el.getAttribute('data-itdna-easy-current'));}); 484 var cmp=d.comparison||{},out=d.outcome||{}; 485 var outcomeMap={setup:(st==='complete'?'COMPLETE':Math.round(pct)+'%'),timing:((Number(current.response_ms)||0)>0 ? ((String(current.cache).toUpperCase()==='HIT' && Number(current.response_ms)<=100)?'EXCELLENT':(Number(current.response_ms)<=250?'FAST':(Number(current.response_ms)<=500?'OK':'NEEDS WORK'))) + ' · ' + easyNum(current.response_ms) + ' ms' : (st==='complete'?'Measurement unavailable':'Pending final measurement')),applied:easyNum(out.applied_count||0),verified:easyNum(out.verified_count||0),skipped:easyNum(out.skipped_count||0),limiting:easyNum(out.limiting_count||0)}; 486 easyRoot.querySelectorAll('[data-itdna-easy-outcome]').forEach(function(el){var k=el.getAttribute('data-itdna-easy-outcome');if(Object.prototype.hasOwnProperty.call(outcomeMap,k))el.textContent=outcomeMap[k];}); 487 var timingChange=easyRoot.querySelector('[data-itdna-easy-timing-change]'); 488 if(timingChange)timingChange.textContent=out.timing_label||(st==='complete'?'No verified speed gain':'Pending final measurement'); 489 var delivery=d.delivery||{}, deliveryEl=easyRoot.querySelector('[data-itdna-easy-delivery]'), deliveryNote=easyRoot.querySelector('[data-itdna-easy-delivery-note]'); 490 if(deliveryEl)deliveryEl.textContent=delivery.summary||'Unavailable'; 491 if(deliveryNote)deliveryNote.textContent=delivery.note||''; 492 if(easyVerdict){ 493 easyVerdict.hidden=!cmp.message;easyVerdict.textContent=cmp.message||''; 494 easyVerdict.classList.remove('ok','error','warn','info'); 495 easyVerdict.classList.add(cmp.verdict==='improved'?'ok':(cmp.verdict==='slower'?'error':(cmp.verdict==='needs_review'?'warn':'info'))); 496 } 497 var appliedRows=(Array.isArray(out.applied)?out.applied:[]).concat(Array.isArray(out.verified)?out.verified:[]).filter(function(v,i,a){return a.indexOf(v)===i;}); 498 var skippedRows=Array.isArray(out.skipped)?out.skipped:[]; 499 var resultDetails=easyRoot.querySelector('[data-itdna-easy-result-details]'), appliedList=easyRoot.querySelector('[data-itdna-easy-applied-list]'), skippedList=easyRoot.querySelector('[data-itdna-easy-skipped-list]'); 500 function easyList(el,rows){if(!el)return;el.innerHTML='';rows.slice(0,8).forEach(function(v){var r=document.createElement('div');r.textContent='• '+String(v);el.appendChild(r);});} 501 easyList(appliedList,appliedRows);easyList(skippedList,skippedRows);if(resultDetails)resultDetails.hidden=!(appliedRows.length||skippedRows.length); 502 var issues=Array.isArray(d.blockers)?d.blockers:[]; 503 if(easyLimit)easyLimit.hidden=!issues.length; 504 if(easyIssues){easyIssues.innerHTML='';issues.slice(0,8).forEach(function(it){var row=document.createElement('div');var b=document.createElement('b');b.textContent=(it.label||'Attention')+': ';row.appendChild(document.createTextNode('• '));row.appendChild(b);row.appendChild(document.createTextNode(it.detail||''));easyIssues.appendChild(row);});} 505 if(easyStart){easyStart.hidden=(st==='running');easyStart.disabled=false;easyStart.textContent=st==='complete'?'Run Easy Auto Setup Again':'Run Easy Auto Setup';} 506 if(easyTimer){window.clearTimeout(easyTimer);easyTimer=null;} 507 if(st==='running'){var wait=(easyState.phase==='settling'?30000:10000);if(easyState.phase==='settling'&&easyState.target_remaining>90)wait=60000;easyTimer=window.setTimeout(easyPoll,wait);} 508 } 509 function easyPoll(){ 510 if(!alive()||easyBusy)return;easyBusy=true; 511 var settling=easyState.phase==='settling',due=Number(easyState.target_remaining||0)<=3; 512 // While cache is merely settling, polling is read-only. WP-Cron owns the wait; 513 // the browser advances only once the real final measurement is due. This avoids 514 // hammering admin-ajax/WAF rules every 10 seconds for ~10 minutes. 515 var advance=(!settling||due)?1:0; 516 var pending=easyPendingError; 517 easyPost('itdna_tc_easy_setup_status',{advance:advance,client_error:pending}).then(function(d){if(pending&&easyPendingError===pending)easyPendingError='';easyRender(d);}).catch(function(e){ 518 easyPollErrors++; 519 easyPendingError=String((e&&e.message)||'request error').slice(0,180); 520 if(easyMsg)easyMsg.textContent='Live setup status is temporarily unavailable ('+easyPendingError+'). Setup continues safely in WP-Cron; retrying automatically.'; 521 easyTimer=window.setTimeout(easyPoll,Math.min(120000,30000+(easyPollErrors*15000))); 522 }).finally(function(){easyBusy=false;}); 523 } 524 function easyStartFallback(reason){ 525 var url=(ITDNA_TC_LIVE&&ITDNA_TC_LIVE.adminPostUrl)||''; 526 if(!url)return false; 527 if(easyMsg)easyMsg.textContent='admin-ajax was blocked ('+String(reason||'request blocked')+'). Retrying once through normal WordPress admin-post…'; 528 var f=document.createElement('form');f.method='POST';f.action=url;f.style.display='none'; 529 [['action','itdna_tc_easy_setup_start_fallback'],['nonce',ITDNA_TC_LIVE.easySetupNonce||'']].forEach(function(pair){var i=document.createElement('input');i.type='hidden';i.name=pair[0];i.value=pair[1];f.appendChild(i);}); 530 document.body.appendChild(f);f.submit();return true; 531 } 532 if(easyStart)easyStart.addEventListener('click',function(){ 533 if(easyBusy)return;easyBusy=true;easyStart.disabled=true;if(easyMsg)easyMsg.textContent='Starting real Before Auto Setup measurement…'; 534 easyPost('itdna_tc_easy_setup_start',{}).then(easyRender).catch(function(e){ 535 var msg=String((e&&e.message)||'Could not start Easy Auto Setup.'); 536 if(/403|unauthori[sz]ed|invalid setup response/i.test(msg)&&easyStartFallback(msg))return; 537 easyStart.disabled=false;if(easyMsg)easyMsg.textContent=msg; 538 }).finally(function(){easyBusy=false;}); 539 }); 540 if((easyRoot.getAttribute('data-status')||'')==='running'){easyTimer=window.setTimeout(easyPoll,1200);} 541 } 542 543 var optimizerPanel=viewMain.querySelector('[data-itdna-optimizer-live]'); 544 if(optimizerPanel && window.ITDNA_TC_LIVE && ITDNA_TC_LIVE.ajaxUrl){ 545 var optBusy=false,optTimer=null,optInterval=10000,optStopped=false,optStarted=false,optTab=optimizerPanel.getAttribute('data-itdna-optimizer-live')==='images'?'images':'optimization'; 546 function optFmt(n){try{return new Intl.NumberFormat().format(Number(n)||0);}catch(e){return String(Number(n)||0);}} 547 function optSet(k,v){document.querySelectorAll('[data-itdna-opt-value="'+k+'"]').forEach(function(el){var t=String(v);if(el.textContent!==t){el.textContent=t;el.classList.remove('itdna-live-flash');void el.offsetWidth;el.classList.add('itdna-live-flash');}var stat=el.closest('[data-itdna-zero-sensitive="1"]');if(stat){stat.classList.remove('is-pending');var n=Number(String(v).replace(/[^0-9.-]/g,''));stat.classList.toggle('is-zero',!isNaN(n)&&n===0);}if(k==='integrity_css'||k==='integrity_js'){var badge=el.closest('.itdna-integrity-badge');if(badge){var state=String(v).toUpperCase(),pass=state==='PASS',fail=state==='FAIL';badge.classList.toggle('is-pass',pass);badge.classList.toggle('is-fail',fail);badge.classList.toggle('is-pending',!pass&&!fail);}}});} 548 function optHas(o,k){return !!o&&Object.prototype.hasOwnProperty.call(o,k);} 549 function optMetric(outKey,o,srcKey){if(optHas(o,srcKey))optSet(outKey,optFmt(o[srcKey]));} 550 function optIntegrity(rp,kind){var ik='integrity_'+kind;if(optHas(rp,ik))return rp[ik]?'PASS':'FAIL';var dk='detected_'+kind,lk='local_'+kind,ek='eligible_'+kind,rk='reused_'+kind,sk='local_skipped_'+kind,xk='external_'+kind;if(!optHas(rp,dk)&&!optHas(rp,lk))return 'PENDING';var d=Number(rp[dk])||0,l=Number(rp[lk])||0,e=Number(rp[ek])||0,r=Number(rp[rk])||0,s=Number(rp[sk])||0,x=Number(rp[xk])||0;return (l===e+r+s&&d===l+x)?'PASS':'FAIL';} 551 function optPoll(){ 552 if(!alive()||optStopped)return; 553 if(document.hidden){optTimer=window.setTimeout(optPoll,Math.max(30000,optInterval*2));return;} 554 if(optBusy){optTimer=window.setTimeout(optPoll,optInterval);return;} 555 optBusy=true; 556 var b=new URLSearchParams();b.set('action','itdna_tc_optimizer_live');b.set('nonce',ITDNA_TC_LIVE.optimizerNonce||'');b.set('tab',optTab); 557 fetch(ITDNA_TC_LIVE.ajaxUrl,{method:'POST',credentials:'same-origin',headers:{'Content-Type':'application/x-www-form-urlencoded; charset=UTF-8'},body:b.toString(),cache:'no-store'}) 558 .then(function(r){if(!r.ok)throw new Error('HTTP '+r.status);return r.json();}) 559 .then(function(j){ 560 if(!j||!j.success||!j.data)throw new Error('Live optimizer unavailable'); 561 if(j.data.paused){optStopped=true;window.clearTimeout(optTimer);return;} 562 var gov=j.data.governor||{}; 563 if(gov.admin_poll_ms){optInterval=Math.max(10000,Math.min(60000,Number(gov.admin_poll_ms)||10000));} 564 if(gov.score!==undefined)optSet('governor_pressure',Math.round(Number(gov.score)||0)+'%'); 565 if(gov.level)optSet('governor_level',gov.level); 566 if(gov.capacity)optSet('governor_capacity',gov.capacity); 567 if(gov.image_batch!==undefined)optSet('governor_image_batch',gov.image_batch); 568 if(gov.preload_batch!==undefined)optSet('governor_preload_batch',gov.preload_batch); 569 if(gov.admin_poll_ms)optSet('governor_admin_poll',Math.round(Number(gov.admin_poll_ms)/1000)+'s'); 570 if(j.data.images){ 571 var d=j.data.images,s=d.stats||{},sc=d.scan||{},w=d.worker||{}; 572 optSet('webp',optFmt(s.webp));optSet('avif',optFmt(s.avif));optSet('processed',optFmt(s.processed));optSet('queue',optFmt(d.queue));optSet('scan',sc.active?'Running':'Idle');optSet('scanned',optFmt(sc.scanned)); 573 var p=document.querySelector('[data-itdna-image-worker]'); 574 if(p)p.innerHTML='<strong>Last worker:</strong> '+String(w.message||'Waiting for the next background batch.').replace(/[<>&]/g,function(c){return {'<':'<','>':'>','&':'&'}[c];}); 575 } 576 if(j.data.assets){ 577 var a=j.data.assets||{},rp=a.build_report||{}; 578 optMetric('detected_css',rp,'detected_css');optMetric('local_css',rp,'local_css');optMetric('external_css',rp,'external_css');optMetric('eligible_css',rp,'eligible_css');optMetric('built_css',rp,'optimized_css');optMetric('reused_css',rp,'reused_css');optMetric('local_skipped_css',rp,'local_skipped_css');optSet('integrity_css',optIntegrity(rp,'css'));optSet('css_assets',optFmt(a.css_assets)); 579 optMetric('detected_js',rp,'detected_js');optMetric('local_js',rp,'local_js');optMetric('external_js',rp,'external_js');optMetric('eligible_js',rp,'eligible_js');optMetric('built_js',rp,'optimized_js');optMetric('reused_js',rp,'reused_js');optMetric('local_skipped_js',rp,'local_skipped_js');optSet('integrity_js',optIntegrity(rp,'js'));optSet('js_assets',optFmt(a.js_assets));optSet('assets',optFmt(a.assets)); 580 var bytes=Number(a.asset_bytes)||0,sz=bytes<1024?bytes+' B':(bytes<1048576?(bytes/1024).toFixed(1)+' KB':(bytes/1048576).toFixed(1)+' MB');optSet('asset_size',sz); 581 var bs=document.querySelector('[data-itdna-asset-build-status]'); 582 if(bs&&rp.message){bs.textContent='Build status: '+String(rp.message);} 583 } 584 if(!gov.admin_poll_ms)optInterval=10000; 585 }) 586 .catch(function(){optInterval=Math.min(30000,Math.round(optInterval*1.6));}) 587 .finally(function(){optBusy=false;if(!optStopped)optTimer=window.setTimeout(optPoll,optInterval);}); 588 } 589 function optStart(){if(optStarted||optStopped)return;optStarted=true;optPoll();} 590 // The asset/image live report can sit far below the settings controls. Do not wake 591 // admin-ajax merely because the tab opened; start only when the report approaches 592 // the viewport. This lowers wp-admin load and avoids generic host/WAF error toasts. 593 if('IntersectionObserver' in window){ 594 var optObserver=new IntersectionObserver(function(entries){ 595 for(var oi=0;oi<entries.length;oi++){if(entries[oi].isIntersecting){optObserver.disconnect();optStart();break;}} 596 },{root:null,rootMargin:'700px 0px',threshold:0}); 597 optObserver.observe(optimizerPanel); 598 }else{ 599 window.setTimeout(optStart,2500); 600 } 601 } 602 603 var liveCards=viewMain.querySelectorAll('[data-itdna-live-metric]'); 604 var liveStatus=viewMain.querySelector('[data-itdna-live-status]'); 605 if(!liveCards.length || !window.ITDNA_TC_LIVE || !ITDNA_TC_LIVE.ajaxUrl){return;} 606 607 var liveBaseInterval=Math.max(10000,parseInt(ITDNA_TC_LIVE.interval,10)||10000); 608 // Optimization/Image screens already have their own read-only optimizer poller. Keep 609 // the general live counters live, but do not wake a second PHP AJAX loop every 2s. 610 if(optimizerPanel){liveBaseInterval=Math.max(10000,liveBaseInterval);} 611 var timer=null, busy=false, interval=liveBaseInterval; 612 var maxInterval=Math.max(interval,parseInt(ITDNA_TC_LIVE.maxInterval,10)||60000); 613 var lastServerTime=0, consecutiveLiveFailures=0; 614 615 function setStatus(mode,text){ 616 if(!liveStatus)return; 617 liveStatus.classList.remove('is-live','is-warn','is-error'); 618 if(mode==='live')liveStatus.classList.add('is-live'); 619 if(mode==='warn')liveStatus.classList.add('is-warn'); 620 if(mode==='error')liveStatus.classList.add('is-error'); 621 var small=liveStatus.querySelector('[data-itdna-live-time]'); 622 if(small)small.textContent=text||''; 623 } 624 625 function formatNumber(n){ 626 try{return new Intl.NumberFormat().format(Number(n)||0);}catch(e){return String(Number(n)||0);} 627 } 628 629 function updateCard(key,value,sub){ 630 document.querySelectorAll('[data-itdna-live-metric="'+CSS.escape(key)+'"]').forEach(function(card){ 631 var v=card.querySelector('[data-itdna-live-value]'); 632 var s=card.querySelector('[data-itdna-live-sub]'); 633 if(v && value!==undefined){ 634 var next=String(value); 635 if(v.textContent!==next){ 636 v.classList.remove('itdna-live-flash'); 637 void v.offsetWidth; 638 v.textContent=next; 639 v.classList.add('itdna-live-flash'); 23 640 } 24 if (small && note) small.textContent = note; 25 } 26 27 function setLive(state) { 28 var root = document.querySelector('[data-itdna-live-status]'); 29 if (!root) return; 30 root.classList.toggle('is-live', !!state); 31 } 32 33 function refresh() { 34 var data = new URLSearchParams(); 35 data.append('action', 'itdna_tc_lite_stats'); 36 data.append('nonce', window.itdnaTcLite.nonce); 37 fetch(window.itdnaTcLite.ajaxUrl, { 38 method: 'POST', 39 credentials: 'same-origin', 40 headers: {'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'}, 41 body: data.toString() 42 }).then(function (r) { return r.json(); }).then(function (json) { 43 if (!json || !json.success || !json.data) { setLive(false); return; } 44 updateMetric('Page Cache', json.data.enabled ? 'ON' : 'OFF', 'Working Lite feature'); 45 updateMetric('GZIP HTML', json.data.gzip ? 'ON' : 'OFF', 'Working Lite feature'); 46 updateMetric('HTML Cleanup', json.data.html_minify ? 'ON' : 'OFF', 'Safe Lite option'); 47 updateMetric('Cached Pages', String(json.data.count || 0), json.data.size || '0 B'); 48 setLive(true); 49 }).catch(function () { setLive(false); }); 50 } 51 52 refresh(); 53 window.setInterval(refresh, 5000); 641 } 642 if(s && sub!==undefined)s.textContent=sub; 643 }); 644 } 645 646 function ageText(ts){ 647 if(!ts)return 'Waiting for traffic'; 648 var sec=Math.max(0,Math.floor(Date.now()/1000)-Number(ts)); 649 if(sec<2)return 'just now'; 650 if(sec<60)return sec+'s ago'; 651 var min=Math.floor(sec/60);return min+'m ago'; 652 } 653 654 function schedule(delay){ 655 window.clearTimeout(timer); 656 if(!alive()||document.hidden)return; 657 timer=window.setTimeout(poll,delay); 658 } 659 660 function poll(){ 661 if(!alive())return; 662 if(document.hidden){schedule(5000);return;} 663 if(busy){schedule(interval);return;} 664 busy=true; 665 var body=new URLSearchParams(); 666 body.set('action','itdna_tc_live_stats'); 667 body.set('nonce',ITDNA_TC_LIVE.nonce||''); 668 fetch(ITDNA_TC_LIVE.ajaxUrl,{method:'POST',credentials:'same-origin',headers:{'Content-Type':'application/x-www-form-urlencoded; charset=UTF-8'},body:body.toString(),cache:'no-store'}) 669 .then(function(r){if(!r.ok)throw new Error('HTTP '+r.status);return r.json().catch(function(){throw new Error('Invalid server response');});}) 670 .then(function(json){ 671 if(!json || !json.success || !json.data)throw new Error((json&&json.data&&json.data.message)||'Live stats unavailable'); 672 consecutiveLiveFailures=0; 673 if(json.data.paused){window.clearTimeout(timer);timer=null;setStatus('warn','Reload page to resume live stats');return;} 674 var d=json.data; 675 updateCard('cached_pages',formatNumber(d.cached_pages),d.cached_size); 676 if(Number(d.external_page_cache)>0){ 677 var extOwner=String(d.external_page_cache_owner||'External full-page cache'); 678 updateCard('hit_rate','EXTERNAL',extOwner+' owns full-page cache; IndiaTVDNA does not invent its HIT percentage.'); 679 updateCard('early_hits','STANDBY','IndiaTVDNA early cache is intentionally inactive while '+extOwner+' owns delivery.'); 680 updateCard('stale','LOCAL N/A','External full-page stale delivery is outside IndiaTVDNA local counters.'); 681 updateCard('misses','LOCAL N/A','External-owner misses cannot be inferred from IndiaTVDNA local counters.'); 682 }else{ 683 var hitMeta=formatNumber(d.samples)+' cacheable origin samples'; 684 if(Number(d.origin_samples)>0){hitMeta+=' · '+formatNumber(d.origin_samples)+' total origin samples';} 685 updateCard('hit_rate',d.hit_rate,hitMeta); 686 updateCard('early_hits',formatNumber(d.early_hits),'Served before normal WordPress bootstrap'); 687 updateCard('stale',formatNumber(d.stale),'Fast stale-while-revalidate responses'); 688 updateCard('misses',formatNumber(d.misses),'Sampled requests that needed WordPress/rebuild'); 689 } 690 lastServerTime=Number(d.server_time)||Math.floor(Date.now()/1000); 691 setStatus('live','Live · updated just now'); 692 var cq=d.central_queue||{};var cqs=cq.status||{};updateCard('queue_pending',formatNumber(cqs.pending||0),String(cqs.status||'idle')); 693 var tele=d.hosting_telemetry||{}; 694 var speed=viewMain.querySelector('[data-itdna-speed-console]'); 695 if(speed){ 696 function put(attr,value){var el=speed.querySelector('['+attr+']');if(el)el.textContent=value;} 697 put('data-itdna-load-cpu',tele.cpu_value===null||tele.cpu_value===undefined?'Unavailable':String(tele.cpu_value)+'%'); 698 put('data-itdna-load-cpu-detail',String(tele.cpu_label||'Hosting does not expose CPU measurements')); 699 put('data-itdna-load-memory',tele.memory_value===null||tele.memory_value===undefined?'Unavailable':String(tele.memory_value)+'%'); 700 put('data-itdna-load-memory-detail',String(tele.memory_label||'Hosting does not expose memory measurements')); 701 put('data-itdna-load-average',tele.load_avg===null||tele.load_avg===undefined?'Unavailable':String(tele.load_avg)); 702 put('data-itdna-load-average-detail',String(tele.load_label||'1-minute host load (not CPU%)')); 703 var scoped=tele.scope_verified===true||tele.scope_verified===1; 704 var accountScoped=tele.account_scope_verified===true||tele.account_scope_verified===1; 705 var cpu=scoped&&tele.cpu_value!==null&&tele.cpu_value!==undefined?String(tele.cpu_value)+'%':'Unavailable'; 706 var ram=scoped&&tele.memory_value!==null&&tele.memory_value!==undefined?String(tele.memory_value)+'%':'Unavailable'; 707 speed.querySelectorAll('[data-speed-cpu-ram]').forEach(function(el){el.textContent='Scoped CPU '+cpu+' · RAM '+ram+(accountScoped?' · verified hosting account':(scoped?' · container quota; account unverified':' · account unknown; runtime guard active'));}); 708 } 709 var hg=d.hosting_guard||{}; 710 if(speed&&hg.profile){ 711 var a=speed.querySelector('[data-itdna-host-active]');if(a)a.textContent=String(hg.profile); 712 var b=speed.querySelector('[data-itdna-host-allowed]');if(b)b.textContent=String(Number(hg.allowed)||1); 713 var c=speed.querySelector('[data-itdna-host-status]'); 714 if(c)c.textContent=(!hg.enabled?'⚪ Adaptive Speed OFF · Safe · ':(hg.emergency?'🚨 Emergency Safe Mode · ':(hg.verified?'🟢 Verified account resources · ':(hg.safety_mode==='runtime-downshift'?'🟠 Runtime pressure downshift · ':'⚪ CPU/RAM unknown · Runtime guard ready · '))))+ 715 'High load: '+Math.max(Number(hg.high_cpu_for)||0,Number(hg.high_ram_for)||0)+' / 20s · '+String(hg.warning||''); 716 } 717 var g=d.governor||{}; 718 var governorPoll=g.admin_poll_ms?Math.max(10000,Math.min(60000,Number(g.admin_poll_ms)||10000)):0; 719 interval=Math.max(liveBaseInterval,governorPoll||0); 720 }) 721 .catch(function(err){ 722 consecutiveLiveFailures++; 723 var raw=String(err&&err.message||'Network failure'); 724 var reason=/HTTP 403/.test(raw)?'Access denied (403) · reload dashboard': 725 /HTTP (500|502|503|504)/.test(raw)?'Server error · check hosting PHP log': 726 /Invalid server response/.test(raw)?'Invalid AJAX response · check PHP log': 727 /Failed to fetch|NetworkError|Network failure/.test(raw)?'Network blocked · check browser/firewall': 728 raw.substring(0,90); 729 setStatus(consecutiveLiveFailures>=2?'error':'warn','LIVE unavailable · '+reason); 730 if(liveStatus)liveStatus.title='Last live polling error: '+raw.substring(0,160); 731 interval=Math.min(maxInterval,Math.round(interval*1.7)); 732 }) 733 .finally(function(){busy=false;schedule(interval);}); 734 } 735 736 document.addEventListener('visibilitychange',function(){ 737 if(!alive())return; 738 if(document.hidden){window.clearTimeout(timer);timer=null;setStatus('warn','Paused while tab is hidden');} 739 else{interval=liveBaseInterval;setStatus('warn','Reconnecting…');poll();} 740 }); 741 742 poll(); 743 744 } 745 746 function itdnaRefreshLocalizedState(doc){ 747 try{ 748 var node=doc&&doc.querySelector?doc.querySelector('#itdna-tc-admin-js-extra'):null; 749 if(!node)return; 750 var txt=node.textContent||''; 751 var m=txt.match(/var\s+ITDNA_TC_LIVE\s*=\s*(\{[\s\S]*\})\s*;?\s*$/); 752 if(m&&m[1])window.ITDNA_TC_LIVE=JSON.parse(m[1]); 753 }catch(e){} 754 } 755 756 function itdnaSetActiveNav(tab){ 757 document.querySelectorAll('.itdna-sidebar nav a[href*="page=itdna-turbo-cache"]').forEach(function(a){ 758 try{ 759 var u=new URL(a.href,location.href),t=u.searchParams.get('tab')||'dashboard'; 760 a.classList.toggle('active',t===tab); 761 if(t===tab)a.setAttribute('aria-current','page');else a.removeAttribute('aria-current'); 762 }catch(e){} 763 }); 764 } 765 766 function itdnaUnsavedMain(){ 767 var form=document.querySelector('.itdna-main .itdna-settings-form[data-itdna-dirty="1"]'); 768 return !!form; 769 } 770 771 function itdnaBindDirtyTracking(){ 772 var main=document.querySelector('.itdna-main');if(!main)return; 773 main.querySelectorAll('.itdna-settings-form').forEach(function(form){ 774 if(form.getAttribute('data-itdna-dirty-bound')==='1')return; 775 form.setAttribute('data-itdna-dirty-bound','1'); 776 form.addEventListener('change',function(){form.setAttribute('data-itdna-dirty','1');}); 777 form.addEventListener('input',function(){form.setAttribute('data-itdna-dirty','1');}); 778 form.addEventListener('submit',function(){form.removeAttribute('data-itdna-dirty');}); 779 }); 780 } 781 782 var itdnaNavSeq=0,itdnaNavController=null,itdnaNavTimeout=null; 783 var itdnaNavCache=new Map(); 784 function itdnaTabFromUrl(url){ 785 try{var u=new URL(url,location.href);return u.searchParams.get('tab')||'dashboard';}catch(e){return 'dashboard';} 786 } 787 function itdnaNavAjaxUrl(url){ 788 var tab=itdnaTabFromUrl(url); 789 var ajax=(window.ITDNA_TC_LIVE&&ITDNA_TC_LIVE.ajaxUrl)?ITDNA_TC_LIVE.ajaxUrl:(location.origin+'/wp-admin/admin-ajax.php'); 790 var u=new URL(ajax,location.href); 791 u.searchParams.set('action','itdna_tc_admin_tab'); 792 u.searchParams.set('tab',tab); 793 u.searchParams.set('nonce',(window.ITDNA_TC_LIVE&&ITDNA_TC_LIVE.navNonce)||''); 794 u.searchParams.set('_itdna_nav_ts',String(Date.now())); 795 return u.toString(); 796 } 797 function itdnaApplyMainHtml(html,url,pushState,seq){ 798 if(seq!==itdnaNavSeq)return false; 799 var doc=new DOMParser().parseFromString(html,'text/html'); 800 var next=doc.querySelector('.itdna-main'); 801 var current=document.querySelector('.itdna-main'); 802 if(!next||!current)throw new Error('Turbo Cache content area not found'); 803 var tab=next.getAttribute('data-itdna-tab')||itdnaTabFromUrl(url); 804 current.replaceWith(next); 805 itdnaSetActiveNav(tab); 806 itdnaBusyClear(120); 807 if(pushState)history.pushState({itdnaTurboTab:tab},'',url); 808 itdnaInitAdminMain(); 809 itdnaBindDirtyTracking(); 810 document.dispatchEvent(new CustomEvent('itdna:adminTabReady',{detail:{tab:tab}})); 811 requestAnimationFrame(function(){ 812 next.classList.add('itdna-nav-entered'); 813 requestAnimationFrame(function(){next.classList.remove('itdna-nav-entered');}); 814 }); 815 return true; 816 } 817 function itdnaNavigate(url,pushState){ 818 var current=document.querySelector('.itdna-main'); 819 if(!current){location.href=url;return;} 820 var tab=itdnaTabFromUrl(url); 821 var seq=++itdnaNavSeq; 822 823 // Never swallow a second click. A newer click cancels the older in-flight tab request. 824 if(itdnaNavController){try{itdnaNavController.abort();}catch(e){}} 825 if(itdnaNavTimeout){clearTimeout(itdnaNavTimeout);itdnaNavTimeout=null;} 826 itdnaNavController=(typeof AbortController!=='undefined')?new AbortController():null; 827 828 itdnaSetActiveNav(tab); // instant visual response to the click 829 var activeLink=document.querySelector('.itdna-sidebar nav a.active'); 830 var openingLabel=activeLink?String(activeLink.textContent||'').trim():'section'; 831 itdnaBusyNotice('Opening '+openingLabel+'…'); 832 current.classList.add('itdna-nav-loading'); 833 current.setAttribute('aria-busy','true'); 834 835 var cached=itdnaNavCache.get(tab); 836 if(cached && (Date.now()-cached.time)<30000){ 837 try{ 838 itdnaApplyMainHtml(cached.html,url,pushState,seq); 839 itdnaNavController=null; 840 return; 841 }catch(e){itdnaNavCache.delete(tab);} 842 } 843 844 var ajaxUrl=itdnaNavAjaxUrl(url); 845 var fetchOpts={method:'GET',credentials:'same-origin',cache:'no-store',headers:{'X-Requested-With':'XMLHttpRequest'}}; 846 if(itdnaNavController)fetchOpts.signal=itdnaNavController.signal; 847 itdnaNavTimeout=setTimeout(function(){ 848 if(seq!==itdnaNavSeq)return; 849 if(itdnaNavController){try{itdnaNavController.abort();}catch(e){}} 850 location.href=url; 851 },12000); 852 853 fetch(ajaxUrl,fetchOpts) 854 .then(function(r){if(!r.ok)throw new Error('HTTP '+r.status);return r.text();}) 855 .then(function(html){ 856 if(seq!==itdnaNavSeq)return; 857 if(itdnaNavTimeout){clearTimeout(itdnaNavTimeout);itdnaNavTimeout=null;} 858 itdnaNavCache.set(tab,{html:html,time:Date.now()}); 859 // Keep cache small and predictable. 860 if(itdnaNavCache.size>8){var first=itdnaNavCache.keys().next();if(!first.done)itdnaNavCache.delete(first.value);} 861 itdnaApplyMainHtml(html,url,pushState,seq); 862 }) 863 .catch(function(err){ 864 if(seq!==itdnaNavSeq)return; 865 if(err&&err.name==='AbortError')return; 866 location.href=url; 867 }) 868 .finally(function(){ 869 if(seq!==itdnaNavSeq)return; 870 if(itdnaNavTimeout){clearTimeout(itdnaNavTimeout);itdnaNavTimeout=null;} 871 itdnaNavController=null; 872 var m=document.querySelector('.itdna-main'); 873 if(m){m.classList.remove('itdna-nav-loading');m.removeAttribute('aria-busy');} 874 }); 875 } 876 877 function itdnaBindPartialNavigation(){ 878 if(window.__itdnaPartialNavBound)return;window.__itdnaPartialNavBound=1; 879 document.addEventListener('click',function(e){ 880 if(e.defaultPrevented||e.button!==0||e.metaKey||e.ctrlKey||e.shiftKey||e.altKey)return; 881 882 var toolbarPurge=e.target&&e.target.closest?e.target.closest('#wp-admin-bar-itdna-turbo-cache-purge > a'):null; 883 if(toolbarPurge){ 884 try{var purgeUrl=new URL(toolbarPurge.href,location.href);purgeUrl.searchParams.set('return_to',location.href);toolbarPurge.href=purgeUrl.toString();}catch(err){} 885 return; 886 } 887 888 var a=e.target&&e.target.closest?e.target.closest('.itdna-sidebar nav a'):null; 889 if(!a||a.classList.contains('itdna-buy-link')||a.target==='_blank'||a.hasAttribute('download'))return; 890 var u; 891 try{u=new URL(a.href,location.href);}catch(err){return;} 892 if(u.origin!==location.origin||u.searchParams.get('page')!=='itdna-turbo-cache')return; 893 if(itdnaUnsavedMain()&&!window.confirm('You have unsaved Turbo Cache changes. Open another section without saving?'))return; 894 e.preventDefault();itdnaNavigate(u.href,true); 895 }); 896 window.addEventListener('popstate',function(){ 897 var u=new URL(location.href); 898 if(u.searchParams.get('page')==='itdna-turbo-cache')itdnaNavigate(u.href,false); 899 }); 900 } 901 902 function itdnaBoot(){itdnaBindGlobalActionFeedback();itdnaBindPartialNavigation();itdnaInitAdminMain();itdnaBindDirtyTracking();} 903 if(document.readyState==='loading')document.addEventListener('DOMContentLoaded',itdnaBoot,{once:true});else itdnaBoot(); 54 904 })(); -
indiatvdna-turbo-cache-lite/trunk/indiatvdna-turbo-cache.php
r3744271 r3763637 1 1 <?php 2 2 /** 3 * Plugin Name: IndiaTVDNA Turbo Cache – Speed & Performance Optimization 3 4 * Plugin URI: https://indiatvdna.com/product-category/wordpress-plugins/turbo-cache-pro-wordpress-plugins/ 4 * Plugin Name: IndiaTVDNA Turbo Cache – Speed & Performance Optimization 5 * Description: Free WordPress performance plugin with page cache, GZIP HTML, HTTP 304 validation, CSS/HTML optimization, Woo safety, preload, diagnostics, safe database cleanup and clear Full-version previews. 6 * Version: 1.4.8 5 * Description: Safe-first WordPress performance suite with page cache, preload, CSS/JS/media optimization, object cache, Cloudflare/CDN, diagnostics and safe automation. 6 * Version: 1.4.9 7 7 * Author: IndiaTVDNA 8 8 * Author URI: https://indiatvdna.com/ … … 12 12 * Text Domain: indiatvdna-turbo-cache-lite 13 13 */ 14 15 14 if (!defined('ABSPATH')) { exit; } 16 15 17 define('ITDNA_TC_LITE_VERSION', '1.4.8'); 18 define('ITDNA_TC_LITE_FILE', __FILE__); 19 define('ITDNA_TC_LITE_DIR', plugin_dir_path(__FILE__)); 20 define('ITDNA_TC_LITE_URL', plugin_dir_url(__FILE__)); 21 define('ITDNA_TC_LITE_CACHE_DIR', WP_CONTENT_DIR . '/cache/indiatvdna-turbo-cache-lite/'); 22 define('ITDNA_TC_BUY_URL', 'https://indiatvdna.com/product-category/wordpress-plugins/turbo-cache-pro-wordpress-plugins/'); 23 24 require_once ITDNA_TC_LITE_DIR . 'includes/class-itdna-lite-cache.php'; 25 require_once ITDNA_TC_LITE_DIR . 'includes/class-itdna-lite-performance.php'; 26 require_once ITDNA_TC_LITE_DIR . 'includes/class-itdna-lite-admin.php'; 27 28 register_activation_hook(__FILE__, array('ITDNA_Lite_Cache', 'activate')); 29 register_deactivation_hook(__FILE__, array('ITDNA_Lite_Cache', 'deactivate')); 30 31 32 add_action('plugins_loaded', static function () { 33 ITDNA_Lite_Cache::instance(); 34 ITDNA_Lite_Performance::instance(); 35 if (is_admin()) { 36 ITDNA_Lite_Admin::instance(); 37 } 38 }, 1); 16 // The public plugin ships full Free functionality, not disabled paid algorithms. 17 // Premium implementations are distributed in the separate external Pro plugin. 18 if (!defined('ITDNA_TC_FREE_EDITION')) { define('ITDNA_TC_FREE_EDITION', true); } 19 if (!defined('ITDNA_TC_PRO_URL')) { 20 define('ITDNA_TC_PRO_URL', 'https://indiatvdna.com/product-category/wordpress-plugins/turbo-cache-pro-wordpress-plugins/'); 21 } 22 function itdna_tc_free_safe_options($value) { 23 if (!is_array($value)) { return $value; } 24 foreach (array('rum_auto_tune') as $flag) { 25 $value[$flag] = 0; 26 } 27 return $value; 28 } 29 // Legacy options from a former private Pro install cannot activate omitted code. 30 add_filter('option_itdna_tc_options', 'itdna_tc_free_safe_options', 99); 31 // On saving FREE options, keep only the separately distributed auto-tune engine disabled. 32 add_filter('pre_update_option_itdna_tc_options', 'itdna_tc_free_safe_options', 99); 33 34 // Tiny read-only origin challenge for Auto Best. The early cache must make its 35 // normal cookie decision first; this header does NOT force an early-cache bypass. 36 // Works even when the optimized frontend skips the full plugin runtime. 37 if (!empty($_SERVER['HTTP_X_ITDNA_AUTO_COOKIE_PROBE'])) { 38 require_once __DIR__ . '/includes/class-itdna-auto-cookie-probe.php'; 39 add_action('send_headers', array('ITDNA_Auto_Cookie_Probe', 'stamp_origin'), 1); 40 } 41 42 // Master Pause is checked BEFORE private-cookie and frontend hooks. When OFF, 43 // visitors, REST, cron, WP-CLI and third-party admin screens do not boot Turbo. 44 // Administrators retain a tiny independent Dashboard to turn the engine ON. 45 if ((string)get_option('itdna_tc_master_enabled', '1') === '0') { 46 if (is_admin() && !(defined('DOING_CRON') && DOING_CRON)) { 47 if (!defined('ITDNA_TC_VERSION')) { define('ITDNA_TC_VERSION', '1.4.9'); } 48 if (!defined('ITDNA_TC_FILE')) { define('ITDNA_TC_FILE', __FILE__); } 49 require_once __DIR__.'/includes/class-itdna-master-control.php'; 50 ITDNA_Master_Control::boot_paused(); 51 } 52 return; 53 } 54 if (is_admin() && !(defined('DOING_CRON') && DOING_CRON)) { 55 // Native form submission; does not depend on admin AJAX or monitor polling. 56 require_once __DIR__.'/includes/class-itdna-master-control.php'; 57 ITDNA_Master_Control::boot(); 58 } 59 60 // advanced-cache.php can classify a logged-in/private *frontend* request before 61 // WordPress loads normal plugins. Never let that sentinel short-circuit wp-admin, 62 // REST, cron or WP-CLI: those control-plane requests still need the lightweight 63 // router so the Turbo menu/actions/endpoints remain available. 64 $itdna_tc_early_uri = isset($_SERVER['REQUEST_URI']) && is_scalar($_SERVER['REQUEST_URI']) ? esc_url_raw(wp_unslash(is_scalar($_SERVER['REQUEST_URI'] ?? null) ? (string)$_SERVER['REQUEST_URI'] : '')) : ''; 65 $itdna_tc_early_control_plane = 66 (defined('WP_ADMIN') && WP_ADMIN) || 67 (defined('DOING_CRON') && DOING_CRON) || 68 (defined('WP_CLI') && WP_CLI) || 69 ($itdna_tc_early_uri !== '' && ( 70 strpos($itdna_tc_early_uri, '/wp-admin/') !== false || 71 strpos($itdna_tc_early_uri, '/wp-json/') !== false || 72 strpos($itdna_tc_early_uri, 'rest_route=') !== false || 73 strpos($itdna_tc_early_uri, '/wp-cron.php') !== false 74 )); 75 if (defined('ITDNA_TC_PRIVATE_ZERO_LOAD') && ITDNA_TC_PRIVATE_ZERO_LOAD && !$itdna_tc_early_control_plane) { 76 if (!headers_sent()) { 77 header('Cache-Control: private, no-store, no-cache, must-revalidate, max-age=0', true); 78 header('X-LiteSpeed-Cache-Control: no-cache', true); 79 header('CDN-Cache-Control: no-store, max-age=0', true); 80 header('Cloudflare-CDN-Cache-Control: no-store, max-age=0', true); 81 header('X-ITDNA-Runtime: private-cross-layer-zero-load', true); 82 } 83 // The logged-in private fast-path bypasses the normal plugin runtime. 84 // Attach ONLY the tiny per-page asset manager when user-scoped rules exist. 85 // No cache/optimizer or telemetry is enabled for private sessions. 86 if (function_exists('get_option') && get_option('itdna_tc_lab_asset_rules',array())) { 87 require_once __DIR__.'/includes/class-itdna-pro-lab.php'; 88 ITDNA_Pro_Lab::register_frontend_only(); 89 } 90 unset($itdna_tc_early_uri, $itdna_tc_early_control_plane); 91 return; 92 } 93 unset($itdna_tc_early_uri, $itdna_tc_early_control_plane); 94 95 /* 96 * v1.4.29 password-protected reader session fail-closed fallback when 97 * advanced-cache.php is absent/disabled. Never affect wp-admin or REST. 98 */ 99 if (!(defined('WP_ADMIN') && WP_ADMIN) && !(defined('DOING_CRON') && DOING_CRON) && !(defined('WP_CLI') && WP_CLI)) { 100 $itdna_pass_uri = esc_url_raw(wp_unslash(is_scalar($_SERVER['REQUEST_URI'] ?? null) ? (string)$_SERVER['REQUEST_URI'] : '')); 101 $itdna_pass_control = preg_match('~(?:/wp-admin(?:/|$)|/wp-login\.php(?:\?|$)|/wp-json(?:/|$)|/wp-cron\.php(?:\?|$)|[?&]rest_route=)~i', $itdna_pass_uri); 102 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized,WordPress.Security.ValidatedSanitizedInput.MissingUnslash -- Reviewed compatibility exception: Keep type-checked transport bytes exact for cache/private-session decisions; consumers perform protocol-specific checks. Text sanitization would alter encoded cache keys or authentication data. 103 $itdna_pass_cookie = (string)($_SERVER['HTTP_COOKIE'] ?? $_SERVER['REDIRECT_HTTP_COOKIE'] ?? ''); 104 if (!$itdna_pass_control && preg_match('/(?:^|;\s*)wp-postpass_[^=;]*\s*=/i', $itdna_pass_cookie)) { 105 if (!defined('DONOTCACHEPAGE')) { define('DONOTCACHEPAGE', true); } 106 if (!headers_sent()) { 107 header('Cache-Control: private, no-store, no-cache, must-revalidate, max-age=0', true); 108 header('X-LiteSpeed-Cache-Control: no-cache', true); 109 header('CDN-Cache-Control: no-store, max-age=0', true); 110 header('Cloudflare-CDN-Cache-Control: no-store, max-age=0', true); 111 header('Surrogate-Control: no-store', true); 112 header('Vary: Cookie', false); 113 header('X-ITDNA-Runtime: password-cookie-private-bypass', true); 114 } 115 unset($itdna_pass_uri, $itdna_pass_control, $itdna_pass_cookie); 116 return; 117 } 118 unset($itdna_pass_uri, $itdna_pass_control, $itdna_pass_cookie); 119 } 120 121 /* 122 * Private frontend absolute bypass. 123 * Detect the authenticated WordPress cookie without bootstrapping the user API. 124 * advanced-cache.php already emitted no-store headers before WordPress loaded, so 125 * the normal plugin does no hooks, no toolbar node, no option reads and no classes. 126 */ 127 if (!(defined('WP_ADMIN') && WP_ADMIN) && !(defined('DOING_CRON') && DOING_CRON) && !(defined('WP_CLI') && WP_CLI)) { 128 $itdna_tc_uri = isset($_SERVER['REQUEST_URI']) ? esc_url_raw(wp_unslash(is_scalar($_SERVER['REQUEST_URI'] ?? null) ? (string)$_SERVER['REQUEST_URI'] : '')) : ''; 129 $itdna_tc_is_rest = $itdna_tc_uri !== '' && (strpos($itdna_tc_uri, '/wp-json/') !== false || strpos($itdna_tc_uri, 'rest_route=') !== false); 130 if (!$itdna_tc_is_rest) { 131 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized,WordPress.Security.ValidatedSanitizedInput.MissingUnslash -- Reviewed compatibility exception: Keep type-checked transport bytes exact for cache/private-session decisions; consumers perform protocol-specific checks. Text sanitization would alter encoded cache keys or authentication data. 132 $itdna_tc_cookie_header = isset($_SERVER['HTTP_COOKIE']) ? (string) $_SERVER['HTTP_COOKIE'] : ''; 133 if ($itdna_tc_cookie_header !== '' && stripos($itdna_tc_cookie_header, 'wordpress_logged_in_') !== false) { 134 // Fallback headers in case WP_CACHE/advanced-cache.php is disabled. 135 if (!headers_sent()) { 136 header('Cache-Control: private, no-store, no-cache, must-revalidate, max-age=0', true); 137 header('X-LiteSpeed-Cache-Control: no-cache', true); 138 header('CDN-Cache-Control: no-store, max-age=0', true); 139 header('Cloudflare-CDN-Cache-Control: no-store, max-age=0', true); 140 header('X-ITDNA-Runtime: private-absolute-bypass', true); 141 } 142 // The logged-in private fast-path bypasses the normal plugin runtime. 143 // Attach ONLY the tiny per-page asset manager when user-scoped rules exist. 144 // No cache/optimizer or telemetry is enabled for private sessions. 145 if (function_exists('get_option') && get_option('itdna_tc_lab_asset_rules',array())) { 146 require_once __DIR__.'/includes/class-itdna-pro-lab.php'; 147 ITDNA_Pro_Lab::register_frontend_only(); 148 } 149 unset($itdna_tc_uri, $itdna_tc_is_rest, $itdna_tc_cookie_header); 150 return; 151 } 152 unset($itdna_tc_cookie_header); 153 } 154 unset($itdna_tc_uri, $itdna_tc_is_rest); 155 } 156 157 define('ITDNA_TC_VERSION','1.4.9'); 158 define('ITDNA_TC_FILE',__FILE__); 159 define('ITDNA_TC_DIR',plugin_dir_path(__FILE__)); 160 // Preserve settings when upgrading the existing WordPress.org Lite plugin. 161 require_once ITDNA_TC_DIR . 'includes/class-itdna-lite-upgrade.php'; 162 itdna_tc_migrate_lite_148_settings(); 163 // Opt-in FREE Workers Static Assets: independent secondary copy. 164 try { 165 require_once ITDNA_TC_DIR . 'includes/class-itdna-workers-assets.php'; 166 } catch (\Throwable $e) { 167 // Optional Workers error must not bring down WordPress core or Turbo's cache. 168 $GLOBALS['itdna_tc_workers_boot_failed']=true; 169 // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Reviewed compatibility exception: Production failure diagnostics are intentional and do not render to visitors. Removing this logging would remove failure visibility. 170 if (function_exists('error_log')) error_log('IndiaTVDNA Turbo Cache: Workers optional module unavailable '.get_class($e).' at '.basename($e->getFile()).':'.$e->getLine()); 171 } 172 /* 173 * Stable production boot. The early drop-ins load BEFORE ordinary plugins, so 174 * activation and upgrade must retire ONLY our old drop-ins before the next 175 * request. The standard WordPress-side engine boots normally; the independent 176 * early-cache acceleration is enabled only after explicit verified repair. 177 */ 178 function itdna_tc_recovery_disable_delivery() { 179 $dir = WP_CONTENT_DIR . '/cache/indiatvdna-turbo-cache/'; 180 if (!is_dir($dir) && function_exists('wp_mkdir_p')) { wp_mkdir_p($dir); } 181 if (is_dir($dir)) { 182 // phpcs:ignore PluginCheck.CodeAnalysis.WriteFile.PluginDirectoryWrite -- Reviewed compatibility exception: The destination is the explicit wp-content cache/drop-in path, not this plugin directory. Runtime sentinels and owned drop-in rollback must survive plugin upgrades. 183 @file_put_contents($dir . 'runtime-disabled.flag', "1\n", LOCK_EX); 184 // phpcs:ignore WordPress.WP.AlternativeFunctions.unlink_unlink -- Reviewed compatibility exception: Cache/runtime local filesystem operation: retain native atomic rename, checked deletion result, permissions or timestamps. Replacing it with remote/copy-based WP_Filesystem operations changes the cache consistency contract. 185 @unlink($dir . 'runtime-active.flag'); 186 } 187 } 188 /** 189 * Never remove or overwrite third-party drop-ins. Renaming OUR files makes 190 * WordPress's native cache implementation take over on the next request, even 191 * when the old early runtime didn't support a recovery sentinel. 192 */ 193 function itdna_tc_retire_old_owned_dropins() { 194 foreach (array( 195 'advanced-cache.php' => 'IndiaTVDNA Turbo Cache Early Drop-in', 196 'object-cache.php' => 'IndiaTVDNA Turbo Cache Object Cache Drop-in', 197 ) as $name => $marker) { 198 $path = WP_CONTENT_DIR . '/' . $name; 199 if (!is_file($path)) { continue; } 200 $head = @file_get_contents($path, false, null, 0, 1024); 201 if (!is_string($head) || strpos($head, $marker) === false) { continue; } 202 $backup = WP_CONTENT_DIR . '/' . $name . '.itdna-retired-148.php'; 203 // Never overwrite a backup; if one already contains exactly this owned 204 // drop-in, deleting the redundant active copy is safe and idempotent. 205 // phpcs:ignore PluginCheck.CodeAnalysis.WriteFile.PluginDirectoryWrite,WordPress.WP.AlternativeFunctions.rename_rename -- Reviewed compatibility exception: Cache/runtime local filesystem operation: retain native atomic rename, checked deletion result, permissions or timestamps. Replacing it with remote/copy-based WP_Filesystem operations changes the cache consistency contract. The destination is the explicit wp-content cache/drop-in path, not this plugin directory. Runtime sentinels and owned drop-in rollback must survive plugin upgrades. 206 if (!file_exists($backup)) { @rename($path, $backup); } 207 elseif (is_file($backup) && is_file($path)) { 208 $old_hash = @hash_file('sha256', $backup); 209 $live_hash = @hash_file('sha256', $path); 210 if (is_string($old_hash) && $old_hash !== '' && hash_equals($old_hash, (string)$live_hash)) { 211 // phpcs:ignore WordPress.WP.AlternativeFunctions.unlink_unlink -- Reviewed compatibility exception: Cache/runtime local filesystem operation: retain native atomic rename, checked deletion result, permissions or timestamps. Replacing it with remote/copy-based WP_Filesystem operations changes the cache consistency contract. 212 @unlink($path); 213 } 214 } 215 } 216 } 217 /** A verified working owned cache must NEVER be disabled just because its ZIP changed. */ 218 function itdna_tc_owned_delivery_operational() { 219 if (get_option('itdna_tc_recovery_mode', 0)) { return false; } 220 if (!defined('WP_CACHE') || !WP_CACHE) { return false; } 221 $dropin = WP_CONTENT_DIR . '/advanced-cache.php'; 222 $dir = WP_CONTENT_DIR . '/cache/indiatvdna-turbo-cache/'; 223 $head = is_file($dropin) ? @file_get_contents($dropin, false, null, 0, 1024) : false; 224 return is_string($head) && strpos($head, 'IndiaTVDNA Turbo Cache Early Drop-in') !== false 225 && is_file($dir.'early-config.php') && is_file($dir.'runtime-active.flag') 226 && !is_file($dir.'runtime-disabled.flag'); 227 } 228 function itdna_tc_stable_activate($network_wide = false) { 229 $was_live = itdna_tc_owned_delivery_operational(); 230 update_option('itdna_tc_recovery_mode', 0, false); 231 update_option('itdna_tc_delivery_auto_repair_disabled', 1, false); 232 update_option('itdna_tc_stable_guard_version', ITDNA_TC_VERSION, false); 233 // A brand-new install has no page-cache drop-in. A previously healthy 234 // installation keeps its working drop-in, configuration and active flag. 235 // Do not retire our object-cache.php either: it is an independent service. 236 if (!$was_live) { 237 itdna_tc_recovery_disable_delivery(); 238 update_option('itdna_tc_delivery_setup_pending', 1, false); 239 } else { 240 delete_option('itdna_tc_delivery_setup_pending'); 241 } 242 wp_clear_scheduled_hook('itdna_tc_cache_delivery_repair_event'); 243 wp_clear_scheduled_hook('itdna_tc_first_install_bootstrap_event'); 244 } 245 function itdna_tc_stable_deactivate() { 246 wp_clear_scheduled_hook('itdna_tc_host_guard_watch'); 247 itdna_tc_recovery_disable_delivery(); 248 // The removed plugin must not leave its pre-bootstrap code running. 249 itdna_tc_retire_old_owned_dropins(); 250 } 251 register_activation_hook(ITDNA_TC_FILE,'itdna_tc_stable_activate'); 252 register_deactivation_hook(ITDNA_TC_FILE,'itdna_tc_stable_deactivate'); 253 254 // ZIP updates are NOT activation events. The former upgrade hook retired a 255 // working advanced-cache.php on EVERY VERSION CHANGE, producing the recurring 256 // "cache delivery is not active" notice. Preserve healthy infrastructure. 257 if ((string)get_option('itdna_tc_stable_guard_version','') !== ITDNA_TC_VERSION) { 258 $was_live = itdna_tc_owned_delivery_operational(); 259 update_option('itdna_tc_stable_guard_version', ITDNA_TC_VERSION, false); 260 update_option('itdna_tc_delivery_auto_repair_disabled', 1, false); 261 if (!$was_live && !get_option('itdna_tc_recovery_mode', 0)) { 262 // Legacy v1.3.54 installations were left with a disabled cache on each 263 // upgrade. Allow a ONE-TIME, admin-only guarded setup below. 264 update_option('itdna_tc_delivery_setup_pending', 1, false); 265 } 266 // Never silently clear a genuine fatal-recovery state or delete third-party 267 // drop-ins. The owner can use the Recovery dashboard when necessary. 268 } 269 if (get_option('itdna_tc_recovery_mode', 0)) { 270 require_once ITDNA_TC_DIR.'includes/bootstrap-recovery.php'; 271 return; 272 } 273 274 // Show proof that the known legacy fatal was cleared. Never claim an active 275 // page-cache drop-in or suppress a new recovery state just to display success. 276 add_action('admin_notices', static function() { 277 if (!current_user_can('manage_options') || get_option('itdna_tc_recovery_mode', 0)) { return; } 278 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Reviewed compatibility exception: Read-only route/tab/notice/cache-eligibility selection; this request field is not authority to mutate settings. Action handlers retain their own authentication. 279 if (!isset($_GET['itdna_recovery_fixed']) || (string)$_GET['itdna_recovery_fixed'] !== '1') { return; } 280 $record = get_option('itdna_tc_last_fixed_legacy_error', array()); 281 if (!is_array($record) || ($record['fixed_in'] ?? '') !== ITDNA_TC_VERSION) { return; } 282 echo '<div class="notice notice-success is-dismissible"><p><strong>IndiaTVDNA Turbo Cache:</strong> The previously recorded WP_Hook scheduler fatal was verified and recovery has been cleared once. The current engine is active; please test your site and watch for new errors. Cache delivery remains subject to separate verification.</p></div>'; 283 }); 284 285 // v1.3.51: configurable advisory-lock slots (default max 1), with a 286 // configurable post-event quiet period (default 2 seconds). 287 require_once ITDNA_TC_DIR.'includes/class-itdna-strict-event-scheduler.php'; 288 require_once ITDNA_TC_DIR.'includes/class-itdna-server-telemetry.php'; 289 require_once ITDNA_TC_DIR.'includes/class-itdna-hosting-guard.php'; 290 require_once ITDNA_TC_DIR.'includes/class-itdna-real-image-pool.php'; 291 /** 292 * Complete an explicitly requested repair on the FIRST request that actually 293 * loads WP_CACHE=true. No wp-config/.htaccess edits and no automatic enabling 294 * after failed prerequisites; this is a verification-only transition. 295 */ 296 function itdna_tc_finish_verified_delivery() { 297 if (!get_option('itdna_tc_delivery_activation_pending', 0) || get_option('itdna_tc_recovery_mode', 0)) { return; } 298 if ((string)get_option('itdna_tc_master_enabled', '1') === '0' || is_file(WP_CONTENT_DIR.'/cache/indiatvdna-turbo-cache/master-paused.flag')) { return; } 299 if (!defined('WP_CACHE') || !WP_CACHE) { return; } 300 $dropin = WP_CONTENT_DIR . '/advanced-cache.php'; 301 $cfg = WP_CONTENT_DIR . '/cache/indiatvdna-turbo-cache/early-config.php'; 302 $runtime = ITDNA_TC_DIR . 'dropins/advanced-cache-runtime.php'; 303 $head = is_file($dropin) ? @file_get_contents($dropin, false, null, 0, 1024) : false; 304 if (!is_string($head) || strpos($head, 'IndiaTVDNA Turbo Cache Early Drop-in') === false || !is_file($cfg) || !is_file($runtime)) { return; } 305 foreach (array($dropin, $runtime, $cfg) as $file) { 306 $content = @file_get_contents($file); 307 if (!is_string($content) || $content === '' || strlen($content) > 1048576) { return; } 308 try { token_get_all($content, TOKEN_PARSE); } 309 catch (\ParseError $error) { return; } 310 } 311 $config = @include $cfg; 312 if (!is_array($config) || empty($config['enabled'])) { return; } 313 $cache_dir = WP_CONTENT_DIR . '/cache/indiatvdna-turbo-cache/'; 314 // phpcs:ignore PluginCheck.CodeAnalysis.WriteFile.PluginDirectoryWrite -- Reviewed compatibility exception: The destination is the explicit wp-content cache/drop-in path, not this plugin directory. Runtime sentinels and owned drop-in rollback must survive plugin upgrades. 315 if (@file_put_contents($cache_dir.'runtime-active.flag', "1\n", LOCK_EX) === false) { return; } 316 // phpcs:ignore WordPress.WP.AlternativeFunctions.unlink_unlink -- Reviewed compatibility exception: Cache/runtime local filesystem operation: retain native atomic rename, checked deletion result, permissions or timestamps. Replacing it with remote/copy-based WP_Filesystem operations changes the cache consistency contract. 317 if (is_file($cache_dir.'runtime-disabled.flag') && !@unlink($cache_dir.'runtime-disabled.flag')) { 318 // phpcs:ignore WordPress.WP.AlternativeFunctions.unlink_unlink -- Reviewed compatibility exception: Cache/runtime local filesystem operation: retain native atomic rename, checked deletion result, permissions or timestamps. Replacing it with remote/copy-based WP_Filesystem operations changes the cache consistency contract. 319 @unlink($cache_dir.'runtime-active.flag'); 320 return; 321 } 322 delete_option('itdna_tc_delivery_activation_pending'); 323 } 324 add_action('admin_init','itdna_tc_finish_verified_delivery', 3); 325 326 // Trap fatals that point into this plugin. The next WordPress request runs the 327 // minimal recovery dashboard, rather than repeatedly loading the crash path. 328 register_shutdown_function(static function() { 329 $err = error_get_last(); 330 if (!is_array($err) || !in_array((int)($err['type'] ?? 0), array(E_ERROR,E_PARSE,E_CORE_ERROR,E_COMPILE_ERROR,E_USER_ERROR,E_RECOVERABLE_ERROR), true)) { return; } 331 $path = str_replace('\\','/',(string)($err['file'] ?? '')); 332 $plugin = str_replace('\\','/',ITDNA_TC_DIR); 333 if (strpos($path, $plugin) !== 0) { return; } 334 if (!function_exists('update_option')) { return; } 335 update_option('itdna_tc_last_plugin_fatal', array( 336 'time'=>time(), 'version'=>ITDNA_TC_VERSION, 'file'=>substr($path,strlen($plugin)), 337 'line'=>(int)($err['line'] ?? 0), 338 'message'=>substr((string)($err['message'] ?? ''),0,800), 339 ), false); 340 update_option('itdna_tc_recovery_mode', 1, false); 341 itdna_tc_recovery_disable_delivery(); 342 }); 343 require_once ITDNA_TC_DIR.'includes/bootstrap-router.php'; -
indiatvdna-turbo-cache-lite/trunk/readme.txt
r3744271 r3763637 1 1 === IndiaTVDNA Turbo Cache – Speed & Performance Optimization === 2 2 Contributors: msntargetcom, indiatvdna 3 Tags: cache, performance, minify, cloudflare, cdn3 Tags: cache, performance, cloudflare, cdn, optimization 4 4 Requires at least: 6.9 5 5 Requires PHP: 7.4 6 6 Tested up to: 7.1 7 Stable tag: 1.4. 87 Stable tag: 1.4.9 8 8 License: GPLv2 or later 9 9 License URI: https://www.gnu.org/licenses/gpl-2.0.html 10 10 11 Free WordPress caching, CSS/HTML optimization, preload, Cloudflare purge, CDN delivery and diagnostics.11 Cache and optimization controls for WordPress, with performance monitoring and optional CDN integrations. 12 12 13 13 == Description == 14 IndiaTVDNA Turbo Cache provides page caching, cache preload, CSS/JS/image optimization, object caching, diagnostics, Cloudflare/CDN tools and WooCommerce safety controls. Free features are fully available without purchasing a subscription or installing a Pro package. 14 15 15 IndiaTVDNA Turbo Cache - Speed & Performance Optimization is a free WordPress performance plugin with functional caching, safe optimization and diagnostic tools. It is not a trial. The separate *Turbo Cache Pro* package offers additional performance and CDN features; those engines are not bundled in this WordPress.org download.16 Free includes local real-user performance reporting, anonymous predictive page warming, and per-page optimization profiles (all opt-in where appropriate), but not RUM Safe Auto Tune. Free additionally includes functioning Predictive Cache Engine and Per-Page Optimization Profiles. An optional independently distributed Pro edition has seven separate enhancement groups: verified fastest CDN route selection, Cloudflare R2 Smart Mirror, Real User Performance Auto Tune, advanced Unused CSS review/approval, Workers queue watchdog, responsive image delivery policy and guarded WooCommerce product warming. Their source code is not included in this WordPress.org-candidate ZIP. The preview fields shown in Free are descriptions of separately distributed optional features; there is no bundled paid unlocker. In Free, Workers post selection defaults to 100 latest plus 50 extra popular posts but both can be increased or decreased without payment. Background sync continues in safe small batches; hosting resources and Cloudflare service-side limits can affect completion time. Pro adds independent schedule recovery and monitoring, not higher numeric quotas. 16 17 17 = Included in this free plugin = 18 Third-party services are optional and require separately supplied credentials/consent. The local plugin can work without third-party service accounts. When enabling Cloudflare or other external services, review that provider's terms and data/privacy policies. Local browser measurement reporting posts sampled anonymous performance data to this site's own WordPress admin-ajax endpoint, only when learning is enabled; see Privacy & Compatibility for controls. Remote requests to a configured CDN are initiated by settings that you choose to enable. 18 19 19 * **Page caching:** Anonymous HTML page cache, session-aware bypasses, automatic invalidation and manual purge. 20 * **HTTP and browser caching:** Optional GZIP copies, ETag / Last-Modified HTTP 304 validation and cache counts / storage statistics. 21 * **Safe asset optimization:** Conservative HTML cleanup, generated CSS minification copies and local font-display: swap; original stylesheets are not edited. 22 * **Media loading:** WordPress-core image and iframe lazy-loading support. 23 * **Preload and maintenance:** Basic Auto Optimize, manual preload, bounded changed-URL warming, expired-transient cleanup and bounded recent-revision cleanup. 24 * **Cloudflare controls:** Optional credential verification, zone detection, manual purge and administrator-enabled content-change purge. 25 * **Bring-your-own CDN:** Optional URL rewriting for eligible wp-content / wp-includes assets to an administrator-provided CDN hostname. 26 * **Diagnostics:** Basic Performance Doctor, cache self-test, local theme/plugin compatibility intelligence, low-overhead cache analytics and generated-asset statistics. 27 * **WooCommerce safety:** Conservative cache exclusions for logged-in users, cart, checkout, account and session-dependent requests. 28 * **Portable settings:** JSON export/import without saved Cloudflare secrets, account email or detected zone identifiers. 20 Pro details: https://indiatvdna.com/product-category/wordpress-plugins/turbo-cache-pro-wordpress-plugins/ 29 21 30 Lite features remain usable without a purchase. Any Pro cards displayed in the free administration area are informational previews linking to a separately distributed package, not time-limited premium functionality. 31 32 = Separate Turbo Cache Pro package = 33 34 The following features describe the **separately distributed premium product**. They are **not included in the WordPress.org Lite ZIP**. 35 36 **Smart CDN and Cloudflare Workers** 37 38 * **Cloudflare Workers asset delivery:** Discover, validate, stage and synchronize eligible CSS, JavaScript and image assets through configured, administrator-owned Worker delivery routes. 39 * **Independent CDN Verification Lab:** Test hosting/origin URLs and Worker URLs independently, with resource-level HTTP responses, latency samples and available HIT / MISS / EXPIRED headers. 40 * **Origin, hosting CDN and Worker choices:** Guarded Auto-Fastest selection and safe origin fallback for supported assets when a preferred route is not verified or available. 41 * **Worker deployment controls:** Bounded background jobs, manual discovery/safe-sync action, deployment status and per-file staging diagnostics. 42 * **Hosting migration visibility:** Distinguish a pending/mismatched origin TLS certificate from an actual Worker failure, without disabling SSL verification. 43 * **Managed Cloudflare edge features:** Advanced full-page edge-cache rule controls and self-heal for previously plugin-owned rules; first-time installation requires explicit administrator action. 44 45 **Advanced cache and site optimization** 46 47 * Early `advanced-cache.php` delivery, stale-cache safeguards and stampede protection. 48 * Background AVIF/WebP image conversion with CPU-aware pacing, source fingerprints and duplicate-work prevention. 49 * Redis/Memcached discovery, object-cache diagnostics and guarded recovery following successful health checks. 50 * Adaptive preload, advanced asset exclusions, governed CSS rebuilds, cache freshness and targeted invalidation. 51 * Runtime canary/regression protections, safe rollback, deeper WooCommerce isolation checks and cache-coherence diagnostics. 52 * Bounded local real-user performance trends and font/CLS diagnostics without a second external analytics beacon. 53 * Coordinated background scheduling and safeguards to avoid stacking heavy jobs on busy or shared hosting. 54 55 **What Auto-Fastest does not promise:** A reachable or cached Worker URL alone does not establish that every visitor is using it. Route verification, configuration and real visitor delivery must be assessed separately. It is not a guarantee of per-visitor fastest routing, automatic whole-site traffic balancing or server failover. 56 57 **Performance expectations:** The benefit varies with PHP/CPU resources, cache-hit rate, workload, media, hosting/CDN provider, visitor location and network conditions. A low-cost host cannot be guaranteed to match a higher-capacity server for uncached or dynamic requests. No Lighthouse score, percentage gain or universal CDN advantage is guaranteed. 58 59 [Explore IndiaTVDNA Turbo Cache Pro features and licensing](https://indiatvdna.com/product-category/wordpress-plugins/turbo-cache-pro-wordpress-plugins/) 60 61 == External services == 62 63 IndiaTVDNA Turbo Cache – Speed & Performance Optimization does not automatically send site or visitor data to IndiaTVDNA. 22 == External Services and Privacy == 23 The core Free cache and optimization features do not require an IndiaTVDNA account. 64 24 65 25 = Cloudflare = 66 Cloudflare integration is optional and OFF by default. It is used only when an administrator explicitly configures/uses the Cloudflare controls. The plugin may send authenticated requests to Cloudflare's API to verify the configured Cloudflare credential, find the zone for the current site and purge Cloudflare cache. These requests include the credential and site/zone information needed for the requested operation. When the administrator chooses legacy Global API Key authentication, the matching Cloudflare account email is also sent because Cloudflare requires it for that legacy authentication method.26 Optional Cloudflare connection and purge tools communicate with Cloudflare APIs only after the site administrator enables/configures the integration. The request includes the configured API credentials, zone data and site details needed for the chosen operation. Legacy Global API Key authentication also sends the configured account email. See https://www.cloudflare.com/ , https://www.cloudflare.com/privacypolicy/ and https://www.cloudflare.com/terms/ . 67 27 68 Service: https://www.cloudflare.com/ 69 Privacy Policy: https://www.cloudflare.com/privacypolicy/ 70 Terms: https://www.cloudflare.com/terms/ 28 = Cloudflare Workers asset mirror = 29 Only after the administrator configures a Cloudflare account and explicitly selects the Worker setup/sync action, this plugin communicates with that account's Cloudflare Workers API. The setup may upload a static JavaScript Worker module and public CSS, JS, fonts, image files and published public-page cache assets to the account. It does not upload PHP executables, install WordPress plugins from Cloudflare, or send private/checkout/user sessions into a shared CDN cache. Cloudflare hosts the selected public static files and serves eligible requests under its own terms and resource limits. The administrator controls credentials, synchronization and optional cleanup. Free Workers upload jobs remain in small resource-protected batches even when more published posts are selected. 30 Cloudflare privacy: https://www.cloudflare.com/privacypolicy/ 31 Cloudflare terms: https://www.cloudflare.com/terms/ 71 32 72 = User-configuredCDN =73 CDN URL Delivery is optional and OFF by default. The plugin does not choose or create a CDN provider. If an administrator enters a CDN hostname and enables delivery, eligible static asset URLs are rewritten to that hostname. Visitors' browsers may then send normal web requests (such as IP address, user agent and requested asset URL) to the administrator-selected CDN provider. Review the privacy policy and terms of the CDN provider you choose.33 = Administrator-chosen CDN = 34 When CDN delivery is explicitly enabled, eligible visitors' asset requests are directed to the CDN hostname configured by the administrator. The chosen CDN receives normal HTTP request metadata, such as IP addresses, user agents and requested URLs, subject to its policies. 74 35 75 = IndiaTVDNA website links =76 The admin interface contains optional Full-version purchase links to https://indiatvdna.com/product-category/wordpress-plugins/turbo-cache-pro-wordpress-plugins/. Data is sent to that website only when an administrator chooses to follow a link, according to the website's own terms and privacy policy.36 = Local performance measurements = 37 Optional browser measurements use a sampled first-party endpoint at this site's own WordPress installation. No IndiaTVDNA-hosted analytics endpoint is required for the Free cache; site administrators should disclose locally collected data in their site's privacy notice as applicable. 77 38 78 The plugin also adds suggested text to WordPress's Privacy Policy Guide for the optional Cloudflare/CDN features. 39 = IndiaTVDNA purchase link = 40 The Pro purchase links open https://indiatvdna.com/product-category/wordpress-plugins/turbo-cache-pro-wordpress-plugins/ only when an administrator chooses to follow them. 41 42 == 1.4.9 Changes == 43 - REV5: Fixed nine output escaping findings in Pro-preview links and Workers numeric fields, and matched the readme plugin title with the main plugin header; no features or settings were changed. 44 - REV4: Removed the paid 100/50 Workers selection quotas in the Free UI, save handlers, and eligible-post discovery. Defaults remain 100 and 50, and background upload/mirror safety limits remain intact. 45 - Normal Workers static asset synchronization and manual CDN setup remain Free; advanced multi-CDN route auto-selection stays in the separately distributed Pro edition. 46 - Cloudflare credentials and remote asset transfers remain opt-in. No remotely downloaded plugin executable code or automatic private-plugin updates are installed by the Free edition. 47 - Seven Pro enhancement groups, including four new advanced workflows, remain in a separately distributed private plugin. Free CSS, Workers, image, and WooCommerce controls remain functional without any purchase. 48 - Predictive Cache Engine and Per-Page Optimization Profiles are fully functional in Free. 49 - Free Workers synchronization defaults to 100 latest plus 50 additional popular posts (with a verified numeric views key); both selection counts are adjustable without a paid limit. 50 - Extended Workers content selection is offered by the separately distributed Pro product. 79 51 80 52 == Installation == 81 82 1. Upload the plugin ZIP in Plugins > Add New > Upload Plugin. 83 2. Activate IndiaTVDNA Turbo Cache – Speed & Performance Optimization. 84 3. Open Turbo Cache in wp-admin. 85 4. Start with Auto Optimize or configure individual Free modules. 86 5. Test CSS/font optimizations on the front end after enabling them. 87 6. Configure Cloudflare/CDN only if you already use those external services. 53 1. Back up the site. Deactivate and remove the private Pro edition before installing Free. Do not run both simultaneously. 54 2. Upload the Free ZIP through Plugins > Add New > Upload Plugin. 55 3. Activate the plugin and open Turbo Cache > Dashboard. Configure only the services you want, and verify WooCommerce logged-in/cart bypass on a staging site before production deployment. 88 56 89 57 == Frequently Asked Questions == 58 = Can I run the free version without buying Pro? = 59 Yes. All functionality inside this Free package is available without payment. 90 60 91 = Is this free plugin a limited trial? =92 No. Its listed free functionality has no purchase deadline.61 = Are the seven separately offered Pro enhancements included in Free? = 62 No. They are upgrade previews for separately distributed software. Free operation does not depend on their code. 93 63 94 = Are premium engines locked inside the Lite download? = 95 No. Premium modules are distributed separately; previews in Lite are informational only. 96 97 = Does the free Smart Intelligence feature use an AI service? = 98 No. The Lite scan is deterministic and runs locally. 99 100 = Does the free plugin turn on Cloudflare by itself? = 101 No. Cloudflare features are optional and require administrator configuration or action. 102 103 = Does free CDN URL Delivery select or create a CDN provider? = 104 No. Administrators configure their own CDN hostname, provider and terms. 105 106 = Is Cloudflare Workers CDN included in the free plugin? = 107 No. Worker synchronization and independent Worker diagnostics are part of the separate Pro package. 108 109 = Does the plugin cache WooCommerce checkout or logged-in pages? = 110 The free plugin bypasses those requests to avoid caching private or session-specific content. 111 112 = Can Pro guarantee the same speed on every hosting provider? = 113 No. Cacheable delivery may reduce dependence on origin hosting, but uncached PHP, databases and server capacity still matter. 114 115 == Screenshots == 116 117 1. Dashboard Overview - Current cache status, quick actions and setup. 118 2. Page Cache Controls - HTML cache delivery, freshness and storage settings. 119 3. Performance Doctor - Available basic diagnostics and Pro feature previews. 120 4. Image Optimizer - Preview of advanced AVIF/WebP controls in the separate Pro edition. 121 5. Cloudflare Integration - Optional connection, authentication and purge controls. 122 6. Diagnostics Status - Environment checks and cache health signals. 123 7. Tools and Diagnostics - Local tests, logs and import/export tools. 124 8. Image Optimization Controls - Preview of Pro background processing options. 64 = Are remote integrations enabled without my approval? = 65 Cloudflare, Workers and other remote integrations require setup and applicable explicit settings. Review the configuration and privacy details before connecting them. 125 66 126 67 == Changelog == 68 = 1.4.9 = 69 * Update of the previously published Lite plugin, with the same directory, main plugin file, text domain, and contributors. 70 * Retains working Free cache, CDN, optimization, browser diagnostics and admin options; premium algorithms are excluded from the Free release. 71 * Shows contextual information for seven separate Pro enhancement groups, with no paid implementation or unlocker in Free. Existing Free options, including local CSS, image and WooCommerce safety controls, remain functional. 72 * Preserves existing Lite 1.4.8 settings with a non-destructive one-time option migration; an existing newer options record is never overwritten. 73 * Keeps native WordPress.org plugin updates (no private updater or Update URI) and fixes the Free drop-in folder references. 127 74 128 75 = 1.4.8 = 129 * Added a Plugin Homepage link to the main plugin header for WordPress.org. 130 76 * Added the plugin homepage link in the WordPress.org main plugin header. 131 77 = 1.4.7 = 132 * Updated the public plugin display name to IndiaTVDNA Turbo Cache - Speed & Performance Optimization. 133 * Preserved the existing plugin slug, text domain and update path. 134 135 = 1.4.6 = 136 * Strengthened private/no-store and authenticated-request page-cache bypasses. 137 * Added HTTP 304 cache validation, WooCommerce safety, analytics and bounded background maintenance. 138 * Improved cache directory safeguards, optional Cloudflare controls and free/premium separation. 139 140 For older releases (1.4.7–1.0.0), see `changelog.txt`. 78 * Updated the public display name, keeping the plugin slug and text domain. -
indiatvdna-turbo-cache-lite/trunk/uninstall.php
r3729757 r3763637 2 2 if (!defined('WP_UNINSTALL_PLUGIN')) { exit; } 3 3 4 delete_option('itdna_tc_lite_settings'); 5 delete_option('itdna_tc_lite_last_self_test'); 6 delete_option('itdna_tc_lite_last_cf_purge'); 7 delete_option('itdna_tc_lite_last_purge'); 8 delete_option('itdna_tc_lite_last_changed_warm'); 9 delete_option('itdna_tc_lite_last_preload'); 10 delete_option('itdna_tc_lite_last_db_cleanup'); 11 delete_option('itdna_tc_lite_last_revision_cleanup'); 12 wp_clear_scheduled_hook('itdna_tc_lite_warm_changed_post'); 13 14 $itdna_tc_lite_root = WP_CONTENT_DIR . '/cache/indiatvdna-turbo-cache-lite/'; 4 // Fail closed before any cleanup. If filesystem/DB cleanup later fails, the owned 5 // drop-ins still see the disabled sentinel (or missing owner plugin after deletion) 6 // and cannot keep cache/object-cache behavior active. 7 $itdna_tc_runtime_dir = WP_CONTENT_DIR . '/cache/indiatvdna-turbo-cache/'; 8 // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_mkdir -- Reviewed compatibility exception: Cache/runtime local filesystem operation: retain native atomic rename, checked deletion result, permissions or timestamps. Replacing it with remote/copy-based WP_Filesystem operations changes the cache consistency contract. 9 if (!is_dir($itdna_tc_runtime_dir)) { @mkdir($itdna_tc_runtime_dir, 0755, true); } 10 // phpcs:ignore PluginCheck.CodeAnalysis.WriteFile.PluginDirectoryWrite -- Reviewed compatibility exception: The destination is the explicit wp-content cache/drop-in path, not this plugin directory. Runtime sentinels and owned drop-in rollback must survive plugin upgrades. 11 @file_put_contents($itdna_tc_runtime_dir . 'runtime-disabled.flag', "1\n", LOCK_EX); 12 // phpcs:ignore WordPress.WP.AlternativeFunctions.unlink_unlink -- Reviewed compatibility exception: Cache/runtime local filesystem operation: retain native atomic rename, checked deletion result, permissions or timestamps. Replacing it with remote/copy-based WP_Filesystem operations changes the cache consistency contract. 13 @unlink($itdna_tc_runtime_dir . 'runtime-active.flag'); 14 15 // Uninstall cleanup must never turn the WordPress Plugins delete transaction into a 16 // critical error. Every cleanup below is best-effort and scoped to this plugin. 17 try { 18 15 19 if (!function_exists('WP_Filesystem')) { 16 20 require_once ABSPATH . 'wp-admin/includes/file.php'; 17 21 } 18 22 global $wp_filesystem; 19 if (WP_Filesystem() && $wp_filesystem && is_dir($itdna_tc_lite_root)) { 20 $wp_filesystem->rmdir($itdna_tc_lite_root, true); 21 } 23 WP_Filesystem(); 24 $itdna_tc_fs = is_object($wp_filesystem) ? $wp_filesystem : null; 25 26 // Cloudflare Workers deletion is ownership-scoped and best-effort. Plugin-owned 27 // Workers only; NEVER delete WordPress uploads, another Worker or an R2 bucket. 28 // Run BEFORE options containing encrypted tokens/ownership records are purged. 29 try { 30 require_once __DIR__ . '/includes/class-itdna-workers-assets.php'; 31 ITDNA_Workers_Assets::uninstall_cleanup(); 32 } catch (Throwable $itdna_tc_remote_uninstall_error) { 33 // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Reviewed compatibility exception: Production failure diagnostics are intentional and do not render to visitors. Removing this logging would remove failure visibility. 34 error_log('[ITDNA Turbo Cache] Remote Worker uninstall cleanup did not complete.'); 35 } 36 37 // Remove ONLY cryptographically verified derivatives recorded when this plugin 38 // actually generated them. No filename-only scans and no WordPress originals. 39 // A time-bounded uninstall cannot delete an arbitrarily large media library; 40 // any remaining or unverified files are preserved rather than risk data loss. 41 require_once __DIR__ . '/includes/class-itdna-generated-image-registry.php'; 42 $itdna_tc_media_cleanup = ITDNA_Generated_Image_Registry::cleanup(2500, 8.0); 43 44 // Remove our advanced-cache.php only if it is definitely ours. 45 $itdna_tc_dropin = WP_CONTENT_DIR . '/advanced-cache.php'; 46 if ($itdna_tc_fs && $itdna_tc_fs->is_file($itdna_tc_dropin)) { 47 $itdna_tc_head = $itdna_tc_fs->get_contents($itdna_tc_dropin); 48 if (is_string($itdna_tc_head) && false !== strpos(substr($itdna_tc_head, 0, 512), 'IndiaTVDNA Turbo Cache Early Drop-in')) { 49 $itdna_tc_fs->delete($itdna_tc_dropin, false, 'f'); 50 } 51 } 52 53 // Remove our object-cache.php only if it is definitely ours. Fail closed first: 54 // if host permissions refuse deletion, the orphaned drop-in must not keep Redis/ 55 // Memcached persistence active after the plugin itself is gone. 56 $itdna_tc_object_dropin = WP_CONTENT_DIR . '/object-cache.php'; 57 if ($itdna_tc_fs && $itdna_tc_fs->is_file($itdna_tc_object_dropin)) { 58 $itdna_tc_head = $itdna_tc_fs->get_contents($itdna_tc_object_dropin); 59 if (is_string($itdna_tc_head) && false !== strpos(substr($itdna_tc_head, 0, 768), 'IndiaTVDNA Turbo Cache Object Cache Drop-in')) { 60 $itdna_tc_cfg_dir = WP_CONTENT_DIR . '/cache/indiatvdna-turbo-cache/'; 61 if (!$itdna_tc_fs->is_dir($itdna_tc_cfg_dir)) { $itdna_tc_fs->mkdir($itdna_tc_cfg_dir, 0755, true); } 62 $itdna_tc_cfg = $itdna_tc_cfg_dir . 'object-cache-config.php'; 63 $itdna_tc_disabled = "<?php\nreturn array('disabled'=>true,'backend'=>'auto','resolved_backend'=>'','non_persistent_groups'=>array('counts','plugins','options','site-options','theme_json'));\n"; 64 if ($itdna_tc_fs->is_dir($itdna_tc_cfg_dir)) { $itdna_tc_fs->put_contents($itdna_tc_cfg, $itdna_tc_disabled, defined('FS_CHMOD_FILE') ? FS_CHMOD_FILE : 0640); } 65 $itdna_tc_fs->delete($itdna_tc_object_dropin, false, 'f'); 66 } 67 } 68 69 // Restore/remove only the WP_CACHE line that this plugin previously managed. 70 // If another active cache plugin/drop-in now needs WP_CACHE, preserve a generic true 71 // define instead of removing it and breaking the foreign cache owner. 72 $itdna_tc_config = is_file(ABSPATH . 'wp-config.php') ? ABSPATH . 'wp-config.php' : dirname(rtrim(ABSPATH, '/\\')) . '/wp-config.php'; 73 $itdna_tc_foreign_advanced = false; 74 if ($itdna_tc_fs && $itdna_tc_fs->is_file(WP_CONTENT_DIR . '/advanced-cache.php')) { 75 $itdna_tc_foreign_head = $itdna_tc_fs->get_contents(WP_CONTENT_DIR . '/advanced-cache.php'); 76 $itdna_tc_foreign_advanced = !(is_string($itdna_tc_foreign_head) && false !== strpos(substr($itdna_tc_foreign_head, 0, 512), 'IndiaTVDNA Turbo Cache Early Drop-in')); 77 } 78 $itdna_tc_active_plugins = (array) get_option('active_plugins', array()); 79 if (is_multisite()) { $itdna_tc_active_plugins = array_merge($itdna_tc_active_plugins, array_keys((array)get_site_option('active_sitewide_plugins', array()))); } 80 $itdna_tc_cache_plugins = array( 81 'litespeed-cache/litespeed-cache.php','wp-rocket/wp-rocket.php','w3-total-cache/w3-total-cache.php','wp-super-cache/wp-cache.php', 82 'sg-cachepress/sg-cachepress.php','wp-optimize/wp-optimize.php','breeze/breeze.php','hummingbird-performance/wp-hummingbird.php' 83 ); 84 $itdna_tc_foreign_cache_active = $itdna_tc_foreign_advanced || (bool)array_intersect($itdna_tc_cache_plugins, $itdna_tc_active_plugins); 85 if ($itdna_tc_fs && $itdna_tc_fs->is_file($itdna_tc_config) && $itdna_tc_fs->is_writable($itdna_tc_config)) { 86 $itdna_tc_data = $itdna_tc_fs->get_contents($itdna_tc_config); 87 if (is_string($itdna_tc_data)) { 88 $itdna_tc_before = $itdna_tc_data; 89 $itdna_tc_original = get_option('itdna_tc_wp_cache_original', ''); 90 if ($itdna_tc_original) { 91 $itdna_tc_data = preg_replace("/^define\\('WP_CACHE', true\\); \\/\\/ IndiaTVDNA Turbo Cache\\s*$/m", $itdna_tc_original, $itdna_tc_data, 1); 92 } elseif (get_option('itdna_tc_wp_cache_inserted')) { 93 if ($itdna_tc_foreign_cache_active) { 94 $itdna_tc_data = preg_replace("/^define\\('WP_CACHE', true\\); \\/\\/ IndiaTVDNA Turbo Cache\\s*$/m", "define('WP_CACHE', true); // Preserved for active cache drop-in", $itdna_tc_data, 1); 95 } else { 96 $itdna_tc_data = preg_replace("/^define\\('WP_CACHE', true\\); \\/\\/ IndiaTVDNA Turbo Cache\\s*$/m", '', $itdna_tc_data, 1); 97 } 98 } 99 if ($itdna_tc_data !== $itdna_tc_before) { 100 $itdna_tc_tmp = $itdna_tc_config . '.itdna-tmp'; 101 if ($itdna_tc_fs->put_contents($itdna_tc_tmp, $itdna_tc_data, defined('FS_CHMOD_FILE') ? FS_CHMOD_FILE : 0644)) { 102 if (!$itdna_tc_fs->move($itdna_tc_tmp, $itdna_tc_config, true)) { $itdna_tc_fs->delete($itdna_tc_tmp, false, 'f'); } 103 } 104 } 105 } 106 } 107 108 foreach (array( 109 'itdna_tc_scheduler_settings','itdna_tc_strict_event_gate_state','itdna_tc_heavy_worker_lock_1','itdna_tc_heavy_worker_lock_2','itdna_tc_heavy_worker_lock_3', 110 'itdna_tc_options','itdna_tc_options_schema_version','itdna_tc_activated_at','itdna_tc_last_purge','itdna_tc_last_preload', 111 'itdna_tc_preload_page','itdna_tc_preload_queue','itdna_tc_preload_queue_built','itdna_tc_preload_cursor','itdna_tc_preload_status','itdna_tc_last_cf_purge','itdna_tc_cf_connection_status','itdna_tc_cf_edge_status','itdna_tc_cf_edge_warm_queue','itdna_tc_cf_edge_warm_status','itdna_tc_cf_live_probe','itdna_tc_cf_smart_audit','itdna_tc_cdn_health','itdna_tc_last_db_cleanup','itdna_tc_last_db_report','itdna_tc_db_cleanup_lock','itdna_tc_early_status','itdna_tc_last_self_test','itdna_tc_self_test_v2_progress','itdna_tc_self_test_http_block_cooldown_until', 112 'itdna_tc_wp_cache_original','itdna_tc_wp_cache_inserted','itdna_tc_google_fonts_map','itdna_tc_last_cache_gc','itdna_tc_last_auto_fix','itdna_tc_last_url_inspection','itdna_tc_google_fonts_built','itdna_tc_object_cache_installed','itdna_tc_version', 113 'itdna_tc_priority_urls','itdna_tc_priority_preload_status','itdna_tc_preload_failures','itdna_tc_preload_lock','itdna_tc_preload_adaptive_state','itdna_tc_preload_queue_meta','itdna_tc_last_selective_purge','itdna_tc_compatibility_scan','itdna_tc_last_health_report','itdna_tc_auto_diagnostics_report','itdna_tc_self_heal_history','itdna_tc_self_heal_cooldowns','itdna_tc_self_heal_safe_snapshot','itdna_tc_self_heal_safe_mode','itdna_tc_last_settings_snapshot','itdna_tc_upgrade_needs_purge', 114 'itdna_tc_auto_v20_job','itdna_tc_auto_v20_snapshot','itdna_tc_last_auto_site_apply','itdna_tc_performance_scan','itdna_tc_automatic_benchmark_scan','itdna_tc_preconnect_snapshot','itdna_tc_site_profile', 115 'itdna_tc_image_queue','itdna_tc_image_stats','itdna_tc_image_scan','itdna_tc_image_status','itdna_tc_image_failures','itdna_tc_image_variant_manifest','itdna_tc_image_worker_lock','itdna_tc_real_image_pool_state','itdna_tc_real_image_pool_auto','itdna_tc_image_rebuild_after','itdna_tc_object_cache_detection','itdna_tc_gravatar_queue','itdna_tc_gravatar_manifest','itdna_tc_gravatar_status','itdna_tc_asset_warm_status','itdna_tc_v252_repair','itdna_tc_asset_dirty', 116 'itdna_tc_admin_refresh_notice','itdna_tc_asset_build_report','itdna_tc_css_delivery_map','itdna_tc_css_viewport_learning','itdna_tc_css_template_learning','itdna_tc_css_runtime_guard','itdna_tc_asset_retry_state','itdna_tc_asset_retry_after','itdna_tc_metrics_reset_at','itdna_tc_object_cache_upgrade_sync_error','itdna_tc_upgrade_sync_object_cache','itdna_tc_activation_reinstall_object_cache','itdna_tc_object_cache_activation_reinstall_error', 117 'itdna_tc_background_governor_status','itdna_tc_background_health_status','itdna_tc_heavy_worker_lock','itdna_tc_tag_index_started_at','itdna_tc_environment_maintenance_pending','itdna_tc_object_cache_deactivate_notice','itdna_tc_cf_deactivate_cleanup_notice', 118 'itdna_tc_cf_purge_queue','itdna_tc_cache_delivery_repair_status','itdna_tc_install_bootstrap_complete','itdna_tc_install_bootstrap_lock','itdna_tc_install_bootstrap_pending','itdna_tc_install_bootstrap_status','itdna_tc_green_soft_rollout','itdna_tc_adaptive_all_on_upgrade','itdna_tc_last_scheduled_purge','itdna_tc_last_regression_report','itdna_tc_db_schedule_cursor','itdna_tc_db_continue_passes' 119 ) as $itdna_tc_opt) { delete_option($itdna_tc_opt); } 120 121 // These three runtime locks/ticks are transients, not normal options. delete_option() 122 // does not remove the _transient_* rows, so clear them through the proper API. 123 delete_transient('itdna_tc_asset_spawn_lock'); 124 125 delete_option('itdna_tc_lcp_learning'); 126 delete_option('itdna_tc_lcp_template_learning'); 127 delete_transient('itdna_tc_image_spawn_lock'); 128 delete_transient('itdna_tc_image_admin_tick'); 129 delete_transient('itdna_tc_image_pressure_streak'); 130 delete_transient('itdna_tc_preload_pressure_streak'); 131 delete_transient('itdna_tc_priority_preload_pressure_streak'); 132 delete_transient('itdna_tc_db_health_snapshot'); 133 delete_transient('itdna_tc_background_governor_sample'); 134 delete_transient('itdna_tc_background_governor_db_sample'); 135 delete_transient('itdna_tc_resource_disk_benchmark'); 136 delete_transient('itdna_tc_cgroup_cpu_stat_prev'); 137 delete_transient('itdna_tc_live_cpu_sample_v151'); 138 delete_transient('itdna_tc_cache_delivery_repair_check'); 139 delete_transient('itdna_tc_cron_runtime_check'); 140 delete_transient('itdna_tc_asset_bootstrap_check'); 141 delete_transient('itdna_tc_green_rollout_cooldown'); 142 143 wp_clear_scheduled_hook('itdna_tc_preload_event'); 144 wp_clear_scheduled_hook('itdna_tc_preload_continue_event'); 145 wp_clear_scheduled_hook('itdna_tc_priority_preload_event'); 146 wp_clear_scheduled_hook('itdna_tc_cache_gc_event'); 147 wp_clear_scheduled_hook('itdna_tc_cache_gc_retry_event'); 148 wp_clear_scheduled_hook('itdna_tc_cache_index_reconcile_event'); 149 wp_clear_scheduled_hook('itdna_tc_tag_index_rebuild_event'); 150 wp_clear_scheduled_hook('itdna_tc_db_cleanup_event'); 151 wp_clear_scheduled_hook('itdna_tc_db_cleanup_retry_event'); 152 wp_clear_scheduled_hook('itdna_tc_health_event'); 153 wp_clear_scheduled_hook('itdna_tc_health_retry_event'); 154 wp_clear_scheduled_hook('itdna_tc_first_install_bootstrap_event'); 155 wp_clear_scheduled_hook('itdna_tc_easy_setup_event'); 156 wp_clear_scheduled_hook('itdna_tc_cache_delivery_repair_event'); 157 wp_clear_scheduled_hook('itdna_tc_system_maintenance_event'); 158 wp_clear_scheduled_hook('itdna_tc_ownership_refresh_event'); 159 wp_clear_scheduled_hook('itdna_tc_runtime_plan_rebuild_event'); 160 wp_clear_scheduled_hook('itdna_tc_cf_purge_event'); 161 wp_clear_scheduled_hook('itdna_tc_litespeed_purge_event'); 162 wp_clear_scheduled_hook('itdna_tc_scheduled_purge_event'); 163 wp_clear_scheduled_hook('itdna_tc_scheduled_purge_event_retry'); 164 wp_clear_scheduled_hook('itdna_tc_regression_event'); 165 wp_clear_scheduled_hook('itdna_tc_runner_watchdog'); 166 wp_clear_scheduled_hook('itdna_tc_edge_tag_purge_event'); 167 168 delete_option('itdna_tc_auto_step_lock'); 169 delete_option('itdna_tc_server_profile_snapshot'); 170 delete_option('itdna_tc_server_profile_apply'); 171 delete_option('itdna_tc_server_profile_status'); 172 delete_option('itdna_tc_server_profile_lock'); 173 174 delete_option('itdna_tc_preload_last_queue_after_purge'); 175 176 wp_clear_scheduled_hook('itdna_tc_cf_edge_warm_event'); 177 wp_clear_scheduled_hook('itdna_tc_image_event'); 178 wp_clear_scheduled_hook('itdna_tc_image_fast_event'); 179 wp_clear_scheduled_hook('itdna_tc_gravatar_event'); 180 wp_clear_scheduled_hook('itdna_tc_asset_warm_event'); 181 wp_clear_scheduled_hook('itdna_tc_asset_auto_event'); 182 wp_clear_scheduled_hook('itdna_tc_external_asset_worker'); 183 184 // Original uploads and all unverified/legacy derivatives are retained. 185 186 // Future-proof cleanup: this prefix belongs exclusively to this plugin. Remove any 187 // runtime option/transient introduced by a newer build even if an old explicit list 188 // did not know its name yet. 189 global $wpdb; 190 $itdna_tc_like_option = $wpdb->esc_like('itdna_tc_') . '%'; 191 $itdna_tc_like_transient = $wpdb->esc_like('_transient_itdna_tc_') . '%'; 192 $itdna_tc_like_timeout = $wpdb->esc_like('_transient_timeout_itdna_tc_') . '%'; 193 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- uninstall owns and removes only plugin-prefixed rows. 194 $itdna_tc_owned_names = $wpdb->get_col($wpdb->prepare("SELECT option_name FROM {$wpdb->options} WHERE option_name LIKE %s OR option_name LIKE %s OR option_name LIKE %s", $itdna_tc_like_option, $itdna_tc_like_transient, $itdna_tc_like_timeout)); 195 foreach ((array)$itdna_tc_owned_names as $itdna_tc_owned_name) { delete_option((string)$itdna_tc_owned_name); } 196 197 // v1.3.22 dedicated scale tables are plugin-owned and safe to remove on uninstall. 198 foreach (array('itdna_tc_queue','itdna_tc_metrics','itdna_tc_edge_tags','itdna_tc_r2_mirror') as $itdna_tc_table_suffix) { 199 $itdna_tc_table = $wpdb->prefix . $itdna_tc_table_suffix; 200 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.SchemaChange,WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- uninstall removes only plugin-owned tables. Reviewed compatibility exception: Plugin-owned queue/mirror/schema records or current database maintenance diagnostics have no equivalent WordPress object API. Prepared SQL/typed wpdb writes are retained; cached results could serve stale work or stale delivery evidence. 201 $wpdb->query($wpdb->prepare('DROP TABLE IF EXISTS %i', $itdna_tc_table)); 202 } 203 204 // Public REST cache fallback transients intentionally use a shorter key prefix so 205 // WordPress's 172-character transient key ceiling still leaves room for hashes. 206 $itdna_tc_rest_like = $wpdb->esc_like('_transient_itdna_r_') . '%'; 207 $itdna_tc_rest_timeout_like = $wpdb->esc_like('_transient_timeout_itdna_r_') . '%'; 208 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- uninstall cleanup is prefix-scoped to this plugin. 209 $itdna_tc_rest_names = $wpdb->get_col($wpdb->prepare("SELECT option_name FROM {$wpdb->options} WHERE option_name LIKE %s OR option_name LIKE %s", $itdna_tc_rest_like, $itdna_tc_rest_timeout_like)); 210 foreach ((array)$itdna_tc_rest_names as $itdna_tc_rest_name) { delete_option((string)$itdna_tc_rest_name); } 211 212 // Uninstall must REMOVE plugin-generated cache, not just rename it forever. 213 // Retire runtime first (already disabled above), then quarantine the owned cache 214 // directory to prevent old early-cache requests from using it during cleanup. 215 // The cleaner refuses unverified folders, uploads, images and unrecognized files. 216 // A bounded pass prevents huge caches from causing a WordPress uninstall timeout. 217 require_once __DIR__ . '/includes/class-itdna-orphan-cache-cleaner.php'; 218 $itdna_tc_dir = WP_CONTENT_DIR . '/cache/indiatvdna-turbo-cache'; 219 $itdna_tc_archive = ''; 220 if (is_dir($itdna_tc_dir) && !is_link($itdna_tc_dir)) { 221 for ($itdna_tc_idx = 0; $itdna_tc_idx < 10; ++$itdna_tc_idx) { 222 $itdna_tc_suffix = gmdate('YmdHis') . ($itdna_tc_idx ? '-' . $itdna_tc_idx : ''); 223 $itdna_tc_candidate = WP_CONTENT_DIR . '/cache/indiatvdna-turbo-cache-uninstalled-' . $itdna_tc_suffix; 224 if (file_exists($itdna_tc_candidate)) { continue; } 225 // phpcs:ignore PluginCheck.CodeAnalysis.WriteFile.PluginDirectoryWrite,WordPress.WP.AlternativeFunctions.rename_rename -- Reviewed compatibility exception: Cache/runtime local filesystem operation: retain native atomic rename, checked deletion result, permissions or timestamps. Replacing it with remote/copy-based WP_Filesystem operations changes the cache consistency contract. The destination is the explicit wp-content cache/drop-in path, not this plugin directory. Runtime sentinels and owned drop-in rollback must survive plugin upgrades. 226 if (@rename($itdna_tc_dir, $itdna_tc_candidate)) { $itdna_tc_archive = $itdna_tc_candidate; break; } 227 } 228 } 229 // Old archives are processed too, within ONE total request budget. This only 230 // cleans verified cache-format files; non-cache or recoverable media are kept. 231 try { 232 $itdna_tc_cleanup_start = microtime(true); 233 // Remove the current installation's cache FIRST, before old archived data 234 // can consume the request's time budget. 235 if ($itdna_tc_archive !== '') { 236 $itdna_tc_primary = ITDNA_Orphan_Cache_Cleaner::prune($itdna_tc_archive, 18000, 9.0); 237 } 238 $itdna_tc_cleanup = ITDNA_Orphan_Cache_Cleaner::prune_archives( 239 20000, max(0.1, 12.0 - (microtime(true) - $itdna_tc_cleanup_start)) 240 ); 241 if ($itdna_tc_archive === '' && is_dir($itdna_tc_dir)) { 242 // Rename was denied. The active path is safe to clean only when the 243 // plugin's disabled marker proves the directory is no longer active. 244 $itdna_tc_cleanup_active = ITDNA_Orphan_Cache_Cleaner::prune($itdna_tc_dir, 3000, 2.0, true); 245 } 246 if (!empty($itdna_tc_cleanup['remaining']) || !empty($itdna_tc_cleanup['protected'])) { 247 // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Reviewed compatibility exception: Production failure diagnostics are intentional and do not render to visitors. Removing this logging would remove failure visibility. 248 error_log('[IndiaTVDNA Turbo Cache] Uninstall left protected/large cache archives for manual review. Original uploads were not touched by cache cleanup.'); 249 } 250 } catch (Throwable $itdna_tc_cache_cleanup_error) { 251 // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Reviewed compatibility exception: Production failure diagnostics are intentional and do not render to visitors. Removing this logging would remove failure visibility. 252 error_log('[IndiaTVDNA Turbo Cache] Safe cache cleanup could not finish; no non-cache files were targeted.'); 253 } 254 255 256 if (!function_exists('insert_with_markers')) { 257 require_once ABSPATH . 'wp-admin/includes/misc.php'; 258 } 259 $itdna_tc_ht = ABSPATH . '.htaccess'; 260 if ($itdna_tc_fs && $itdna_tc_fs->exists($itdna_tc_ht) && $itdna_tc_fs->is_writable($itdna_tc_ht)) { 261 insert_with_markers($itdna_tc_ht, 'IndiaTVDNA Turbo Cache', array()); 262 } 263 264 delete_option('itdna_tc_master_enabled'); 265 delete_option('itdna_tc_master_runtime_snapshot'); 266 delete_option('itdna_tc_coexistence_asset_blacklist'); 267 268 // Low-load diagnostic journal (privacy-safe event ring). 269 delete_option('itdna_tc_diagnostic_journal'); 270 271 } catch (Throwable $itdna_tc_uninstall_error) { 272 // Intentionally swallow cleanup failures. WordPress must be allowed to remove the 273 // plugin directory; fail-closed sentinels/owner checks make leftover cache files inert. 274 } 275 276 delete_option('itdna_tc_benchmark_lab_report'); 277 delete_option('itdna_tc_rollback_history'); 278 delete_option('itdna_tc_last_known_good'); 279 delete_option('itdna_tc_change_impact_events'); 280 delete_option('itdna_tc_change_impact_last_probe'); 281 delete_option('itdna_tc_central_dependency_queue_history'); 282 delete_option('itdna_tc_intelligence_suite_v1318'); 283 delete_option('itdna_tc_performance_extensions_v1320'); 284 wp_clear_scheduled_hook('itdna_tc_change_impact_probe');
Note:
See TracChangeset
for help on using the changeset viewer.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)