{"id":463,"date":"2026-10-15T05:46:29","date_gmt":"2026-10-15T05:46:29","guid":{"rendered":"https:\/\/ongroundmedia.com\/?page_id=463"},"modified":"2026-10-15T06:03:58","modified_gmt":"2026-10-15T06:03:58","slug":"contrast-checker","status":"publish","type":"page","link":"https:\/\/ongroundmedia.com\/?page_id=463","title":{"rendered":"Contrast Checker"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-page\" data-elementor-id=\"463\" class=\"elementor elementor-463\">\n\t\t\t\t<div class=\"elementor-element elementor-element-6e72d4e e-con e-atomic-element e-flexbox-base e-default-div e-89fe377 \" data-id=\"6e72d4e\" data-element_type=\"e-flexbox\" data-e-type=\"e-flexbox\" data-interaction-id=\"6e72d4e\">\n    \t\t<div class=\"elementor-element elementor-element-1a279d0 elementor-widget elementor-widget-html\" data-id=\"1a279d0\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t\t<!doctype html><html><head><meta charset=utf8><meta name=viewport content=\"width=device-width,initial-scale=1,viewport-fit=cover\"><style>:root{color-scheme:light;box-sizing:border-box;padding-top:env(safe-area-inset-top,0px);padding-bottom:env(safe-area-inset-bottom,0px)}html{scroll-padding-top:env(safe-area-inset-top,0px)}body{margin:0;padding:0;font:14px -apple-system,BlinkMacSystemFont,sans-serif;background:#fff;color:#000}img{max-width:100%}[hidden]:not([hidden=until-found i]){display:none!important}<\/style><\/head><body>\r\n<title>Onground Contrast Checker<\/title>\r\n<meta name=\"claude:viewport-fit-sides\" content=\"cover\">\r\n<link rel=\"preconnect\" href=\"https:\/\/fonts.googleapis.com\">\r\n<link rel=\"preconnect\" href=\"https:\/\/fonts.gstatic.com\" crossorigin>\r\n<link rel=\"stylesheet\" href=\"https:\/\/fonts.googleapis.com\/css2?family=Bricolage+Grotesque:wght@500;700;800&family=Figtree:wght@400;500;600;700&family=IBM+Plex+Mono:wght@400;500;600&display=swap\">\r\n<style>\r\n\/* Layout concept: a two-pane instrument. Colour inputs on the left, a navy readout (log-scale meter + WCAG checklist) on the right,\r\n   then a live preview stage, one-click fixes, colour-vision simulation and an Onground palette matrix below. *\/\r\n:root{\r\n  --bg:#F8FAFC; --surface:#FFFFFF; --surface-2:#F1F5F9; --line:#E2E8F0;\r\n  --ink:#1E293B; --ink-strong:#0F172A; --muted:#5A6A80;\r\n  --indigo:#4F46E5; --indigo-ink:#4338CA; --btn-hover:#0F172A; --orange:#FF6B35; --emerald:#10B981;\r\n  --focus:#4F46E5;\r\n  --pass:#047857; --pass-bg:#D1FAE5; --warn:#B45309; --warn-bg:#FEF3C7; --fail:#B91C1C; --fail-bg:#FEE2E2;\r\n  --hero-a:#0F172A; --hero-b:#1E1B4B; --hero-ink:#F8FAFC; --hero-muted:#A8B5C8;\r\n  --code-bg:#0F172A; --code-ink:#E2E8F0;\r\n  --shadow:0 1px 2px rgba(15,23,42,.06),0 14px 32px -18px rgba(15,23,42,.28);\r\n  --font-display:'Bricolage Grotesque','Trebuchet MS',system-ui,sans-serif;\r\n  --font-body:'Figtree',system-ui,'Segoe UI',sans-serif;\r\n  --font-mono:'IBM Plex Mono',ui-monospace,Menlo,Consolas,monospace;\r\n}\r\n@media (prefers-color-scheme: dark){\r\n  :root:not([data-theme=\"light\"]){\r\n    --bg:#0B1220; --surface:#131C2F; --surface-2:#1B2740; --line:#2A3850;\r\n    --ink:#E2E8F0; --ink-strong:#F8FAFC; --muted:#9AA9BE;\r\n    --indigo-ink:#A5B4FC; --btn-hover:#3730A3; --focus:#A5B4FC;\r\n    --pass:#6EE7B7; --pass-bg:#064E3B; --warn:#FCD34D; --warn-bg:#4A2A05; --fail:#FCA5A5; --fail-bg:#4C1111;\r\n    --hero-a:#0F172A; --hero-b:#241F6B; --code-bg:#070C18;\r\n    --shadow:0 1px 2px rgba(0,0,0,.4),0 14px 32px -18px rgba(0,0,0,.7);\r\n    color-scheme:dark;\r\n  }\r\n}\r\n:root[data-theme=\"dark\"]{\r\n  --bg:#0B1220; --surface:#131C2F; --surface-2:#1B2740; --line:#2A3850;\r\n  --ink:#E2E8F0; --ink-strong:#F8FAFC; --muted:#9AA9BE;\r\n  --indigo-ink:#A5B4FC; --btn-hover:#3730A3; --focus:#A5B4FC;\r\n  --pass:#6EE7B7; --pass-bg:#064E3B; --warn:#FCD34D; --warn-bg:#4A2A05; --fail:#FCA5A5; --fail-bg:#4C1111;\r\n  --hero-a:#0F172A; --hero-b:#241F6B; --code-bg:#070C18;\r\n  --shadow:0 1px 2px rgba(0,0,0,.4),0 14px 32px -18px rgba(0,0,0,.7);\r\n  color-scheme:dark;\r\n}\r\n\r\n*{box-sizing:border-box}\r\nhtml{-webkit-text-size-adjust:100%}\r\nbody{\r\n  background:var(--bg);color:var(--ink);font-family:var(--font-body);font-size:15px;line-height:1.55;\r\n  padding-block:28px 64px;\r\n  padding-left:max(16px,env(safe-area-inset-left,0px));\r\n  padding-right:max(16px,env(safe-area-inset-right,0px));\r\n}\r\n:focus-visible{outline:3px solid var(--focus);outline-offset:2px}\r\nbutton{font-family:inherit}\r\n.wrap{max-width:1160px;margin-inline:auto;display:flex;flex-direction:column;gap:28px}\r\n.sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}\r\n.mono{font-family:var(--font-mono)}\r\n\r\n\/* header *\/\r\n.top{display:flex;align-items:center;justify-content:space-between;gap:16px}\r\n.brand{display:flex;align-items:center;gap:12px;min-width:0}\r\n.brand-name{display:block;font:700 17px\/1.1 var(--font-display);color:var(--ink-strong)}\r\n.brand-sub{display:block;font:500 11px\/1.4 var(--font-mono);letter-spacing:.1em;text-transform:uppercase;color:var(--muted)}\r\n.iconbtn{width:42px;height:42px;border-radius:50%;border:1px solid var(--line);background:var(--surface);color:var(--ink);display:grid;place-items:center;cursor:pointer;flex:none}\r\n.iconbtn:hover{border-color:var(--indigo-ink)}\r\n.intro{display:flex;flex-direction:column;gap:12px}\r\n.eyebrow{font:500 12px\/1.4 var(--font-mono);letter-spacing:.1em;text-transform:uppercase;color:var(--indigo-ink);margin:0}\r\nh1{font:800 clamp(36px,5.4vw,60px)\/1 var(--font-display);letter-spacing:-.025em;color:var(--ink-strong);margin:0;text-wrap:balance}\r\n.lede{margin:0;max-width:60ch;color:var(--muted);font-size:17px}\r\nh2{font:700 20px\/1.2 var(--font-display);letter-spacing:-.01em;color:var(--ink-strong);margin:0}\r\n\r\n\/* cards *\/\r\n.card{background:var(--surface);border:1px solid var(--line);border-radius:20px;padding:24px;box-shadow:var(--shadow);min-width:0}\r\n.cardhead{display:flex;align-items:flex-start;justify-content:space-between;gap:14px;flex-wrap:wrap;margin-bottom:18px}\r\n.cardhead p{margin:4px 0 0;color:var(--muted);font-size:14px;max-width:62ch}\r\n.workbench{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:20px;align-items:stretch}\r\n\r\n\/* colour inputs *\/\r\n.pair{display:grid;grid-template-columns:minmax(0,1fr) auto minmax(0,1fr);column-gap:10px;row-gap:8px;margin-top:18px;\r\n  grid-template-areas:\"l1 . l2\" \"i1 sw i2\" \"r1 . r2\"}\r\n.pair .l1{grid-area:l1}.pair .l2{grid-area:l2}.pair .i1{grid-area:i1}.pair .i2{grid-area:i2}\r\n.pair .r1{grid-area:r1}.pair .r2{grid-area:r2}.pair .sw{grid-area:sw}\r\n.lab{font-weight:600;font-size:13px;color:var(--ink-strong)}\r\n.inrow{display:flex;gap:10px;align-items:center;min-width:0}\r\n.swatch{position:relative;flex:none;width:52px;height:52px;border-radius:14px;background:var(--c,#fff);cursor:pointer;\r\n  box-shadow:inset 0 0 0 3px var(--surface),0 0 0 1px var(--line)}\r\n.swatch input{position:absolute;inset:0;width:100%;height:100%;opacity:0;cursor:pointer;border:0;padding:0}\r\n.swatch:focus-within{outline:3px solid var(--focus);outline-offset:2px}\r\n.hex{flex:1;min-width:0;width:100%;font:500 17px\/1 var(--font-mono);text-transform:uppercase;letter-spacing:.02em;\r\n  padding:15px 14px;border-radius:12px;border:1.5px solid var(--line);background:var(--surface-2);color:var(--ink-strong)}\r\n.hex.bad{border-color:var(--fail)}\r\n.readout{margin:0;font:400 12px\/1.6 var(--font-mono);color:var(--muted);overflow-wrap:anywhere}\r\n.swap{align-self:center;width:40px;height:40px;border-radius:50%;border:1px solid var(--line);background:var(--surface-2);color:var(--ink-strong);cursor:pointer;display:grid;place-items:center;transition:transform .25s}\r\n.swap:hover{border-color:var(--indigo-ink)}\r\n.swap:active{transform:rotate(180deg)}\r\n.err{margin:10px 0 0;color:var(--fail);font-size:13px;font-weight:600}\r\n.brandrows{display:flex;flex-direction:column;gap:14px;margin-top:22px;padding-top:20px;border-top:1px solid var(--line)}\r\n.mini{margin:0 0 8px;font:600 11px\/1.3 var(--font-mono);letter-spacing:.1em;text-transform:uppercase;color:var(--muted)}\r\n.chips{display:flex;flex-wrap:wrap;gap:9px}\r\n.chip{width:32px;height:32px;border-radius:50%;padding:0;border:1px solid var(--line);background:var(--c);cursor:pointer;\r\n  box-shadow:inset 0 0 0 2px var(--surface)}\r\n.chip[aria-pressed=\"true\"]{box-shadow:inset 0 0 0 2px var(--surface),0 0 0 2px var(--surface),0 0 0 4px var(--ink-strong)}\r\n.hint{margin:0;color:var(--muted);font-size:13px}\r\n\r\n\/* hero readout *\/\r\n.hero{position:relative;overflow:hidden;border-radius:20px;padding:24px;color:var(--hero-ink);min-width:0;\r\n  background:radial-gradient(70% 60% at 100% 0%,rgba(255,107,53,.26),transparent 70%),linear-gradient(145deg,var(--hero-a) 0%,var(--hero-b) 100%);\r\n  border:1px solid rgba(148,163,184,.22);box-shadow:var(--shadow)}\r\n.hero-top{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap}\r\n.hero h2{color:var(--hero-muted);font:600 12px\/1.3 var(--font-mono);letter-spacing:.12em;text-transform:uppercase}\r\n.verdict{display:inline-flex;align-items:center;gap:7px;font:700 13px\/1 var(--font-body);padding:8px 12px;border-radius:99px}\r\n.v-pass{background:#064E3B;color:#6EE7B7}.v-warn{background:#78350F;color:#FDE68A}.v-fail{background:#7F1D1D;color:#FECACA}\r\n.ratio{display:flex;align-items:baseline;gap:6px;margin:14px 0 6px;font-family:var(--font-display);font-weight:800;line-height:.95;letter-spacing:-.03em}\r\n.ratio #ratioNum{font-size:clamp(60px,9.5vw,104px);font-variant-numeric:tabular-nums}\r\n.ratio .colon{font-size:clamp(26px,3.6vw,38px);color:var(--hero-muted);font-weight:700}\r\n.meter{position:relative;height:50px;margin:10px 6px 6px}\r\n.track{height:10px;border-radius:99px;background:linear-gradient(90deg,#EF4444 0 36.09%,#F59E0B 36.09% 49.4%,#34D399 49.4% 63.92%,#10B981 63.92% 100%)}\r\n.thumb{position:absolute;top:-5px;left:0;width:20px;height:20px;border-radius:50%;background:#fff;border:4px solid var(--hero-a);\r\n  box-shadow:0 0 0 2px #fff;transform:translateX(-50%);transition:left .32s cubic-bezier(.2,.8,.2,1)}\r\n.tick{position:absolute;top:16px;display:flex;flex-direction:column;align-items:center;transform:translateX(-50%)}\r\n.tick i{display:block;width:1px;height:6px;background:var(--hero-muted)}\r\n.tick b{font:500 11px\/1.4 var(--font-mono);color:var(--hero-muted);margin-top:3px}\r\n.tick.end{transform:translateX(-100%);align-items:flex-end}\r\n.crit{list-style:none;margin:22px 0 0;padding:0;display:flex;flex-direction:column;gap:8px}\r\n.crow{display:flex;align-items:center;gap:12px;padding:10px 12px;border-radius:12px;background:rgba(255,255,255,.06);border:1px solid transparent}\r\n.crow.cur{border-color:rgba(255,255,255,.38);background:rgba(255,255,255,.1)}\r\n.crow .cl{flex:1;min-width:0;display:flex;flex-direction:column;line-height:1.3}\r\n.crow .cl b{font-weight:600;font-size:14px}\r\n.crow .cl small{font:400 12px\/1.4 var(--font-mono);color:var(--hero-muted)}\r\n.tag{font:600 10px\/1 var(--font-mono);letter-spacing:.08em;text-transform:uppercase;padding:5px 7px;border-radius:6px;background:#fff;color:#0F172A;flex:none}\r\n.pill{display:inline-flex;align-items:center;gap:6px;font:700 12px\/1 var(--font-body);padding:7px 10px;border-radius:99px;flex:none}\r\n.pill.p{background:#064E3B;color:#6EE7B7}.pill.f{background:#7F1D1D;color:#FECACA}\r\n.note{margin:16px 2px 0;font-size:13px;color:var(--hero-muted)}\r\n\r\n\/* segmented, tabs *\/\r\n.seg{display:inline-flex;gap:4px;padding:4px;border-radius:12px;background:var(--surface-2);max-width:100%;flex-wrap:wrap}\r\n.seg button,.seg label span{display:block;border:0;background:transparent;color:var(--ink);font:600 13px\/1 var(--font-body);padding:9px 14px;border-radius:9px;cursor:pointer;white-space:nowrap}\r\n.seg button[aria-selected=\"true\"],.seg input:checked+span{background:var(--surface);color:var(--ink-strong);box-shadow:0 1px 3px rgba(15,23,42,.18),inset 0 0 0 1px var(--line)}\r\n.seg label{position:relative}\r\n.seg input{position:absolute;opacity:0;inset:0;cursor:pointer}\r\n.seg label:focus-within span{outline:3px solid var(--focus);outline-offset:1px}\r\n\r\n\/* preview *\/\r\n.tools{display:grid;grid-template-columns:minmax(0,1.1fr) auto minmax(0,1.4fr);gap:18px 24px;align-items:end;margin-bottom:16px}\r\n.tool{display:flex;flex-direction:column;gap:8px;min-width:0}\r\n.tool>label,.tool>.lab{font-weight:600;font-size:13px;color:var(--ink-strong);display:flex;justify-content:space-between;gap:8px}\r\n.tool .val{font:500 12px var(--font-mono);color:var(--muted)}\r\ninput[type=range]{width:100%;accent-color:var(--indigo);margin:6px 0}\r\n.textin{width:100%;font:500 15px var(--font-body);padding:11px 14px;border-radius:12px;border:1.5px solid var(--line);background:var(--surface-2);color:var(--ink-strong)}\r\n.stage{--pv-fg:#FF6B35;--pv-bg:#F8FAFC;--pv-size:20px;--pv-weight:500;\r\n  background:var(--pv-bg);color:var(--pv-fg);border:1px solid var(--line);border-radius:16px;padding:clamp(20px,4vw,40px);min-height:310px;transition:background-color .25s,color .25s}\r\n.stage [hidden]{display:none!important}\r\n.pv-eyebrow{margin:0 0 10px;font:600 12px\/1.3 var(--font-mono);letter-spacing:.12em;text-transform:uppercase}\r\n.pv-h{margin:0 0 14px;font:800 calc(var(--pv-size)*1.55)\/1.08 var(--font-display);letter-spacing:-.02em;max-width:22ch;text-wrap:balance}\r\n.pv-body{margin:0 0 14px;font-size:var(--pv-size);font-weight:var(--pv-weight);line-height:1.5;max-width:58ch;overflow-wrap:anywhere}\r\n.pv-small{margin:18px 0 0;font-size:13px;line-height:1.5;max-width:64ch}\r\n.pv-link{color:inherit;text-decoration:underline;text-underline-offset:3px;text-decoration-thickness:2px;font-weight:700}\r\n.pv-row{display:flex;flex-wrap:wrap;gap:12px;align-items:center;margin-bottom:20px}\r\n.pv-btn{font:700 15px\/1 var(--font-body);padding:14px 22px;border-radius:12px;border:2px solid var(--pv-fg);cursor:pointer}\r\n.pv-btn.solid{background:var(--pv-fg);color:var(--pv-bg)}\r\n.pv-btn.outline{background:transparent;color:var(--pv-fg)}\r\n.pv-field{display:flex;flex-direction:column;gap:6px;max-width:340px;margin-bottom:20px;font-weight:600;font-size:14px}\r\n.pv-field input{font:500 15px var(--font-body);padding:13px 14px;border-radius:10px;border:2px solid var(--pv-fg);background:transparent;color:var(--pv-fg)}\r\n.pv-field input::placeholder{color:var(--pv-fg);opacity:1;font-style:italic}\r\n.pv-sw{display:inline-flex;align-items:center;width:46px;height:26px;border-radius:99px;border:2px solid var(--pv-fg);padding:2px;justify-content:flex-end}\r\n.pv-sw i{display:block;width:18px;height:18px;border-radius:50%;background:var(--pv-fg)}\r\n.pv-badge{font:700 12px\/1 var(--font-body);padding:7px 11px;border-radius:99px;background:var(--pv-fg);color:var(--pv-bg);border:2px solid var(--pv-fg)}\r\n.pv-badge.ol{background:transparent;color:var(--pv-fg)}\r\n.pv-banner{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;gap:22px;border:2px solid var(--pv-fg);border-radius:16px;padding:clamp(18px,3vw,30px)}\r\n.pv-banner>div{min-width:0}\r\n\r\n\/* fixes *\/\r\n.fixgrid{display:grid;grid-template-columns:repeat(auto-fit,minmax(230px,1fr));gap:14px;outline:none}\r\n.fix{background:var(--surface-2);border-radius:16px;padding:16px;display:flex;flex-direction:column;gap:12px;min-width:0}\r\n.fix h3{margin:0;font:700 15px\/1.3 var(--font-body);color:var(--ink-strong)}\r\n.fix .sub{margin:2px 0 0;font:400 12px\/1.4 var(--font-mono);color:var(--muted)}\r\n.mini-s{display:grid;place-items:center;height:58px;border-radius:12px;font:800 26px\/1 var(--font-display);box-shadow:inset 0 0 0 1px rgba(100,116,139,.35)}\r\n.fix .res{font:500 13px\/1.5 var(--font-mono);color:var(--ink);overflow-wrap:anywhere}\r\n.fix .ok{display:inline-flex;align-items:center;gap:6px;font-weight:700;color:var(--pass);font-family:var(--font-body);font-size:13px}\r\n.fix .no{color:var(--muted);font-size:13px;font-family:var(--font-body)}\r\n.btn{font:600 14px\/1 var(--font-body);padding:11px 16px;border-radius:11px;border:1.5px solid transparent;cursor:pointer}\r\n.btn.primary{background:var(--indigo);color:#fff}\r\n.btn.primary:hover{background:var(--btn-hover)}\r\n.btn.ghost{background:transparent;border-color:var(--line);color:var(--ink-strong)}\r\n.btn.ghost:hover{border-color:var(--indigo-ink)}\r\n\r\n\/* vision *\/\r\n.vgrid{display:grid;grid-template-columns:repeat(auto-fit,minmax(168px,1fr));gap:14px}\r\n.vtile{border-radius:16px;overflow:hidden;border:1px solid var(--line);display:flex;flex-direction:column;background:var(--surface-2);min-width:0}\r\n.vs{height:92px;display:grid;place-items:center;font:800 30px\/1 var(--font-display)}\r\n.vf{padding:12px 14px;display:flex;flex-direction:column;gap:6px}\r\n.vf b{font-size:14px;color:var(--ink-strong)}\r\n.vf .vr{display:flex;align-items:center;justify-content:space-between;gap:8px;font:500 13px var(--font-mono);color:var(--ink)}\r\n.badge{display:inline-flex;align-items:center;gap:5px;font:700 11px\/1 var(--font-body);padding:5px 8px;border-radius:99px}\r\n.badge.p{background:var(--pass-bg);color:var(--pass)}.badge.f{background:var(--fail-bg);color:var(--fail)}.badge.w{background:var(--warn-bg);color:var(--warn)}\r\n\r\n\/* matrix *\/\r\n.mxtools{display:flex;align-items:center;justify-content:space-between;gap:14px;flex-wrap:wrap;margin-bottom:14px}\r\n.check{display:inline-flex;align-items:center;gap:10px;font-weight:600;font-size:14px;cursor:pointer;color:var(--ink-strong)}\r\n.check input{width:18px;height:18px;accent-color:var(--indigo)}\r\n.mxscroll{overflow-x:auto;border:1px solid var(--line);border-radius:14px}\r\n.matrix{border-collapse:separate;border-spacing:0;min-width:100%}\r\n.matrix th,.matrix td{padding:8px;text-align:center;vertical-align:middle}\r\n.matrix thead th{font-weight:600;font-size:12px;color:var(--ink);background:var(--surface-2);min-width:84px}\r\n.matrix thead th .dot{display:block;width:22px;height:22px;border-radius:50%;margin:0 auto 6px;box-shadow:inset 0 0 0 1px rgba(100,116,139,.45)}\r\n.matrix .nm{display:block;line-height:1.25}\r\n.matrix .hx{display:block;font:400 10.5px var(--font-mono);color:var(--muted)}\r\n.matrix th.corner{text-align:left;min-width:140px;font:600 11px var(--font-mono);color:var(--muted);letter-spacing:.06em;text-transform:uppercase}\r\n.matrix th.corner span{display:block}\r\n.matrix tbody th{text-align:left;position:sticky;left:0;background:var(--surface);z-index:1;font-size:13px;font-weight:600;color:var(--ink-strong);border-right:1px solid var(--line)}\r\n.matrix tbody th .dot{display:inline-block;width:14px;height:14px;border-radius:50%;margin-right:8px;vertical-align:-2px;box-shadow:inset 0 0 0 1px rgba(100,116,139,.45)}\r\n.cell{width:78px;border:1.5px solid transparent;background:transparent;border-radius:12px;padding:5px;cursor:pointer;display:flex;flex-direction:column;gap:4px;align-items:stretch;color:var(--ink)}\r\n.cell:hover{border-color:var(--line)}\r\n.cell.sel{border-color:var(--ink-strong);background:var(--surface-2)}\r\n.cs{display:grid;place-items:center;height:34px;border-radius:8px;font:800 16px var(--font-display);box-shadow:inset 0 0 0 1px rgba(100,116,139,.4)}\r\n.cr{font:500 12px var(--font-mono);color:var(--ink)}\r\n.cg{font:700 10.5px\/1 var(--font-body);padding:4px 0;border-radius:6px}\r\n.g-aaa .cg,.g-aa .cg{background:var(--pass-bg);color:var(--pass)}\r\n.g-large .cg{background:var(--warn-bg);color:var(--warn)}\r\n.g-fail .cg{background:var(--fail-bg);color:var(--fail)}\r\n.same{color:var(--muted)}\r\n.onlypass .cell.g-large,.onlypass .cell.g-fail{opacity:.28}\r\n.legend{margin:14px 0 0;color:var(--muted);font-size:13px}\r\n\r\n\/* export *\/\r\n.exgrid{display:grid;grid-template-columns:minmax(0,1.2fr) minmax(0,1fr);gap:24px;align-items:start}\r\npre{margin:0;padding:18px;border-radius:14px;background:var(--code-bg);color:var(--code-ink);font:400 13px\/1.7 var(--font-mono);overflow-x:auto;white-space:pre}\r\n.btnrow{display:flex;gap:10px;flex-wrap:wrap;margin-top:14px}\r\n.saved{display:flex;flex-direction:column;gap:10px;outline:none}\r\n.sitem{display:flex;align-items:center;gap:6px;border:1px solid var(--line);border-radius:14px;padding:6px;background:var(--surface-2)}\r\n.sload{flex:1;min-width:0;display:flex;align-items:center;gap:12px;background:transparent;border:0;color:var(--ink);text-align:left;cursor:pointer;padding:2px;border-radius:10px}\r\n.sload .mini-s{width:48px;height:40px;font-size:18px;flex:none}\r\n.sload span.t{display:flex;flex-direction:column;min-width:0;font:500 12px\/1.5 var(--font-mono)}\r\n.sload span.t b{font-weight:600;color:var(--ink-strong);overflow-wrap:anywhere}\r\n.sdel{flex:none;width:34px;height:34px;border-radius:10px;border:0;background:transparent;color:var(--muted);cursor:pointer;display:grid;place-items:center}\r\n.sdel:hover{background:var(--fail-bg);color:var(--fail)}\r\n.empty{margin:0;padding:18px;border:1.5px dashed var(--line);border-radius:14px;color:var(--muted);font-size:14px}\r\n.foot{color:var(--muted);font-size:13px;max-width:78ch;margin:0}\r\n\r\n\/* toast *\/\r\n.toast{position:fixed;left:50%;bottom:calc(20px + env(safe-area-inset-bottom,0px));transform:translate(-50%,16px);opacity:0;pointer-events:none;\r\n  background:var(--ink-strong);color:var(--bg);font-weight:600;font-size:14px;padding:12px 18px;border-radius:12px;transition:opacity .2s,transform .2s;max-width:calc(100vw - 32px);z-index:5}\r\n.toast.show{opacity:1;transform:translate(-50%,0)}\r\n\r\n@media (max-width:900px){\r\n  .workbench,.exgrid{grid-template-columns:minmax(0,1fr)}\r\n  .tools{grid-template-columns:minmax(0,1fr)}\r\n}\r\n@media (max-width:560px){\r\n  .card,.hero{padding:18px;border-radius:18px}\r\n  .pair{grid-template-columns:minmax(0,1fr);grid-template-areas:\"l1\" \"i1\" \"r1\" \"sw\" \"l2\" \"i2\" \"r2\"}\r\n  .pair .sw{justify-self:start}\r\n  .pair .sw svg{transform:rotate(90deg)}\r\n  .crow{flex-wrap:wrap}\r\n}\r\n@media (prefers-reduced-motion: reduce){\r\n  *,*::before,*::after{transition:none!important;animation:none!important}\r\n}\r\n<\/style>\r\n\r\n<div class=\"wrap\">\r\n  <header class=\"top\">\r\n    <div class=\"brand\">\r\n      <svg width=\"38\" height=\"38\" viewBox=\"0 0 38 38\" aria-hidden=\"true\">\r\n        <rect x=\".5\" y=\".5\" width=\"37\" height=\"37\" rx=\"11\" fill=\"#0F172A\" stroke=\"#334155\"\/>\r\n        <rect x=\"8\" y=\"21\" width=\"5.5\" height=\"9\" rx=\"1.6\" fill=\"#818CF8\"\/>\r\n        <rect x=\"16.2\" y=\"16\" width=\"5.5\" height=\"14\" rx=\"1.6\" fill=\"#818CF8\"\/>\r\n        <rect x=\"24.5\" y=\"11\" width=\"5.5\" height=\"19\" rx=\"1.6\" fill=\"#FF6B35\"\/>\r\n        <path d=\"M8 14.5 15 9l4 3 8-6.5\" fill=\"none\" stroke=\"#F8FAFC\" stroke-width=\"1.8\" stroke-linecap=\"round\" stroke-linejoin=\"round\"\/>\r\n      <\/svg>\r\n      <div><span class=\"brand-name\">Onground Media<\/span><span class=\"brand-sub\">Marketing toolkit<\/span><\/div>\r\n    <\/div>\r\n    <button class=\"iconbtn\" id=\"themeBtn\" type=\"button\" aria-label=\"Switch theme\"><\/button>\r\n  <\/header>\r\n\r\n  <section class=\"intro\">\r\n    <p class=\"eyebrow\">Design and accessibility<\/p>\r\n    <h1>Contrast Checker<\/h1>\r\n    <p class=\"lede\">Test any text and background pair against WCAG 2.2, see it on a live preview, and fix failing colours in one click.<\/p>\r\n  <\/section>\r\n\r\n  <main class=\"wrap\" style=\"gap:20px;padding:0\">\r\n    <div class=\"workbench\">\r\n      <section class=\"card\" aria-labelledby=\"h-colours\">\r\n        <h2 id=\"h-colours\">Colours<\/h2>\r\n        <p class=\"hint\" style=\"margin-top:4px\">Type a hex code, use the picker, or start from the Onground palette.<\/p>\r\n\r\n        <div class=\"pair\">\r\n          <label class=\"lab l1\" for=\"fgHex\">Text colour<\/label>\r\n          <label class=\"lab l2\" for=\"bgHex\">Background<\/label>\r\n          <div class=\"inrow i1\">\r\n            <label class=\"swatch\" id=\"fgSwatch\"><input type=\"color\" id=\"fgPick\" aria-label=\"Pick text colour\"><\/label>\r\n            <input class=\"hex\" id=\"fgHex\" type=\"text\" maxlength=\"7\" spellcheck=\"false\" autocomplete=\"off\" autocapitalize=\"characters\">\r\n          <\/div>\r\n          <button class=\"swap sw\" id=\"swap\" type=\"button\" aria-label=\"Swap text and background colours\">\r\n            <svg width=\"18\" height=\"18\" viewBox=\"0 0 18 18\" aria-hidden=\"true\"><path d=\"M3 6h11M11 3l3 3-3 3M15 12H4m3 3-3-3 3-3\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.7\" stroke-linecap=\"round\" stroke-linejoin=\"round\"\/><\/svg>\r\n          <\/button>\r\n          <div class=\"inrow i2\">\r\n            <label class=\"swatch\" id=\"bgSwatch\"><input type=\"color\" id=\"bgPick\" aria-label=\"Pick background colour\"><\/label>\r\n            <input class=\"hex\" id=\"bgHex\" type=\"text\" maxlength=\"7\" spellcheck=\"false\" autocomplete=\"off\" autocapitalize=\"characters\">\r\n          <\/div>\r\n          <p class=\"readout r1\" id=\"fgRead\"><\/p>\r\n          <p class=\"readout r2\" id=\"bgRead\"><\/p>\r\n        <\/div>\r\n        <p class=\"err\" id=\"hexErr\" role=\"alert\" hidden>Enter a 3 or 6 digit hex code, for example #4F46E5.<\/p>\r\n\r\n        <div class=\"brandrows\">\r\n          <div><p class=\"mini\">Text from Onground palette<\/p><div class=\"chips\" id=\"fgChips\"><\/div><\/div>\r\n          <div><p class=\"mini\">Background from Onground palette<\/p><div class=\"chips\" id=\"bgChips\"><\/div><\/div>\r\n        <\/div>\r\n      <\/section>\r\n\r\n      <section class=\"hero\" aria-labelledby=\"h-ratio\">\r\n        <div class=\"hero-top\">\r\n          <h2 id=\"h-ratio\">Contrast ratio<\/h2>\r\n          <span class=\"verdict\" id=\"verdict\"><\/span>\r\n        <\/div>\r\n        <div class=\"ratio\" aria-hidden=\"true\"><span id=\"ratioNum\">0.00<\/span><span class=\"colon\">:1<\/span><\/div>\r\n        <div class=\"meter\" aria-hidden=\"true\">\r\n          <div class=\"track\"><\/div>\r\n          <div class=\"thumb\" id=\"thumb\"><\/div>\r\n          <span class=\"tick\" style=\"left:36.09%\"><i><\/i><b>3<\/b><\/span>\r\n          <span class=\"tick\" style=\"left:49.4%\"><i><\/i><b>4.5<\/b><\/span>\r\n          <span class=\"tick\" style=\"left:63.92%\"><i><\/i><b>7<\/b><\/span>\r\n          <span class=\"tick end\" style=\"left:100%\"><i><\/i><b>21<\/b><\/span>\r\n        <\/div>\r\n        <ul class=\"crit\" id=\"crit\"><\/ul>\r\n        <p class=\"note\" id=\"sizeNote\"><\/p>\r\n        <p class=\"sr\" id=\"live\" aria-live=\"polite\"><\/p>\r\n      <\/section>\r\n    <\/div>\r\n\r\n    <section class=\"card\" aria-labelledby=\"h-prev\">\r\n      <div class=\"cardhead\">\r\n        <div><h2 id=\"h-prev\">Live preview<\/h2><p>The stage uses your text and background colours. Change the sample to match your real copy.<\/p><\/div>\r\n        <div class=\"seg\" role=\"tablist\" aria-label=\"Preview type\" id=\"tabs\">\r\n          <button type=\"button\" role=\"tab\" id=\"tab-article\" aria-selected=\"true\" aria-controls=\"pv-article\" tabindex=\"0\">Article<\/button>\r\n          <button type=\"button\" role=\"tab\" id=\"tab-ui\" aria-selected=\"false\" aria-controls=\"pv-ui\" tabindex=\"-1\">Interface<\/button>\r\n          <button type=\"button\" role=\"tab\" id=\"tab-ad\" aria-selected=\"false\" aria-controls=\"pv-ad\" tabindex=\"-1\">Ad banner<\/button>\r\n        <\/div>\r\n      <\/div>\r\n      <div class=\"tools\">\r\n        <div class=\"tool\">\r\n          <label for=\"sizeRange\"><span>Sample text size<\/span><span class=\"val\" id=\"sizeVal\">20 px<\/span><\/label>\r\n          <input type=\"range\" id=\"sizeRange\" min=\"12\" max=\"64\" step=\"1\" value=\"20\">\r\n        <\/div>\r\n        <div class=\"tool\">\r\n          <span class=\"lab\" id=\"wLab\">Weight<\/span>\r\n          <div class=\"seg\" role=\"radiogroup\" aria-labelledby=\"wLab\">\r\n            <label><input type=\"radio\" name=\"wt\" value=\"400\"><span>Regular<\/span><\/label>\r\n            <label><input type=\"radio\" name=\"wt\" value=\"500\" checked><span>Medium<\/span><\/label>\r\n            <label><input type=\"radio\" name=\"wt\" value=\"700\"><span>Bold<\/span><\/label>\r\n          <\/div>\r\n        <\/div>\r\n        <div class=\"tool\">\r\n          <label for=\"sampleText\">Sample text<\/label>\r\n          <input class=\"textin\" id=\"sampleText\" type=\"text\" maxlength=\"140\" value=\"Grow your brand with data-led campaigns that people can actually read.\">\r\n        <\/div>\r\n      <\/div>\r\n\r\n      <div class=\"stage\" id=\"stage\">\r\n        <div id=\"pv-article\" role=\"tabpanel\" aria-labelledby=\"tab-article\">\r\n          <p class=\"pv-eyebrow\">Campaign report<\/p>\r\n          <p class=\"pv-h\">Your audience is growing. Make sure they can read it.<\/p>\r\n          <p class=\"pv-body\" id=\"pvSample\"><\/p>\r\n          <p class=\"pv-body\" style=\"font-size:calc(var(--pv-size)*.8)\">Readers scan headings first, then body copy. <a class=\"pv-link\" href=\"#\">Read the full report<\/a> to see how each channel performed.<\/p>\r\n          <p class=\"pv-small\">Small print at 13 px: results vary by channel, region and audience size.<\/p>\r\n        <\/div>\r\n        <div id=\"pv-ui\" role=\"tabpanel\" aria-labelledby=\"tab-ui\" hidden>\r\n          <p class=\"pv-eyebrow\">Buttons, fields and controls<\/p>\r\n          <div class=\"pv-row\">\r\n            <button class=\"pv-btn solid\" type=\"button\">Start free trial<\/button>\r\n            <button class=\"pv-btn outline\" type=\"button\">Book a demo<\/button>\r\n          <\/div>\r\n          <label class=\"pv-field\" for=\"pvEmail\">Work email\r\n            <input id=\"pvEmail\" type=\"text\" placeholder=\"you@company.com\" tabindex=\"-1\">\r\n          <\/label>\r\n          <div class=\"pv-row\">\r\n            <span class=\"pv-sw\" aria-hidden=\"true\"><i><\/i><\/span>\r\n            <span style=\"font-weight:600\">Weekly digest<\/span>\r\n            <span class=\"pv-badge\">New<\/span><span class=\"pv-badge ol\">Beta<\/span>\r\n          <\/div>\r\n          <p class=\"pv-small\" style=\"margin-top:0\">Borders, icons and focus rings need at least 3:1 against the background (WCAG 1.4.11).<\/p>\r\n        <\/div>\r\n        <div id=\"pv-ad\" role=\"tabpanel\" aria-labelledby=\"tab-ad\" hidden>\r\n          <div class=\"pv-banner\">\r\n            <div>\r\n              <p class=\"pv-eyebrow\">Festive sale \u00b7 3 days only<\/p>\r\n              <p class=\"pv-h\" style=\"margin-bottom:8px\">Up to 40% off annual plans<\/p>\r\n              <p class=\"pv-body\" style=\"margin:0;font-size:calc(var(--pv-size)*.8)\">Offer ends Sunday at midnight.<\/p>\r\n            <\/div>\r\n            <button class=\"pv-btn solid\" type=\"button\">Claim offer<\/button>\r\n          <\/div>\r\n          <p class=\"pv-small\">Terms apply. Discount valid on new annual subscriptions only.<\/p>\r\n        <\/div>\r\n      <\/div>\r\n    <\/section>\r\n\r\n    <section class=\"card\" aria-labelledby=\"h-fix\">\r\n      <div class=\"cardhead\">\r\n        <div><h2 id=\"h-fix\">Fix suggestions<\/h2><p id=\"fixNote\">Closest colour that keeps the same hue and saturation.<\/p><\/div>\r\n      <\/div>\r\n      <div class=\"fixgrid\" id=\"fixes\" tabindex=\"-1\"><\/div>\r\n    <\/section>\r\n\r\n    <section class=\"card\" aria-labelledby=\"h-vision\">\r\n      <div class=\"cardhead\">\r\n        <div><h2 id=\"h-vision\">Colour vision check<\/h2><p>How this pair reads for people with common types of colour vision deficiency.<\/p><\/div>\r\n      <\/div>\r\n      <div class=\"vgrid\" id=\"vision\"><\/div>\r\n    <\/section>\r\n\r\n    <section class=\"card\" aria-labelledby=\"h-matrix\">\r\n      <div class=\"cardhead\">\r\n        <div><h2 id=\"h-matrix\">Onground palette matrix<\/h2><p>Every text and background combination from the brand palette. Select a cell to load it above.<\/p><\/div>\r\n      <\/div>\r\n      <div class=\"mxtools\">\r\n        <label class=\"check\"><input type=\"checkbox\" id=\"onlyPass\"> Highlight pairs that pass AA for body text<\/label>\r\n        <span class=\"hint\" id=\"mxCount\"><\/span>\r\n      <\/div>\r\n      <div class=\"mxscroll\" tabindex=\"0\" role=\"region\" aria-label=\"Palette contrast matrix, scrolls horizontally\">\r\n        <table class=\"matrix\" id=\"matrix\"><\/table>\r\n      <\/div>\r\n      <p class=\"legend\">AAA is 7:1 or more, AA is 4.5:1 or more, Large means 3:1 or more (large text only), Fail is under 3:1.<\/p>\r\n    <\/section>\r\n\r\n    <section class=\"card\" aria-labelledby=\"h-export\">\r\n      <div class=\"exgrid\">\r\n        <div>\r\n          <div class=\"cardhead\" style=\"margin-bottom:14px\"><div><h2 id=\"h-export\">Copy the result<\/h2><p>Paste into your stylesheet or send it with your design feedback.<\/p><\/div><\/div>\r\n          <pre id=\"css\" tabindex=\"0\" aria-label=\"CSS snippet\"><\/pre>\r\n          <div class=\"btnrow\">\r\n            <button class=\"btn primary\" id=\"copyBtn\" type=\"button\">Copy CSS<\/button>\r\n            <button class=\"btn ghost\" id=\"saveBtn\" type=\"button\">Save this pair<\/button>\r\n          <\/div>\r\n        <\/div>\r\n        <div>\r\n          <div class=\"cardhead\" style=\"margin-bottom:14px\"><div><h2>Saved pairs<\/h2><p>Kept in this browser so you can compare options.<\/p><\/div><\/div>\r\n          <div class=\"saved\" id=\"saved\" tabindex=\"-1\"><\/div>\r\n        <\/div>\r\n      <\/div>\r\n    <\/section>\r\n\r\n    <p class=\"foot\">Ratios use the WCAG 2.2 relative luminance formula. Values are truncated, never rounded up, so a pair at 4.49:1 never shows as 4.5:1. Large text means 24 px or bigger, or 18.66 px or bigger in bold.<\/p>\r\n  <\/main>\r\n<\/div>\r\n<div class=\"toast\" id=\"toast\" role=\"status\"><\/div>\r\n\r\n<script>\r\n(function(){\r\n'use strict';\r\nvar $=function(id){return document.getElementById(id)};\r\nvar reduce=window.matchMedia&&matchMedia('(prefers-reduced-motion: reduce)').matches;\r\n\r\n\/*MATH-START*\/\r\nfunction hexToRgb(h){\r\n  var s=String(h).trim().replace(\/^#\/,'');\r\n  if(\/^[0-9a-f]{3}$\/i.test(s)) s=s.split('').map(function(c){return c+c}).join('');\r\n  if(!\/^[0-9a-f]{6}$\/i.test(s)) return null;\r\n  var n=parseInt(s,16);\r\n  return {r:(n>>16)&255,g:(n>>8)&255,b:n&255};\r\n}\r\nfunction toHex(c){\r\n  return '#'+[c.r,c.g,c.b].map(function(v){return Math.round(Math.max(0,Math.min(255,v))).toString(16).padStart(2,'0')}).join('').toUpperCase();\r\n}\r\nfunction lin(v){v\/=255;return v<=0.04045?v\/12.92:Math.pow((v+0.055)\/1.055,2.4)}\r\nfunction lum(c){return 0.2126*lin(c.r)+0.7152*lin(c.g)+0.0722*lin(c.b)}\r\nfunction ratio(a,b){var x=lum(a),y=lum(b);return (Math.max(x,y)+0.05)\/(Math.min(x,y)+0.05)}\r\nfunction fmt(r){return (Math.floor(r*100+1e-9)\/100).toFixed(2)}\r\nfunction rgbToHsl(c){\r\n  var r=c.r\/255,g=c.g\/255,b=c.b\/255,mx=Math.max(r,g,b),mn=Math.min(r,g,b),h=0,s=0,l=(mx+mn)\/2,d=mx-mn;\r\n  if(d){\r\n    s=l>0.5?d\/(2-mx-mn):d\/(mx+mn);\r\n    if(mx===r)h=(g-b)\/d+(g<b?6:0);else if(mx===g)h=(b-r)\/d+2;else h=(r-g)\/d+4;\r\n    h*=60;\r\n  }\r\n  return {h:h,s:s*100,l:l*100};\r\n}\r\nfunction hslToRgb(h,s,l){\r\n  s\/=100;l\/=100;\r\n  var k=function(n){return (n+h\/30)%12},a=s*Math.min(l,1-l);\r\n  var f=function(n){return l-a*Math.max(-1,Math.min(k(n)-3,Math.min(9-k(n),1)))};\r\n  return {r:Math.round(f(0)*255),g:Math.round(f(8)*255),b:Math.round(f(4)*255)};\r\n}\r\nfunction suggest(adj,other,t){\r\n  var cur=ratio(adj,other);\r\n  if(cur>=t) return {state:'already',ratio:cur};\r\n  var hsl=rgbToHsl(adj),best=null;\r\n  [1,-1].forEach(function(dir){\r\n    for(var d=0.25;;d+=0.25){\r\n      var l=hsl.l+dir*d,edge=(l<=0||l>=100);\r\n      l=Math.max(0,Math.min(100,l));\r\n      var c=hslToRgb(hsl.h,hsl.s,l);\r\n      if(ratio(c,other)>=t){ if(!best||d<best.d) best={d:d,dir:dir,c:c}; break; }\r\n      if(edge) break;\r\n    }\r\n  });\r\n  if(!best) return {state:'none'};\r\n  return {state:'ok',rgb:best.c,hex:toHex(best.c),ratio:ratio(best.c,other),d:best.d,dir:best.dir};\r\n}\r\nvar SIM={\r\n  protanopia:[[0.152286,1.052583,-0.204868],[0.114503,0.786281,0.099216],[-0.003882,-0.048116,1.051998]],\r\n  deuteranopia:[[0.367322,0.860646,-0.227968],[0.280085,0.672501,0.047413],[-0.011820,0.042940,0.968881]],\r\n  tritanopia:[[1.255528,-0.076749,-0.178779],[-0.078411,0.930809,0.147602],[0.004733,0.691367,0.303900]]\r\n};\r\nfunction toSrgb(v){v=Math.max(0,Math.min(1,v));return 255*(v<=0.0031308?12.92*v:1.055*Math.pow(v,1\/2.4)-0.055)}\r\nfunction simulate(c,kind){\r\n  var r=lin(c.r),g=lin(c.g),b=lin(c.b);\r\n  if(kind==='achromatopsia'){var y=toSrgb(0.2126*r+0.7152*g+0.0722*b);return {r:Math.round(y),g:Math.round(y),b:Math.round(y)}}\r\n  var m=SIM[kind];\r\n  return {r:Math.round(toSrgb(m[0][0]*r+m[0][1]*g+m[0][2]*b)),g:Math.round(toSrgb(m[1][0]*r+m[1][1]*g+m[1][2]*b)),b:Math.round(toSrgb(m[2][0]*r+m[2][1]*g+m[2][2]*b))};\r\n}\r\nfunction grade(r){return r>=7?'aaa':r>=4.5?'aa':r>=3?'large':'fail'}\r\n\/*MATH-END*\/\r\n\r\nvar BRAND=[\r\n  {n:'Indigo',h:'#4F46E5'},{n:'Deep Navy',h:'#0F172A'},{n:'Vibrant Orange',h:'#FF6B35'},\r\n  {n:'Emerald',h:'#10B981'},{n:'Soft White',h:'#F8FAFC'},{n:'White',h:'#FFFFFF'},\r\n  {n:'Slate',h:'#1E293B'},{n:'Gray',h:'#64748B'},{n:'Light Gray',h:'#E2E8F0'}\r\n];\r\nvar CHECK='<svg viewBox=\"0 0 16 16\" width=\"14\" height=\"14\" aria-hidden=\"true\"><path d=\"M3 8.5l3.2 3L13 4.5\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"\/><\/svg>';\r\nvar CROSS='<svg viewBox=\"0 0 16 16\" width=\"14\" height=\"14\" aria-hidden=\"true\"><path d=\"M4 4l8 8M12 4l-8 8\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\"\/><\/svg>';\r\nvar GRADE_TXT={aaa:'AAA',aa:'AA',large:'Large',fail:'Fail'};\r\nvar state={fg:'#FF6B35',bg:'#F8FAFC',size:20,weight:500};\r\nvar F,B,saved=[],raf=0,shown=1,liveT=0,toastT=0;\r\n\r\nfunction isLarge(){return state.size>=24||(state.weight>=700&&state.size>=18.66)}\r\nfunction toast(t){var el=$('toast');el.textContent=t;el.classList.add('show');clearTimeout(toastT);toastT=setTimeout(function(){el.classList.remove('show')},2200)}\r\nfunction esc(s){return String(s).replace(\/[&<>\"]\/g,function(c){return {'&':'&amp;','<':'&lt;','>':'&gt;','\"':'&quot;'}[c]})}\r\n\r\n\/* theme *\/\r\nvar root=document.documentElement;\r\nfunction effTheme(){return root.getAttribute('data-theme')||((window.matchMedia&&matchMedia('(prefers-color-scheme: dark)').matches)?'dark':'light')}\r\nfunction themeIcon(){\r\n  var dark=effTheme()==='dark';\r\n  $('themeBtn').setAttribute('aria-label',dark?'Switch to light theme':'Switch to dark theme');\r\n  $('themeBtn').innerHTML=dark\r\n   ?'<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" aria-hidden=\"true\"><circle cx=\"10\" cy=\"10\" r=\"3.6\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.7\"\/><path d=\"M10 2.5v2M10 15.5v2M2.5 10h2M15.5 10h2M4.7 4.7l1.4 1.4M13.9 13.9l1.4 1.4M4.7 15.3l1.4-1.4M13.9 6.1l1.4-1.4\" stroke=\"currentColor\" stroke-width=\"1.7\" stroke-linecap=\"round\"\/><\/svg>'\r\n   :'<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" aria-hidden=\"true\"><path d=\"M16.5 11.6A6.8 6.8 0 0 1 8.4 3.5a6.8 6.8 0 1 0 8.1 8.1z\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.7\" stroke-linejoin=\"round\"\/><\/svg>';\r\n}\r\n$('themeBtn').addEventListener('click',function(){root.setAttribute('data-theme',effTheme()==='dark'?'light':'dark');themeIcon()});\r\nif(window.matchMedia){try{matchMedia('(prefers-color-scheme: dark)').addEventListener('change',themeIcon)}catch(e){}}\r\nthemeIcon();\r\n\r\n\/* chips + matrix (built once) *\/\r\nfunction buildChips(which){\r\n  $(which+'Chips').innerHTML=BRAND.map(function(b){\r\n    return '<button type=\"button\" class=\"chip\" data-which=\"'+which+'\" data-hex=\"'+b.h+'\" style=\"--c:'+b.h+'\" aria-pressed=\"false\" aria-label=\"'+esc(b.n)+' '+b.h+'\" title=\"'+esc(b.n)+' '+b.h+'\"><\/button>';\r\n  }).join('');\r\n}\r\nbuildChips('fg');buildChips('bg');\r\ndocument.addEventListener('click',function(e){\r\n  var c=e.target.closest&&e.target.closest('.chip');\r\n  if(c){state[c.dataset.which]=c.dataset.hex;update()}\r\n});\r\n\r\nfunction buildMatrix(){\r\n  var pass=0,total=0;\r\n  var head='<thead><tr><th class=\"corner\" scope=\"col\"><span>Text \u2193<\/span><span>Background \u2192<\/span><\/th>'+BRAND.map(function(b){\r\n    return '<th scope=\"col\"><span class=\"dot\" style=\"background:'+b.h+'\"><\/span><span class=\"nm\">'+esc(b.n)+'<\/span><span class=\"hx\">'+b.h+'<\/span><\/th>';\r\n  }).join('')+'<\/tr><\/thead>';\r\n  var body='<tbody>'+BRAND.map(function(f){\r\n    return '<tr><th scope=\"row\"><span class=\"dot\" style=\"background:'+f.h+'\"><\/span>'+esc(f.n)+'<\/th>'+BRAND.map(function(b){\r\n      if(f.h===b.h) return '<td class=\"same\" aria-label=\"Same colour\">\u2014<\/td>';\r\n      var r=ratio(hexToRgb(f.h),hexToRgb(b.h)),g=grade(r);\r\n      total++;if(r>=4.5)pass++;\r\n      return '<td><button type=\"button\" class=\"cell g-'+g+'\" data-fg=\"'+f.h+'\" data-bg=\"'+b.h+'\" aria-label=\"'+esc(f.n)+' text on '+esc(b.n)+', '+fmt(r)+' to 1, '+GRADE_TXT[g]+'\">'\r\n        +'<span class=\"cs\" style=\"background:'+b.h+';color:'+f.h+'\">Aa<\/span><span class=\"cr\">'+fmt(r)+'<\/span><span class=\"cg\">'+GRADE_TXT[g]+'<\/span><\/button><\/td>';\r\n    }).join('')+'<\/tr>';\r\n  }).join('')+'<\/tbody>';\r\n  $('matrix').innerHTML=head+body;\r\n  $('mxCount').textContent=pass+' of '+total+' pairs pass AA for body text';\r\n}\r\nbuildMatrix();\r\n$('matrix').addEventListener('click',function(e){\r\n  var c=e.target.closest('.cell');\r\n  if(c){state.fg=c.dataset.fg;state.bg=c.dataset.bg;update();toast('Loaded '+c.dataset.fg+' on '+c.dataset.bg)}\r\n});\r\n$('onlyPass').addEventListener('change',function(){$('matrix').classList.toggle('onlypass',this.checked)});\r\n\r\n\/* inputs *\/\r\nfunction bindColour(which){\r\n  var pick=$(which+'Pick'),hex=$(which+'Hex');\r\n  pick.addEventListener('input',function(){state[which]=toHex(hexToRgb(pick.value));$('hexErr').hidden=true;update()});\r\n  hex.addEventListener('input',function(){\r\n    var c=hexToRgb(hex.value);\r\n    if(c){state[which]=toHex(c);hex.classList.remove('bad');$('hexErr').hidden=true;update()}\r\n    else{hex.classList.add('bad');$('hexErr').hidden=false}\r\n  });\r\n  hex.addEventListener('blur',function(){hex.value=state[which];hex.classList.remove('bad');$('hexErr').hidden=true});\r\n}\r\nbindColour('fg');bindColour('bg');\r\n$('swap').addEventListener('click',function(){var t=state.fg;state.fg=state.bg;state.bg=t;update()});\r\n$('sizeRange').addEventListener('input',function(){state.size=+this.value;update()});\r\ndocument.querySelectorAll('input[name=wt]').forEach(function(r){r.addEventListener('change',function(){state.weight=+r.value;update()})});\r\n$('sampleText').addEventListener('input',update);\r\n\r\n\/* tabs *\/\r\nvar tabIds=['article','ui','ad'];\r\nfunction selectTab(id,focus){\r\n  tabIds.forEach(function(t){\r\n    var on=t===id,tab=$('tab-'+t);\r\n    tab.setAttribute('aria-selected',on);tab.tabIndex=on?0:-1;$('pv-'+t).hidden=!on;\r\n    if(on&&focus)tab.focus();\r\n  });\r\n}\r\n$('tabs').addEventListener('click',function(e){var b=e.target.closest('[role=tab]');if(b)selectTab(b.id.replace('tab-',''))});\r\n$('tabs').addEventListener('keydown',function(e){\r\n  var i=tabIds.findIndex(function(t){return $('tab-'+t).getAttribute('aria-selected')==='true'});\r\n  if(e.key==='ArrowRight'){selectTab(tabIds[(i+1)%3],true);e.preventDefault()}\r\n  if(e.key==='ArrowLeft'){selectTab(tabIds[(i+2)%3],true);e.preventDefault()}\r\n});\r\n$('stage').addEventListener('click',function(e){if(e.target.closest('a'))e.preventDefault()});\r\n\r\n\/* ratio tween *\/\r\nfunction paintRatio(v){$('ratioNum').textContent=fmt(v)}\r\nfunction tween(to){\r\n  cancelAnimationFrame(raf);\r\n  if(reduce){shown=to;paintRatio(to);return}\r\n  var from=shown,t0=performance.now();\r\n  (function step(now){\r\n    var k=Math.min(1,(now-t0)\/320),e=1-Math.pow(1-k,3);\r\n    shown=from+(to-from)*e;paintRatio(shown);\r\n    if(k<1)raf=requestAnimationFrame(step);else{shown=to;paintRatio(to)}\r\n  })(t0);\r\n}\r\n\r\n\/* render *\/\r\nfunction setField(which,rgb){\r\n  var hex=state[which],pick=$(which+'Pick'),inp=$(which+'Hex'),hsl=rgbToHsl(rgb);\r\n  pick.value=hex.toLowerCase();\r\n  $(which+'Swatch').style.setProperty('--c',hex);\r\n  if(document.activeElement!==inp)inp.value=hex;\r\n  $(which+'Read').textContent='RGB '+rgb.r+' '+rgb.g+' '+rgb.b+'  \u00b7  HSL '+Math.round(hsl.h)+'\u00b0 '+Math.round(hsl.s)+'% '+Math.round(hsl.l)+'%';\r\n  document.querySelectorAll('#'+which+'Chips .chip').forEach(function(c){c.setAttribute('aria-pressed',c.dataset.hex===hex)});\r\n}\r\nfunction critRows(r){\r\n  var large=isLarge();\r\n  var rows=[\r\n    {l:'Normal text',lv:'AA',min:4.5,k:'normal'},\r\n    {l:'Normal text',lv:'AAA',min:7,k:'normal'},\r\n    {l:'Large text',lv:'AA',min:3,k:'large'},\r\n    {l:'Large text',lv:'AAA',min:4.5,k:'large'},\r\n    {l:'UI components and graphics',lv:'AA',min:3,k:'ui'}\r\n  ];\r\n  return rows.map(function(c){\r\n    var ok=r>=c.min,cur=(c.k==='large'&&large&&c.lv==='AA')||(c.k==='normal'&&!large&&c.lv==='AA');\r\n    return '<li class=\"crow'+(cur?' cur':'')+'\"><span class=\"cl\"><b>'+c.l+'<\/b><small>'+c.lv+' \u00b7 '+c.min+':1 needed<\/small><\/span>'\r\n      +(cur?'<span class=\"tag\">Your text<\/span>':'')\r\n      +'<span class=\"pill '+(ok?'p':'f')+'\">'+(ok?CHECK+'Pass':CROSS+'Fail')+'<\/span><\/li>';\r\n  }).join('');\r\n}\r\nfunction renderHero(r){\r\n  var g=grade(r),v=$('verdict');\r\n  var txt={aaa:'AAA \u00b7 Excellent',aa:'AA \u00b7 Good',large:'AA for large text only',fail:'Fails WCAG'}[g];\r\n  v.className='verdict '+(g==='aaa'||g==='aa'?'v-pass':g==='large'?'v-warn':'v-fail');\r\n  v.innerHTML=(g==='fail'?CROSS:CHECK)+txt;\r\n  $('thumb').style.left=(Math.log(Math.max(1,r))\/Math.log(21)*100)+'%';\r\n  $('crit').innerHTML=critRows(r);\r\n  var wn={400:'regular',500:'medium',700:'bold'}[state.weight];\r\n  $('sizeNote').textContent='Your sample is '+state.size+' px '+wn+', so it counts as '+(isLarge()?'large':'normal')+' text.';\r\n  clearTimeout(liveT);\r\n  liveT=setTimeout(function(){$('live').textContent='Contrast '+fmt(r)+' to 1. '+txt+'.'},500);\r\n}\r\nfunction renderFixes(){\r\n  var large=isLarge(),tAA=large?3:4.5,tAAA=large?4.5:7;\r\n  $('fixNote').textContent='Targets use the '+(large?'large':'normal')+' text thresholds ('+tAA+':1 for AA, '+tAAA+':1 for AAA). The closest colour with the same hue and saturation is suggested.';\r\n  var defs=[['fg','AA',tAA],['fg','AAA',tAAA],['bg','AA',tAA],['bg','AAA',tAAA]];\r\n  $('fixes').innerHTML=defs.map(function(d){\r\n    var which=d[0],lvl=d[1],t=d[2],adj=which==='fg'?F:B,other=which==='fg'?B:F;\r\n    var res=suggest(adj,other,t),title=(which==='fg'?'Text colour':'Background')+' to '+lvl;\r\n    var nf=which==='fg'?state.fg:state.bg,sample,body;\r\n    if(res.state==='already'){\r\n      sample='<div class=\"mini-s\" style=\"background:'+state.bg+';color:'+state.fg+'\">Aa<\/div>';\r\n      body='<span class=\"ok\">'+CHECK+'Already meets '+lvl+'<\/span><span class=\"res\">'+fmt(res.ratio)+':1 now<\/span>';\r\n    }else if(res.state==='none'){\r\n      sample='<div class=\"mini-s\" style=\"background:'+state.bg+';color:'+state.fg+'\">Aa<\/div>';\r\n      body='<span class=\"no\">Changing this colour alone cannot reach '+lvl+'. Try the other colour.<\/span>';\r\n    }else{\r\n      var nfg=which==='fg'?res.hex:state.fg,nbg=which==='bg'?res.hex:state.bg;\r\n      sample='<div class=\"mini-s\" style=\"background:'+nbg+';color:'+nfg+'\">Aa<\/div>';\r\n      body='<span class=\"res\">'+nf+' \u2192 '+res.hex+'<br>'+fmt(res.ratio)+':1 \u00b7 '+Math.round(res.d)+'% '+(res.dir>0?'lighter':'darker')+'<\/span>'\r\n          +'<button class=\"btn primary\" type=\"button\" data-apply=\"'+which+'\" data-hex=\"'+res.hex+'\">Apply<\/button>';\r\n    }\r\n    return '<div class=\"fix\"><div><h3>'+title+'<\/h3><p class=\"sub\">'+t+':1 needed<\/p><\/div>'+sample+body+'<\/div>';\r\n  }).join('');\r\n}\r\n$('fixes').addEventListener('click',function(e){\r\n  var b=e.target.closest('[data-apply]');\r\n  if(!b)return;\r\n  state[b.dataset.apply]=b.dataset.hex;update();toast('Applied '+b.dataset.hex);$('fixes').focus();\r\n});\r\nfunction renderVision(){\r\n  var kinds=[['normal','Normal vision'],['protanopia','Protanopia (red-blind)'],['deuteranopia','Deuteranopia (green-blind)'],['tritanopia','Tritanopia (blue-blind)'],['achromatopsia','Greyscale']];\r\n  var need=isLarge()?3:4.5;\r\n  $('vision').innerHTML=kinds.map(function(k){\r\n    var f=k[0]==='normal'?F:simulate(F,k[0]),b=k[0]==='normal'?B:simulate(B,k[0]),r=ratio(f,b),ok=r>=need;\r\n    return '<div class=\"vtile\"><div class=\"vs\" style=\"background:'+toHex(b)+';color:'+toHex(f)+'\">Aa<\/div><div class=\"vf\"><b>'+k[1]+'<\/b><div class=\"vr\"><span>'+fmt(r)+':1<\/span><span class=\"badge '+(ok?'p':'f')+'\">'+(ok?CHECK+'AA':CROSS+'Fail')+'<\/span><\/div><\/div><\/div>';\r\n  }).join('');\r\n}\r\nfunction renderExport(r){\r\n  var rows=[['AA normal text',4.5],['AAA normal text',7],['AA large text',3],['AAA large text',4.5],['UI components',3]];\r\n  var css='.element {\\n  color: '+state.fg+';\\n  background-color: '+state.bg+';\\n}\\n\/* Contrast '+fmt(r)+':1\\n'+rows.map(function(x){return '   '+x[0]+': '+(r>=x[1]?'pass':'fail')}).join('\\n')+' *\/';\r\n  $('css').textContent=css;\r\n}\r\nfunction updateMatrix(){\r\n  document.querySelectorAll('.cell').forEach(function(c){c.classList.toggle('sel',c.dataset.fg===state.fg&&c.dataset.bg===state.bg)});\r\n}\r\nfunction update(){\r\n  F=hexToRgb(state.fg);B=hexToRgb(state.bg);\r\n  var r=ratio(F,B);\r\n  setField('fg',F);setField('bg',B);\r\n  var st=$('stage');\r\n  st.style.setProperty('--pv-fg',state.fg);st.style.setProperty('--pv-bg',state.bg);\r\n  st.style.setProperty('--pv-size',state.size+'px');st.style.setProperty('--pv-weight',state.weight);\r\n  $('sizeVal').textContent=state.size+' px';\r\n  $('pvSample').textContent=$('sampleText').value||'Type your own sample text to preview it here.';\r\n  tween(r);renderHero(r);renderFixes();renderVision();renderExport(r);updateMatrix();\r\n}\r\n\r\n\/* copy + saved *\/\r\n$('copyBtn').addEventListener('click',function(){\r\n  var text=$('css').textContent;\r\n  try{\r\n    navigator.clipboard.writeText(text).then(function(){toast('CSS copied')},function(){fallback()});\r\n  }catch(e){fallback()}\r\n  function fallback(){\r\n    var rg=document.createRange();rg.selectNodeContents($('css'));\r\n    var s=window.getSelection();s.removeAllRanges();s.addRange(rg);toast('Press Ctrl or Cmd + C to copy');\r\n  }\r\n});\r\nfunction loadSaved(){try{var v=JSON.parse(localStorage.getItem('og-cc-saved')||'[]');if(Array.isArray(v))saved=v.filter(function(p){return p&&hexToRgb(p.fg)&&hexToRgb(p.bg)}).slice(0,8)}catch(e){}}\r\nfunction persist(){try{localStorage.setItem('og-cc-saved',JSON.stringify(saved))}catch(e){}}\r\nfunction renderSaved(){\r\n  if(!saved.length){$('saved').innerHTML='<p class=\"empty\">No saved pairs yet. Save the current pair to compare it with other options later.<\/p>';return}\r\n  $('saved').innerHTML=saved.map(function(p,i){\r\n    var r=ratio(hexToRgb(p.fg),hexToRgb(p.bg));\r\n    return '<div class=\"sitem\"><button type=\"button\" class=\"sload\" data-load=\"'+i+'\" aria-label=\"Load '+p.fg+' on '+p.bg+'\"><span class=\"mini-s\" style=\"background:'+p.bg+';color:'+p.fg+'\">Aa<\/span>'\r\n      +'<span class=\"t\"><b>'+p.fg+' on '+p.bg+'<\/b><span>'+fmt(r)+':1 \u00b7 '+GRADE_TXT[grade(r)]+'<\/span><\/span><\/button>'\r\n      +'<button type=\"button\" class=\"sdel\" data-del=\"'+i+'\" aria-label=\"Remove saved pair '+p.fg+' on '+p.bg+'\">'+CROSS+'<\/button><\/div>';\r\n  }).join('');\r\n}\r\n$('saveBtn').addEventListener('click',function(){\r\n  if(saved.some(function(p){return p.fg===state.fg&&p.bg===state.bg})){toast('This pair is already saved');return}\r\n  saved.unshift({fg:state.fg,bg:state.bg});saved=saved.slice(0,8);persist();renderSaved();toast('Pair saved');\r\n});\r\n$('saved').addEventListener('click',function(e){\r\n  var l=e.target.closest('[data-load]'),d=e.target.closest('[data-del]');\r\n  if(l){var p=saved[+l.dataset.load];if(p){state.fg=p.fg;state.bg=p.bg;update()}}\r\n  if(d){saved.splice(+d.dataset.del,1);persist();renderSaved();$('saved').focus()}\r\n});\r\nloadSaved();renderSaved();\r\nupdate();\r\n})();\r\n<\/script>\r\n\r\n<\/body><\/html>\t\t\t\t<\/div>\n\t\t\n<\/div>\n\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>Onground Contrast Checker Onground MediaMarketing toolkit Design and accessibility Contrast Checker Test any text and background pair against WCAG 2.2, [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"site-sidebar-layout":"no-sidebar","site-content-layout":"","ast-site-content-layout":"full-width-container","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"disabled","footer-sml-layout":"","ast-disable-related-posts":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-4)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"footnotes":""},"class_list":["post-463","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/ongroundmedia.com\/index.php?rest_route=\/wp\/v2\/pages\/463","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ongroundmedia.com\/index.php?rest_route=\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/ongroundmedia.com\/index.php?rest_route=\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/ongroundmedia.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/ongroundmedia.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=463"}],"version-history":[{"count":6,"href":"https:\/\/ongroundmedia.com\/index.php?rest_route=\/wp\/v2\/pages\/463\/revisions"}],"predecessor-version":[{"id":500,"href":"https:\/\/ongroundmedia.com\/index.php?rest_route=\/wp\/v2\/pages\/463\/revisions\/500"}],"wp:attachment":[{"href":"https:\/\/ongroundmedia.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=463"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}