{"id":41511,"date":"2026-05-06T17:43:38","date_gmt":"2026-05-06T21:43:38","guid":{"rendered":"https:\/\/ohiotesol.org\/web\/?page_id=41511"},"modified":"2026-05-06T17:45:05","modified_gmt":"2026-05-06T21:45:05","slug":"advocacy-find-your-legislators-tool","status":"publish","type":"page","link":"https:\/\/ohiotesol.org\/web\/advocacy-find-your-legislators-tool\/","title":{"rendered":"Advocacy &#8211; Find your Legislators Tool"},"content":{"rendered":"\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"UTF-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<title>Find Your Legislators \u2014 Ohio TESOL Advocacy<\/title>\n<link href=\"https:\/\/fonts.googleapis.com\/css2?family=Poppins:ital,wght@0,400;0,600;0,700;0,800;1,800&#038;display=swap\" rel=\"stylesheet\">\n<style>\n:root{\n  --plum:#47425D;--coral:#E64E4E;--amber:#FFAC00;\n  --ink:#443F3F;--muted:#68647A;--mist:#F7F7F7;\n  --rule:#EBEBEB;--slate:#767676;--paper:#FFFFFF;\n  --federal:#2C5F8A;\n}\n*{box-sizing:border-box;margin:0;padding:0}\nbody{font-family:'Poppins',sans-serif;font-size:16px;line-height:1.6;color:var(--ink);background:var(--paper)}\n\n.hdr{background:var(--plum);padding:48px 24px;text-align:center}\n.eye{font-size:12px;font-weight:600;letter-spacing:2px;text-transform:uppercase;color:rgba(255,255,255,.6);margin-bottom:10px}\n.hdr h1{font-size:36px;font-weight:800;font-style:italic;color:#fff;line-height:1.1;margin-bottom:14px}\n.hdr p{font-size:16px;color:rgba(255,255,255,.82);max-width:580px;margin:0 auto}\n\n.wrap{max-width:960px;margin:0 auto;padding:0 20px}\n.band{padding:48px 0}\n.band-alt{background:var(--mist)}\n.sec-lbl{font-size:11px;font-weight:600;letter-spacing:1.5px;text-transform:uppercase;color:var(--muted);text-align:center;margin-bottom:18px}\n\n.lookup-box{max-width:640px;margin:0 auto 40px;background:var(--paper);border:1.5px solid var(--rule);border-radius:12px;padding:28px}\n.lookup-box h2{font-size:18px;font-weight:700;color:var(--plum);margin-bottom:6px}\n.lookup-box p{font-size:13px;color:var(--muted);margin-bottom:20px}\n.lookup-row{display:flex;flex-wrap:wrap;gap:10px;align-items:flex-end}\n.lookup-row .addr-wrap{flex:1;min-width:200px}\n.lookup-row .zip-wrap{width:116px}\n.fl{display:block;font-size:12px;font-weight:600;letter-spacing:.5px;color:var(--plum);margin-bottom:6px}\n.finput{font-family:'Poppins',sans-serif;font-size:14px;width:100%;padding:10px 16px;border:1.5px solid var(--rule);border-radius:8px;color:var(--ink);outline:none;transition:border-color .15s}\n.finput:focus{border-color:var(--coral);box-shadow:0 0 0 3px rgba(230,78,78,.1)}\n#geoStatus{font-size:13px;margin-top:12px;min-height:20px;line-height:1.5}\n\n.or-divider{display:flex;align-items:center;gap:12px;max-width:640px;margin:0 auto 28px;color:var(--slate);font-size:12px;font-weight:600;letter-spacing:1px;text-transform:uppercase}\n.or-divider::before,.or-divider::after{content:'';flex:1;height:1px;background:var(--rule)}\n\n.map-scroll{overflow-x:auto;padding:4px 0}\n.cg{display:grid;grid-template-columns:repeat(10,66px);grid-template-rows:repeat(10,44px);gap:3px;width:max-content;margin:0 auto}\n.ct{display:flex;align-items:center;justify-content:center;font-family:'Poppins',sans-serif;font-size:9px;font-weight:600;text-align:center;line-height:1.2;padding:3px 2px;background:var(--paper);color:var(--plum);border:1.5px solid var(--rule);border-radius:4px;cursor:pointer;user-select:none;transition:all .12s;box-shadow:0 1px 2px rgba(71,66,93,.06)}\n.ct.reg-n{background:#EBE7F2;border-color:#D8D1E5}\n.ct.reg-c{background:#F7F1DF;border-color:#EBE0BD}\n.ct.reg-s{background:#F3E7DC;border-color:#E5D0BD}\n.ct:hover{background:#C9BEE0;border-color:var(--plum);transform:translateY(-1px);box-shadow:0 3px 6px rgba(71,66,93,.15)}\n.ct.sel{background:var(--coral);color:#fff;border-color:var(--coral);box-shadow:0 2px 6px rgba(230,78,78,.3)}\n.ct:focus-visible{outline:2px solid var(--coral);outline-offset:2px}\n\n\/* Region legend *\/\n.region-legend{display:flex;gap:18px;justify-content:center;margin-top:14px;flex-wrap:wrap;font-size:11px;color:var(--muted);font-weight:600;letter-spacing:.5px;text-transform:uppercase}\n.region-legend .swatch{display:inline-block;width:12px;height:12px;border-radius:3px;vertical-align:middle;margin-right:5px;border:1px solid rgba(71,66,93,.15)}\n\n.ctrls{display:flex;flex-wrap:wrap;gap:14px;align-items:flex-end;justify-content:center;margin-top:28px}\n.sel-w select{font-family:'Poppins',sans-serif;font-size:14px;padding:10px 40px 10px 18px;border:1.5px solid var(--rule);border-radius:100px;background:#fff url(\"data:image\/svg+xml,%3Csvg xmlns='http:\/\/www.w3.org\/2000\/svg' width='10' height='6'%3E%3Cpath d='M0 0l5 6 5-6z' fill='%2347425D'\/%3E%3C\/svg%3E\") no-repeat right 14px center;-webkit-appearance:none;appearance:none;color:var(--ink);min-width:220px;cursor:pointer;outline:none}\n.sel-w select:focus{border-color:var(--coral);box-shadow:0 0 0 3px rgba(230,78,78,.12)}\n\n.btn{font-family:'Poppins',sans-serif;font-size:13px;font-weight:600;letter-spacing:1px;text-transform:uppercase;padding:11px 28px;border-radius:100px;cursor:pointer;transition:all .15s;border:1.5px solid}\n.btn:disabled{opacity:.5;cursor:not-allowed}\n.btn-p{border-color:var(--coral);background:transparent;color:var(--coral)}\n.btn-p:hover:not(:disabled){background:var(--coral);color:#fff}\n.btn-s{border-color:var(--ink);background:transparent;color:var(--ink)}\n.btn-s:hover:not(:disabled){background:var(--ink);color:#fff}\n.btn-sm{font-size:12px;padding:8px 18px}\n\n.spin{display:inline-block;width:14px;height:14px;border:2px solid rgba(230,78,78,.3);border-top-color:var(--coral);border-radius:50%;animation:spin .7s linear infinite;vertical-align:middle;margin-right:6px}\n@keyframes spin{to{transform:rotate(360deg)}}\n\n.notice{border-left:4px solid var(--amber);background:#fffbf0;padding:14px 18px;border-radius:0 6px 6px 0;font-size:13px;color:var(--ink);margin-top:28px}\n.notice strong{color:var(--plum)}\n.notice a{color:var(--coral);text-decoration:none}\n.notice a:hover{text-decoration:underline}\n\n#res{display:none}\n.rhed{margin-bottom:28px;padding-bottom:18px;border-bottom:1.5px solid var(--rule)}\n.rhed h2{font-size:24px;font-weight:700;color:var(--plum)}\n.rhed p{font-size:14px;color:var(--muted);margin-top:4px}\n\n.level-section{margin-bottom:36px}\n.level-header{display:flex;align-items:center;gap:12px;margin-bottom:16px}\n.level-badge{font-size:11px;font-weight:700;letter-spacing:1.5px;text-transform:uppercase;padding:4px 14px;border-radius:100px;white-space:nowrap}\n.badge-federal{background:var(--federal);color:#fff}\n.badge-state{background:var(--plum);color:#fff}\n.level-desc{font-size:13px;color:var(--muted)}\n.level-rule{flex:1;height:1px;background:var(--rule)}\n\n.cards{display:grid;grid-template-columns:repeat(auto-fill,minmax(260px,1fr));gap:16px}\n.card{background:var(--paper);border:1.5px solid var(--rule);border-radius:8px;padding:20px;position:relative;overflow:hidden}\n.card::before{content:'';position:absolute;top:0;left:0;right:0;height:4px}\n.card.federal::before{background:var(--federal)}\n.card.state-senate::before{background:var(--plum)}\n.card.state-house::before{background:var(--coral)}\n.c-chamber{font-size:11px;font-weight:600;letter-spacing:1.5px;text-transform:uppercase;color:var(--muted);margin-bottom:6px}\n.c-name{font-size:19px;font-weight:700;color:var(--plum);margin-bottom:2px;line-height:1.2}\n.c-meta{font-size:12px;color:var(--slate);margin-bottom:10px}\n.c-party{display:inline-block;font-size:11px;font-weight:600;padding:2px 10px;border-radius:100px;margin-bottom:12px}\n.party-D{background:#dbeafe;color:#1e40af}\n.party-R{background:#fee2e2;color:#991b1b}\n.party-I{background:#f3f4f6;color:#374151}\n.c-links{display:flex;flex-direction:column;gap:7px}\n.c-links a{font-size:13px;color:var(--coral);text-decoration:none;display:inline-flex;align-items:center;gap:6px;word-break:break-all}\n.c-links a:hover{text-decoration:underline}\n.no-email{font-size:13px;color:var(--slate);display:flex;align-items:center;gap:6px}\n\n.ebox{background:var(--paper);border:1.5px solid var(--rule);border-radius:8px;padding:24px}\n.ebox h3{font-size:18px;font-weight:700;color:var(--plum);margin-bottom:6px}\n.hint{font-size:13px;color:var(--muted);margin-bottom:18px}\n.row-label{font-size:13px;font-weight:600;color:var(--plum);white-space:nowrap}\n.to-row{display:flex;flex-wrap:wrap;gap:8px;align-items:center;margin-bottom:14px}\n.tmpl-row{display:flex;flex-wrap:wrap;gap:8px;align-items:center;margin-bottom:14px}\n.tbn,.tmpl-btn{font-family:'Poppins',sans-serif;font-size:12px;font-weight:600;padding:5px 14px;border-radius:100px;border:1.5px solid var(--rule);background:var(--mist);color:var(--plum);cursor:pointer;transition:all .12s}\n.tbn.on,.tmpl-btn.on{background:var(--plum);color:#fff;border-color:var(--plum)}\n.srow{margin-bottom:12px}\n.srow input{font-family:'Poppins',sans-serif;font-size:14px;width:100%;padding:10px 16px;border:1.5px solid var(--rule);border-radius:8px;color:var(--ink);outline:none}\n.srow input:focus{border-color:var(--coral);box-shadow:0 0 0 3px rgba(230,78,78,.1)}\ntextarea{font-family:'Poppins',sans-serif;font-size:13.5px;line-height:1.65;color:var(--ink);width:100%;border:1.5px solid var(--rule);border-radius:8px;padding:16px;resize:vertical;min-height:320px;outline:none}\ntextarea:focus{border-color:var(--coral);box-shadow:0 0 0 3px rgba(230,78,78,.1)}\n.ea{display:flex;flex-wrap:wrap;gap:10px;margin-top:16px}\n\n.change-btn{font-family:'Poppins',sans-serif;font-size:12px;font-weight:600;padding:6px 16px;border-radius:100px;border:1.5px solid rgba(255,255,255,.3);background:transparent;color:rgba(255,255,255,.85);cursor:pointer;transition:all .15s;letter-spacing:.5px;margin-top:14px}\n.change-btn:hover{border-color:#fff;color:#fff}\n\nfooter{background:var(--plum);color:rgba(255,255,255,.65);text-align:center;padding:28px 20px;font-size:13px}\nfooter a{color:var(--coral);text-decoration:none}\nfooter a:hover{text-decoration:underline}\n\n@media(max-width:640px){\n  .hdr h1{font-size:26px}\n  .lookup-row{flex-direction:column}\n  .lookup-row .zip-wrap{width:100%}\n  .cg{grid-template-columns:repeat(10,50px);grid-template-rows:repeat(10,36px);gap:2px}\n  .ct{font-size:7px}\n  .level-desc{display:none}\n}\n<\/style>\n<\/head>\n<body>\n\n<header class=\"hdr\">\n  <div class=\"eye\">Ohio TESOL \u00b7 Advocacy<\/div>\n  <h1>Find Your Legislators<\/h1>\n  <p>Enter your address to find your federal and state legislators \u2014 then send them a message in support of multilingual learners.<\/p>\n<\/header>\n\n<div class=\"band\">\n  <div class=\"wrap\">\n\n    <div class=\"lookup-box\">\n      <h2>Look Up by Address or ZIP Code<\/h2>\n      <p>Enter your home or school address for the most accurate results. Your address is used only to identify your district and is never stored.<\/p>\n      <div class=\"lookup-row\">\n        <div class=\"addr-wrap\">\n          <label class=\"fl\" for=\"addrIn\">Street address <span style=\"font-weight:400;color:var(--slate)\">(optional)<\/span><\/label>\n          <input class=\"finput\" type=\"text\" id=\"addrIn\" placeholder=\"123 Main St, Columbus\"\n            onkeydown=\"if(event.key==='Enter')geoLookup()\">\n        <\/div>\n        <div class=\"zip-wrap\">\n          <label class=\"fl\" for=\"zipIn\">ZIP code<\/label>\n          <input class=\"finput\" type=\"text\" id=\"zipIn\" placeholder=\"43215\" maxlength=\"5\"\n            onkeydown=\"if(event.key==='Enter')geoLookup()\">\n        <\/div>\n        <div>\n          <button class=\"btn btn-p\" id=\"geoBtn\" onclick=\"geoLookup()\">Find My Legislators<\/button>\n        <\/div>\n      <\/div>\n      <div id=\"geoStatus\"><\/div>\n    <\/div>\n\n    <div class=\"or-divider\">or browse by county<\/div>\n\n    <div class=\"sec-lbl\">Click your county on the map \u2014 or choose from the dropdown<\/div>\n    <div class=\"map-scroll\">\n      <div class=\"cg\" id=\"cg\" role=\"group\" aria-label=\"Ohio county map\"><\/div>\n    <\/div>\n    <div class=\"region-legend\" aria-label=\"Map region legend\">\n      <span><span class=\"swatch\" style=\"background:#EBE7F2\"><\/span>Northern Ohio<\/span>\n      <span><span class=\"swatch\" style=\"background:#F7F1DF\"><\/span>Central Ohio<\/span>\n      <span><span class=\"swatch\" style=\"background:#F3E7DC\"><\/span>Southern Ohio<\/span>\n    <\/div>\n\n    <div class=\"ctrls\">\n      <div class=\"sel-w\">\n        <label class=\"fl\" for=\"csel\">Choose a county<\/label>\n        <select id=\"csel\" onchange=\"onDropdown(this.value)\">\n          <option value=\"\">\u2014 Select a county \u2014<\/option>\n        <\/select>\n      <\/div>\n      <div>\n        <div style=\"height:22px\"><\/div>\n        <button class=\"btn btn-p\" onclick=\"countyLookup()\">Find My Legislators<\/button>\n      <\/div>\n    <\/div>\n\n    <div class=\"notice\">\n      <strong>Note on county-level results:<\/strong> Selecting a county uses the county seat to identify likely legislators. For the most precise match \u2014 especially in counties spanning multiple districts \u2014 use the address lookup above. Always verify at\n      <a href=\"https:\/\/www.legislature.ohio.gov\/legislators\/legislators-by-location\" target=\"_blank\" rel=\"noopener\">Ohio&#8217;s official Find My Legislator<\/a>.\n    <\/div>\n\n  <\/div>\n<\/div>\n\n<div class=\"band band-alt\" id=\"res\">\n  <div class=\"wrap\">\n    <div class=\"rhed\">\n      <h2 id=\"rh\">Your Legislators<\/h2>\n      <p id=\"rp\"><\/p>\n    <\/div>\n\n    <div class=\"level-section\" id=\"fedSection\" style=\"display:none\">\n      <div class=\"level-header\">\n        <span class=\"level-badge badge-federal\">Federal<\/span>\n        <span class=\"level-desc\">U.S. Congress \u2014 Title III \/ ESSA funding, immigration policy, federal education law<\/span>\n        <div class=\"level-rule\"><\/div>\n      <\/div>\n      <div class=\"cards\" id=\"fedCards\"><\/div>\n    <\/div>\n\n    <div class=\"level-section\" id=\"stateSection\" style=\"display:none\">\n      <div class=\"level-header\">\n        <span class=\"level-badge badge-state\">State<\/span>\n        <span class=\"level-desc\">Ohio General Assembly \u2014 state ELD funding, educator certification, school policy<\/span>\n        <div class=\"level-rule\"><\/div>\n      <\/div>\n      <div class=\"cards\" id=\"stateCards\"><\/div>\n    <\/div>\n\n    <div class=\"ebox\">\n      <h3>Draft an Advocacy Message<\/h3>\n      <p class=\"hint\">Personalize this message with your school, classroom, and a specific story. Personal messages carry far more weight than form letters.<\/p>\n\n      <div style=\"background:var(--mist);border-radius:8px;padding:16px 18px;margin-bottom:20px;display:grid;grid-template-columns:1fr 1fr;gap:12px\">\n        <div>\n          <div style=\"font-size:11px;font-weight:700;letter-spacing:1.5px;text-transform:uppercase;color:var(--federal);margin-bottom:6px\">For Federal Legislators<\/div>\n          <ol style=\"font-size:13px;color:var(--ink);padding-left:18px;line-height:1.7\">\n            <li>Select your U.S. Senator or Representative below.<\/li>\n            <li>Personalize the message in the box.<\/li>\n            <li>Click <strong style=\"color:var(--ink);border:1.5px solid var(--ink);padding:1px 8px;border-radius:100px;white-space:nowrap;font-size:11px;letter-spacing:.5px\">COPY MESSAGE<\/strong>.<\/li>\n            <li>Click <strong style=\"color:var(--coral);border:1.5px solid var(--coral);padding:1px 8px;border-radius:100px;white-space:nowrap;font-size:11px;letter-spacing:.5px\">OPEN CONTACT FORM<\/strong> \u2014 it opens their official web form in a new tab.<\/li>\n            <li>Paste your message into the form and submit.<\/li>\n          <\/ol>\n        <\/div>\n        <div style=\"border-left:1.5px solid var(--rule);padding-left:12px\">\n          <div style=\"font-size:11px;font-weight:700;letter-spacing:1.5px;text-transform:uppercase;color:var(--plum);margin-bottom:6px\">For State Legislators<\/div>\n          <ol style=\"font-size:13px;color:var(--ink);padding-left:18px;line-height:1.7\">\n            <li>Select your Ohio Senator or Representative below.<\/li>\n            <li>Personalize the message in the box.<\/li>\n            <li>Click <strong style=\"color:var(--coral);border:1.5px solid var(--coral);padding:1px 8px;border-radius:100px;white-space:nowrap;font-size:11px;letter-spacing:.5px\">OPEN IN EMAIL CLIENT<\/strong> \u2014 it opens a pre-addressed email in your email app.<\/li>\n            <li>Review and send.<\/li>\n          <\/ol>\n        <\/div>\n      <\/div>\n\n      <div class=\"to-row\">\n        <span class=\"row-label\">Send to:<\/span>\n        <div id=\"toRow\" style=\"display:flex;flex-wrap:wrap;gap:8px\"><\/div>\n      <\/div>\n\n      <div class=\"tmpl-row\">\n        <span class=\"row-label\">Template:<\/span>\n        <button class=\"tmpl-btn on\" onclick=\"setTmpl(0,this)\">General Advocacy<\/button>\n        <button class=\"tmpl-btn\" onclick=\"setTmpl(1,this)\">ELL Funding<\/button>\n        <button class=\"tmpl-btn\" onclick=\"setTmpl(2,this)\">Educator Support<\/button>\n        <button class=\"tmpl-btn\" onclick=\"setTmpl(3,this)\">Federal (ESSA \/ Title III)<\/button>\n      <\/div>\n\n      <div class=\"srow\">\n        <label class=\"fl\" for=\"esub\">Email subject<\/label>\n        <input type=\"text\" id=\"esub\" value=\"Supporting Multilingual Learners in Ohio \u2014 A Message from an Educator\">\n      <\/div>\n\n      <label class=\"fl\" for=\"ebody\">Message <span style=\"font-weight:400;color:var(--muted)\">(edit and personalize before sending)<\/span><\/label>\n      <textarea id=\"ebody\"><\/textarea>\n\n      <div class=\"ea\">\n        <button class=\"btn btn-p btn-sm\" id=\"emailBtn\" onclick=\"openEmail()\">Open in Email Client<\/button>\n        <button class=\"btn btn-s btn-sm\" onclick=\"copyMsg(event)\">Copy Message<\/button>\n        <button class=\"btn btn-s btn-sm\" onclick=\"resetTmpl()\">Reset Template<\/button>\n      <\/div>\n    <\/div>\n\n    <div style=\"text-align:center\">\n      <button class=\"change-btn\" onclick=\"scrollUp()\">\u2191 Search Again<\/button>\n    <\/div>\n  <\/div>\n<\/div>\n\n<footer>\n  <p>Ohio TESOL \u2014 Advancing excellence in teaching English to speakers of other languages.<br>\n  <a href=\"https:\/\/ohiotesol.org\/web\" target=\"_blank\" rel=\"noopener\">ohiotesol.org<\/a> &nbsp;\u00b7&nbsp;\n  <a href=\"mailto:ohiotesol@gmail.com\">ohiotesol@gmail.com<\/a><\/p>\n  <p style=\"margin-top:8px;font-size:11px;opacity:.6\">Legislator data provided by <a href=\"https:\/\/openstates.org\" target=\"_blank\" rel=\"noopener\">OpenStates<\/a>. Geocoding by <a href=\"https:\/\/nominatim.openstreetmap.org\" target=\"_blank\" rel=\"noopener\">Nominatim \/ OpenStreetMap<\/a>.<\/p>\n<\/footer>\n\n<script>\n\/\/ ================================================================\n\/\/ API KEY OBFUSCATION\n\/\/ ----------------------------------------------------------------\n\/\/ The OpenStates API key is split into base64-encoded chunks and\n\/\/ reassembled at runtime. This is NOT encryption \u2014 a determined\n\/\/ user can still find the key by opening browser DevTools and\n\/\/ inspecting the Network tab during an API call. This obfuscation\n\/\/ only prevents:\n\/\/   \u2022 The raw key appearing in View Source\n\/\/   \u2022 Automated bots that scan websites for UUID-pattern API keys\n\/\/\n\/\/ For true security, proxy the OpenStates call through a\n\/\/ serverless function (AWS Lambda, Netlify Functions, Cloudflare\n\/\/ Workers, etc.) so the key lives server-side and never reaches\n\/\/ the browser.\n\/\/\n\/\/ To rotate the key: run this in the browser console, then paste\n\/\/ the output below, replacing the `_kParts` array:\n\/\/   btoa('your-new-key').match(\/.{1,4}\/g)\n\/\/ ================================================================\nconst _kParts = ['M2Vk','NWMw','MzEt','ZWIw','MC00','ZDM4','LThk','Y2Qt','ZDQy','YzRm','MjIy','ZGY4'];\nconst OPENSTATES_KEY = atob(_kParts.join(''));\n\nconst COUNTY_SEATS = {\n  \"Adams\":\"West Union, Ohio\",\"Allen\":\"Lima, Ohio\",\"Ashland\":\"Ashland, Ohio\",\n  \"Ashtabula\":\"Jefferson, Ohio\",\"Athens\":\"Athens, Ohio\",\"Auglaize\":\"Wapakoneta, Ohio\",\n  \"Belmont\":\"St. Clairsville, Ohio\",\"Brown\":\"Georgetown, Ohio\",\"Butler\":\"Hamilton, Ohio\",\n  \"Carroll\":\"Carrollton, Ohio\",\"Champaign\":\"Urbana, Ohio\",\"Clark\":\"Springfield, Ohio\",\n  \"Clermont\":\"Batavia, Ohio\",\"Clinton\":\"Wilmington, Ohio\",\"Columbiana\":\"Lisbon, Ohio\",\n  \"Coshocton\":\"Coshocton, Ohio\",\"Crawford\":\"Bucyrus, Ohio\",\"Cuyahoga\":\"Cleveland, Ohio\",\n  \"Darke\":\"Greenville, Ohio\",\"Defiance\":\"Defiance, Ohio\",\"Delaware\":\"Delaware, Ohio\",\n  \"Erie\":\"Sandusky, Ohio\",\"Fairfield\":\"Lancaster, Ohio\",\"Fayette\":\"Washington Court House, Ohio\",\n  \"Franklin\":\"Columbus, Ohio\",\"Fulton\":\"Wauseon, Ohio\",\"Gallia\":\"Gallipolis, Ohio\",\n  \"Geauga\":\"Chardon, Ohio\",\"Greene\":\"Xenia, Ohio\",\"Guernsey\":\"Cambridge, Ohio\",\n  \"Hamilton\":\"Cincinnati, Ohio\",\"Hancock\":\"Findlay, Ohio\",\"Hardin\":\"Kenton, Ohio\",\n  \"Harrison\":\"Cadiz, Ohio\",\"Henry\":\"Napoleon, Ohio\",\"Highland\":\"Hillsboro, Ohio\",\n  \"Hocking\":\"Logan, Ohio\",\"Holmes\":\"Millersburg, Ohio\",\"Huron\":\"Norwalk, Ohio\",\n  \"Jackson\":\"Jackson, Ohio\",\"Jefferson\":\"Steubenville, Ohio\",\"Knox\":\"Mount Vernon, Ohio\",\n  \"Lake\":\"Painesville, Ohio\",\"Lawrence\":\"Ironton, Ohio\",\"Licking\":\"Newark, Ohio\",\n  \"Logan\":\"Bellefontaine, Ohio\",\"Lorain\":\"Elyria, Ohio\",\"Lucas\":\"Toledo, Ohio\",\n  \"Madison\":\"London, Ohio\",\"Mahoning\":\"Youngstown, Ohio\",\"Marion\":\"Marion, Ohio\",\n  \"Medina\":\"Medina, Ohio\",\"Meigs\":\"Pomeroy, Ohio\",\"Mercer\":\"Celina, Ohio\",\n  \"Miami\":\"Troy, Ohio\",\"Monroe\":\"Woodsfield, Ohio\",\"Montgomery\":\"Dayton, Ohio\",\n  \"Morgan\":\"McConnelsville, Ohio\",\"Morrow\":\"Mount Gilead, Ohio\",\"Muskingum\":\"Zanesville, Ohio\",\n  \"Noble\":\"Caldwell, Ohio\",\"Ottawa\":\"Port Clinton, Ohio\",\"Paulding\":\"Paulding, Ohio\",\n  \"Perry\":\"New Lexington, Ohio\",\"Pickaway\":\"Circleville, Ohio\",\"Pike\":\"Waverly, Ohio\",\n  \"Portage\":\"Ravenna, Ohio\",\"Preble\":\"Eaton, Ohio\",\"Putnam\":\"Ottawa, Ohio\",\n  \"Richland\":\"Mansfield, Ohio\",\"Ross\":\"Chillicothe, Ohio\",\"Sandusky\":\"Fremont, Ohio\",\n  \"Scioto\":\"Portsmouth, Ohio\",\"Seneca\":\"Tiffin, Ohio\",\"Shelby\":\"Sidney, Ohio\",\n  \"Stark\":\"Canton, Ohio\",\"Summit\":\"Akron, Ohio\",\"Trumbull\":\"Warren, Ohio\",\n  \"Tuscarawas\":\"New Philadelphia, Ohio\",\"Union\":\"Marysville, Ohio\",\"Van Wert\":\"Van Wert, Ohio\",\n  \"Vinton\":\"McArthur, Ohio\",\"Warren\":\"Lebanon, Ohio\",\"Washington\":\"Marietta, Ohio\",\n  \"Wayne\":\"Wooster, Ohio\",\"Williams\":\"Bryan, Ohio\",\"Wood\":\"Bowling Green, Ohio\",\n  \"Wyandot\":\"Upper Sandusky, Ohio\"\n};\n\nconst COUNTIES = [\n  {n:\"Williams\",c:0,r:0},{n:\"Fulton\",c:1,r:0},{n:\"Lucas\",c:2,r:0},\n  {n:\"Ottawa\",c:3,r:0},{n:\"Erie\",c:4,r:0},{n:\"Lorain\",c:5,r:0},\n  {n:\"Cuyahoga\",c:6,r:0},{n:\"Lake\",c:7,r:0},{n:\"Geauga\",c:8,r:0},\n  {n:\"Ashtabula\",c:9,r:0},\n  {n:\"Defiance\",c:0,r:1},{n:\"Henry\",c:1,r:1},{n:\"Wood\",c:2,r:1},\n  {n:\"Sandusky\",c:3,r:1},{n:\"Huron\",c:4,r:1},{n:\"Medina\",c:5,r:1},\n  {n:\"Summit\",c:6,r:1},{n:\"Portage\",c:7,r:1},{n:\"Trumbull\",c:8,r:1},\n  {n:\"Paulding\",c:0,r:2},{n:\"Putnam\",c:1,r:2},{n:\"Hancock\",c:2,r:2},\n  {n:\"Seneca\",c:3,r:2},{n:\"Richland\",c:4,r:2},{n:\"Wayne\",c:5,r:2},\n  {n:\"Stark\",c:6,r:2},{n:\"Mahoning\",c:7,r:2},{n:\"Columbiana\",c:8,r:2},\n  {n:\"Van Wert\",c:0,r:3},{n:\"Allen\",c:1,r:3},{n:\"Wyandot\",c:2,r:3},\n  {n:\"Crawford\",c:3,r:3},{n:\"Ashland\",c:4,r:3},{n:\"Holmes\",c:5,r:3},\n  {n:\"Tuscarawas\",c:6,r:3},{n:\"Carroll\",c:7,r:3},{n:\"Jefferson\",c:8,r:3},\n  {n:\"Mercer\",c:0,r:4},{n:\"Auglaize\",c:1,r:4},{n:\"Hardin\",c:2,r:4},\n  {n:\"Marion\",c:3,r:4},{n:\"Morrow\",c:4,r:4},{n:\"Knox\",c:5,r:4},\n  {n:\"Coshocton\",c:6,r:4},{n:\"Harrison\",c:7,r:4},{n:\"Guernsey\",c:8,r:4},\n  {n:\"Belmont\",c:9,r:4},\n  {n:\"Darke\",c:0,r:5},{n:\"Shelby\",c:1,r:5},{n:\"Logan\",c:2,r:5},\n  {n:\"Union\",c:3,r:5},{n:\"Delaware\",c:4,r:5},{n:\"Licking\",c:5,r:5},\n  {n:\"Muskingum\",c:6,r:5},{n:\"Morgan\",c:7,r:5},{n:\"Noble\",c:8,r:5},\n  {n:\"Monroe\",c:9,r:5},\n  {n:\"Miami\",c:1,r:6},{n:\"Champaign\",c:2,r:6},{n:\"Madison\",c:3,r:6},\n  {n:\"Franklin\",c:4,r:6},{n:\"Fairfield\",c:5,r:6},{n:\"Perry\",c:6,r:6},\n  {n:\"Washington\",c:7,r:6},\n  {n:\"Preble\",c:0,r:7},{n:\"Montgomery\",c:1,r:7},{n:\"Clark\",c:2,r:7},\n  {n:\"Greene\",c:3,r:7},{n:\"Pickaway\",c:4,r:7},{n:\"Hocking\",c:5,r:7},\n  {n:\"Vinton\",c:6,r:7},{n:\"Athens\",c:7,r:7},{n:\"Meigs\",c:8,r:7},\n  {n:\"Butler\",c:0,r:8},{n:\"Warren\",c:1,r:8},{n:\"Clinton\",c:2,r:8},\n  {n:\"Fayette\",c:3,r:8},{n:\"Ross\",c:4,r:8},{n:\"Pike\",c:5,r:8},\n  {n:\"Jackson\",c:6,r:8},{n:\"Gallia\",c:7,r:8},{n:\"Lawrence\",c:8,r:8},\n  {n:\"Hamilton\",c:0,r:9},{n:\"Clermont\",c:1,r:9},{n:\"Brown\",c:2,r:9},\n  {n:\"Highland\",c:3,r:9},{n:\"Scioto\",c:4,r:9},{n:\"Adams\",c:5,r:9},\n];\n\nconst TMPLS = [\n  (name, title) => `Dear ${title} ${name},\n\nMy name is [Your Name], and I am an educator in [City\/Town], Ohio. I am a member of Ohio TESOL \u2014 the state affiliate of TESOL International \u2014 which represents educators who work alongside Ohio's multilingual learners and their families every day.\n\nI am writing to ask for your leadership on behalf of these students. Ohio's multilingual learner population continues to grow. These are children, young adults, and newcomers who bring remarkable linguistic and cultural assets to our schools and communities. They need \u2014 and deserve \u2014 educators who are prepared, resourced, and supported by sound policy.\n\nI respectfully urge you to:\n\n  \u2022 Advocate for sustained, equitable funding for English language development programs in Ohio's K\u201312 districts, especially in rural communities where programs are most at risk.\n  \u2022 Support pathways for multilingual learner families to access information about their children's education in their home language.\n  \u2022 Protect and expand access to bilingual and dual-language programs, which research consistently shows accelerates academic achievement.\n  \u2022 Ensure TESOL-certified educators are recognized, fairly compensated, and present in every Ohio district that serves multilingual learners.\n\nOur multilingual learners are not a problem to be solved. They are Ohio's future \u2014 and they are counting on policymakers who see their potential, not just their challenges.\n\nI would welcome the opportunity to meet with you or a member of your staff. Thank you for your service and your attention to this important matter.\n\nRespectfully,\n\n[Your Name]\n[Your Title \/ School \/ Organization]\n[City, Ohio  ZIP]\n[Email \/ Phone]`,\n\n  (name, title) => `Dear ${title} ${name},\n\nMy name is [Your Name], and I am a TESOL educator in [City\/Town], Ohio, and a member of Ohio TESOL. I am writing with a specific request: please support robust, equitable funding for English language development programs across our state.\n\nOhio currently serves a growing population of multilingual learners across K\u201312 districts. These students face the extraordinary challenge of mastering academic content while simultaneously developing English proficiency \u2014 often in under-resourced schools that lack adequate staffing, materials, or instructional time.\n\nUnderfunding ELD programs has real consequences: students fall behind academically, families feel excluded from school communities, and dedicated teachers burn out. Well-funded, high-quality programming works \u2014 districts that invest in their multilingual learners see measurable gains in graduation rates, college attendance, and civic participation.\n\nI ask that you:\n\n  \u2022 Ensure Ohio's ELD funding formula reflects actual student need and the true cost of quality instruction.\n  \u2022 Oppose any budget cuts that would reduce services for multilingual learners.\n  \u2022 Support monitoring and accountability measures to ensure funds reach the classrooms and students who need them most.\n\nI am glad to share specific data from my school or district, or to connect you with Ohio TESOL leadership. Thank you for your consideration.\n\nRespectfully,\n\n[Your Name]\n[Your Title \/ School \/ Organization]\n[City, Ohio  ZIP]\n[Email \/ Phone]`,\n\n  (name, title) => `Dear ${title} ${name},\n\nMy name is [Your Name], and I teach in [City\/Town], Ohio. I am writing as a member of Ohio TESOL to ask for your support for TESOL educators across our state.\n\nTeaching English to multilingual learners requires specialized preparation, sustained professional development, and working conditions that allow educators to do their best work. Right now, many of Ohio's TESOL educators work in districts where positions are underfunded, certification pathways are unclear, and professional growth opportunities are inconsistent.\n\nI ask you to support policies that:\n\n  \u2022 Strengthen and clarify TESOL certification requirements and career pathways across Ohio.\n  \u2022 Provide funding for professional development specifically for educators of multilingual learners.\n  \u2022 Recognize and fairly compensate TESOL educators for the specialized expertise and bilingual skills they bring to Ohio schools.\n  \u2022 Expand teacher pipeline programs that recruit and prepare educators from multilingual communities.\n\nWhen teachers are supported, students thrive. Ohio's multilingual learners deserve nothing less \u2014 and neither do the educators who serve them.\n\nThank you for your time. I welcome any opportunity to speak further about the needs of educators in our field.\n\nRespectfully,\n\n[Your Name]\n[Your Title \/ School \/ Organization]\n[City, Ohio  ZIP]\n[Email \/ Phone]`,\n\n  (name, title) => `Dear ${title} ${name},\n\nMy name is [Your Name], and I am an educator in [City\/Town], Ohio. I am a member of Ohio TESOL \u2014 the state affiliate of TESOL International \u2014 and I am writing to urge your support for federal policies and funding that protect and advance the education of multilingual learners.\n\nFederal law \u2014 particularly Title III of the Every Student Succeeds Act (ESSA) \u2014 plays a critical role in ensuring that English learners across Ohio and the nation receive the instruction and support they need. Yet Title III remains chronically underfunded relative to the scale of the need, and recent proposals to reduce federal education investment would fall hardest on the most vulnerable students in our schools.\n\nI ask that you:\n\n  \u2022 Oppose any cuts to Title III of ESSA, which funds English language acquisition programs serving millions of students nationwide.\n  \u2022 Support full, sustained funding for ESSA Title I and Title III programs, and resist efforts to consolidate or block-grant these funds in ways that reduce transparency and accountability.\n  \u2022 Champion the rights of multilingual learner families to receive meaningful communication from schools in their home language, as required under federal civil rights law.\n  \u2022 Protect the due process rights of immigrant students and families, ensuring that schools remain safe and welcoming environments regardless of immigration status.\n  \u2022 Support federal investment in the preparation and retention of TESOL-qualified educators, particularly in high-need districts.\n\nThe multilingual learners in my classroom are constituents too. Their futures depend on federal leadership that matches the rhetoric of equity with the reality of resources.\n\nI would welcome the opportunity to speak with you or your education policy staff. Thank you for your attention to this urgent matter.\n\nRespectfully,\n\n[Your Name]\n[Your Title \/ School \/ Organization]\n[City, Ohio  ZIP]\n[Email \/ Phone]`,\n];\n\nlet activeTmpl = 0, activeRecip = null, allRecips = [];\nlet selectedCounty = null;\n\n\/\/ ================================================================\n\/\/ FEDERAL DETECTION \u2014 multi-layered for robustness\n\/\/ ================================================================\nfunction isFederal(leg) {\n  const j    = leg.jurisdiction || {};\n  const name = (j.name || '').toLowerCase();\n  const id   = (j.id   || '').toLowerCase();\n  const classification = (j.classification || '').toLowerCase();\n  const roleTitle = (leg.current_role?.title || '').toLowerCase();\n\n  if (name === 'united states' || name === 'us' || name === 'u.s.') return true;\n  if (name.includes('congress')) return true;\n  if (name.includes('united states')) return true;\n  if (id.includes('country:us') && !id.includes('\/state:')) return true;\n  if (roleTitle.includes('u.s.') || roleTitle.includes('united states')) return true;\n  if (classification === 'country') return true;\n  return false;\n}\n\n\/\/ ================================================================\n\/\/ INIT\n\/\/ ================================================================\nfunction init() {\n  const grid = document.getElementById('cg');\n  const sel  = document.getElementById('csel');\n  [...COUNTIES].sort((a,b) => a.n.localeCompare(b.n)).forEach(c => {\n    const o = document.createElement('option');\n    o.value = c.n; o.textContent = c.n + ' County';\n    sel.appendChild(o);\n  });\n  COUNTIES.forEach(c => {\n    const t = document.createElement('button');\n    t.className = 'ct'; t.textContent = c.n;\n    t.dataset.county = c.n;\n    t.setAttribute('aria-label', c.n + ' County');\n    t.style.gridColumn = c.c + 1;\n    t.style.gridRow    = c.r + 1;\n    \/\/ Region color-coding by latitude band\n    if      (c.r <= 2) t.classList.add('reg-n');\n    else if (c.r <= 6) t.classList.add('reg-c');\n    else               t.classList.add('reg-s');\n    t.onclick = () => selectCountyTile(c.n);\n    grid.appendChild(t);\n  });\n}\n\nfunction selectCountyTile(name) {\n  selectedCounty = name;\n  document.querySelectorAll('.ct').forEach(t =>\n    t.classList.toggle('sel', t.dataset.county === name));\n  document.getElementById('csel').value = name;\n}\n\nfunction onDropdown(val) { if (val) selectCountyTile(val); }\nfunction scrollUp() { document.querySelector('.band').scrollIntoView({behavior:'smooth',block:'start'}); }\n\n\/\/ ================================================================\n\/\/ GEOCODING \u2014 Nominatim\n\/\/ ================================================================\nasync function geocode(query) {\n  const url = 'https:\/\/nominatim.openstreetmap.org\/search?' +\n    new URLSearchParams({q:query, format:'json', addressdetails:'1', countrycodes:'us', limit:'1'});\n  const r = await fetch(url, {headers:{'Accept':'application\/json'}});\n  if (!r.ok) throw new Error('geocode_fail');\n  const data = await r.json();\n  if (!data.length) throw new Error('not_found');\n  const state = data[0].address?.state || '';\n  if (state && !state.toLowerCase().includes('ohio')) throw new Error('not_ohio');\n  return {lat: parseFloat(data[0].lat), lng: parseFloat(data[0].lon)};\n}\n\n\/\/ ================================================================\n\/\/ OPENSTATES LOOKUP \u2014 with debug logging\n\/\/ ================================================================\nasync function fetchLegislators(lat, lng) {\n  const url = `https:\/\/v3.openstates.org\/people.geo?lat=${lat}&lng=${lng}&apikey=${OPENSTATES_KEY}`;\n  const r = await fetch(url, {headers:{'Accept':'application\/json'}});\n  if (!r.ok) throw new Error('openstates_fail');\n  const data = await r.json();\n  return (data.results || []).filter(p => {\n    const org = p.current_role?.org_classification;\n    return org === 'upper' || org === 'lower';\n  });\n}\n\n\/\/ ================================================================\n\/\/ ADDRESS LOOKUP\n\/\/ ================================================================\nasync function geoLookup() {\n  const addr = document.getElementById('addrIn').value.trim();\n  const zip  = document.getElementById('zipIn').value.trim();\n  const stat = document.getElementById('geoStatus');\n  const btn  = document.getElementById('geoBtn');\n\n  if (!addr && !zip) {\n    setStatus(stat, 'error', 'Please enter a street address or ZIP code.');\n    return;\n  }\n\n  const q = addr && zip ? `${addr}, ${zip}, Ohio`\n          : addr        ? `${addr}, Ohio`\n          :               `${zip}, Ohio`;\n\n  setStatus(stat, 'loading', 'Locating your address\u2026');\n  btn.disabled = true;\n\n  try {\n    const {lat, lng} = await geocode(q);\n    setStatus(stat, 'loading', 'Finding your legislators\u2026');\n    const legs = await fetchLegislators(lat, lng);\n    if (!legs.length) throw new Error('no_results');\n    showResults(legs, `Results for: ${q}`);\n    const fed = legs.filter(isFederal).length;\n    const st  = legs.filter(l => !isFederal(l)).length;\n    setStatus(stat, 'success', `\u2713 Found ${fed} federal and ${st} state legislator${st!==1?'s':''} for your address.`);\n  } catch(e) {\n    const msgs = {\n      not_found: 'Address not found. Try adding your city or ZIP, or select your county below.',\n      not_ohio:  'That address appears to be outside Ohio. Please check and try again.',\n      no_results:'No legislators found for that location. Try a more specific address.',\n    };\n    setStatus(stat, 'error', msgs[e.message] || 'Lookup failed. Check your connection and try again, or select your county below.');\n  } finally {\n    btn.disabled = false;\n  }\n}\n\n\/\/ ================================================================\n\/\/ COUNTY LOOKUP\n\/\/ ================================================================\nasync function countyLookup() {\n  if (!selectedCounty) { alert('Please select a county first.'); return; }\n  const seat = COUNTY_SEATS[selectedCounty];\n  const stat = document.getElementById('geoStatus');\n  setStatus(stat, 'loading', `Looking up legislators for ${selectedCounty} County\u2026`);\n  try {\n    const {lat, lng} = await geocode(seat);\n    const legs = await fetchLegislators(lat, lng);\n    if (!legs.length) throw new Error('no_results');\n    showResults(legs, `${selectedCounty} County (via county seat: ${seat.split(',')[0]})`);\n    setStatus(stat, 'success', '');\n  } catch(e) {\n    setStatus(stat, 'error', 'Could not retrieve legislators. Try the address lookup above for a more precise result.');\n  }\n}\n\nfunction setStatus(el, type, msg) {\n  el.innerHTML = '';\n  el.style.color = type === 'error' ? 'var(--coral)' : type === 'success' ? '#2a7a3b' : 'var(--muted)';\n  if (type === 'loading') el.innerHTML = `<span class=\"spin\"><\/span>${msg}`;\n  else el.textContent = msg;\n}\n\n\/\/ ================================================================\n\/\/ DISPLAY RESULTS\n\/\/ ================================================================\nfunction showResults(legs, subtitle) {\n  document.getElementById('rh').textContent = 'Your Federal & State Legislators';\n  document.getElementById('rp').textContent = subtitle;\n\n  const fedLegs   = legs.filter(isFederal);\n  const stateLegs = legs.filter(l => !isFederal(l));\n\n  \/\/ Federal cards\n  const fedSec = document.getElementById('fedSection');\n  const fedCards = document.getElementById('fedCards');\n  fedCards.innerHTML = '';\n  if (fedLegs.length) {\n    fedLegs.forEach(l => fedCards.appendChild(buildCard(l, true)));\n    fedSec.style.display = 'block';\n  } else {\n    fedSec.style.display = 'none';\n  }\n\n  \/\/ State cards\n  const stateSec = document.getElementById('stateSection');\n  const stateCards = document.getElementById('stateCards');\n  stateCards.innerHTML = '';\n  if (stateLegs.length) {\n    stateLegs.forEach(l => stateCards.appendChild(buildCard(l, false)));\n    stateSec.style.display = 'block';\n  } else {\n    stateSec.style.display = 'none';\n  }\n\n  \/\/ Recipient buttons \u2014 built from separated arrays with explicit federal flag\n  allRecips = [];\n  const toRow = document.getElementById('toRow');\n  toRow.innerHTML = '';\n\n  function addRecipBtn(leg, federal) {\n    const org   = leg.current_role?.org_classification;\n    const title = federal\n      ? (org === 'upper' ? 'U.S. Senator' : 'U.S. Representative')\n      : (org === 'upper' ? 'Senator' : 'Representative');\n    const recip = {\n      name:        leg.name,\n      title,\n      email:       leg.email || findEmail(leg),\n      isFederal:   federal,\n      contactForm: findContactForm(leg) || (federal ? findWebsite(leg) : null),\n      label:       `${title} ${leg.name}`\n    };\n    allRecips.push(recip);\n    const b = mkTbn(recip.label, false, () => {\n      toRow.querySelectorAll('.tbn').forEach(x => x.classList.remove('on'));\n      b.classList.add('on');\n      activeRecip = recip;\n      refreshTemplate();\n      refreshEmailBtn();\n    });\n    toRow.appendChild(b);\n    return b;\n  }\n\n  fedLegs.forEach(leg   => addRecipBtn(leg, true));\n  stateLegs.forEach(leg => addRecipBtn(leg, false));\n\n  if (allRecips.length > 1) {\n    const allEmails = allRecips.filter(r => r.email).map(r => r.email).join(',');\n    const allRecip  = { name:'your legislators', title:'', email:allEmails, isFederal:false, contactForm:null, label:'All legislators' };\n    const allBtn = mkTbn('All legislators', false, () => {\n      toRow.querySelectorAll('.tbn').forEach(x => x.classList.remove('on'));\n      allBtn.classList.add('on');\n      activeRecip = allRecip;\n      refreshTemplate();\n      refreshEmailBtn();\n    });\n    toRow.appendChild(allBtn);\n  }\n\n  \/\/ Activate first recipient\n  const firstBtn = toRow.querySelector('.tbn');\n  if (firstBtn) firstBtn.classList.add('on');\n  activeRecip = allRecips[0] || null;\n\n  document.querySelectorAll('.tmpl-btn').forEach((b,i) => b.classList.toggle('on', i===0));\n  activeTmpl = 0;\n  refreshTemplate();\n  refreshEmailBtn();\n\n  document.getElementById('res').style.display = 'block';\n  document.getElementById('res').scrollIntoView({behavior:'smooth', block:'start'});\n}\n\nfunction buildCard(leg, federal) {\n  const org = leg.current_role?.org_classification;\n  const isSenate = org === 'upper';\n\n  let cardClass, chamberLabel;\n  if (federal) {\n    cardClass    = 'federal';\n    chamberLabel = isSenate ? 'U.S. Senate' : 'U.S. House of Representatives';\n  } else {\n    cardClass    = isSenate ? 'state-senate' : 'state-house';\n    chamberLabel = isSenate ? 'Ohio State Senate' : 'Ohio House of Representatives';\n  }\n\n  const district    = leg.current_role?.district || null;\n  const party       = leg.party || 'Unknown';\n  const email       = leg.email || findEmail(leg);\n  const website     = findWebsite(leg);\n  const contactForm = findContactForm(leg);\n\n  let emailRow, webRow;\n  if (federal) {\n    emailRow = (contactForm || website)\n      ? `<a href=\"${contactForm || website}\" target=\"_blank\" rel=\"noopener\" style=\"color:var(--federal)\">\n           ${formSvg()} Web Contact Form (opens in browser)\n         <\/a>\n         <span style=\"font-size:11px;color:var(--slate);margin-top:2px\">\n           U.S. legislators use contact forms, not direct email.\n         <\/span>`\n      : `<span class=\"no-email\">${mailSvg()} Contact via official website<\/span>`;\n    webRow = website && website !== contactForm\n      ? `<a href=\"${website}\" target=\"_blank\" rel=\"noopener\">${extSvg()} Official legislative page<\/a>`\n      : '';\n  } else {\n    emailRow = email\n      ? `<a href=\"mailto:${email}\">${mailSvg()} ${email}<\/a>`\n      : `<span class=\"no-email\">${mailSvg()} No direct email \u2014 use official page<\/span>`;\n    webRow = website\n      ? `<a href=\"${website}\" target=\"_blank\" rel=\"noopener\">${extSvg()} Official legislative page<\/a>`\n      : '';\n  }\n\n  const d = document.createElement('div');\n  d.className = `card ${cardClass}`;\n  d.innerHTML =\n    `<div class=\"c-chamber\">${chamberLabel}<\/div>\n     <div class=\"c-name\">${leg.name}<\/div>\n     <div class=\"c-meta\">${district ? `District ${district}` : 'Statewide'}<\/div>\n     <span class=\"c-party ${partyClass(party)}\">${partyLabel(party)}<\/span>\n     <div class=\"c-links\">${emailRow}${webRow}<\/div>`;\n  return d;\n}\n\nfunction mailSvg() {\n  return `<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" aria-hidden=\"true\" style=\"flex-shrink:0\"><rect x=\"2\" y=\"4\" width=\"20\" height=\"16\" rx=\"2\"\/><path d=\"m2 7 10 7 10-7\"\/><\/svg>`;\n}\nfunction extSvg() {\n  return `<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" aria-hidden=\"true\" style=\"flex-shrink:0\"><path d=\"M18 13v6a2 2 0 01-2 2H5a2 2 0 01-2-2V8a2 2 0 012-2h6\"\/><polyline points=\"15 3 21 3 21 9\"\/><line x1=\"10\" y1=\"14\" x2=\"21\" y2=\"3\"\/><\/svg>`;\n}\nfunction formSvg() {\n  return `<svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" aria-hidden=\"true\" style=\"flex-shrink:0\"><rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\"\/><path d=\"M7 8h10M7 12h6M7 16h4\"\/><\/svg>`;\n}\nfunction findEmail(leg) {\n  return leg.offices?.find(o => o.email)?.email || null;\n}\nfunction findContactForm(leg) {\n  if (!leg.links?.length) return null;\n  const cf = leg.links.find(l =>\n    l.note?.toLowerCase().includes('contact') ||\n    l.url?.toLowerCase().includes('contact')\n  );\n  return cf ? cf.url : null;\n}\nfunction findWebsite(leg) {\n  if (!leg.links?.length) return null;\n  return (leg.links.find(l => l.note?.toLowerCase().includes('official')) || leg.links[0]).url;\n}\nfunction partyClass(p) {\n  if (!p) return 'party-I';\n  const lp = p.toLowerCase();\n  return lp.includes('democrat') ? 'party-D' : lp.includes('republican') ? 'party-R' : 'party-I';\n}\nfunction partyLabel(p) {\n  if (!p) return 'Unknown';\n  const lp = p.toLowerCase();\n  return lp.includes('democrat') ? 'Democrat' : lp.includes('republican') ? 'Republican' : p;\n}\n\nfunction mkTbn(label, active, fn) {\n  const b = document.createElement('button');\n  b.className = 'tbn' + (active ? ' on' : '');\n  b.textContent = label;\n  b.onclick = fn;\n  return b;\n}\n\n\/\/ ================================================================\n\/\/ EMAIL BUTTON \u2014 switches between mailto and contact form\n\/\/ ================================================================\nfunction openEmail() {\n  if (activeRecip?.isFederal) {\n    const url = activeRecip.contactForm;\n    if (url) window.open(url, '_blank', 'noopener');\n    else alert('No contact form found \u2014 please visit their official page above.');\n    return;\n  }\n  const to   = activeRecip?.email || '';\n  const sub  = encodeURIComponent(document.getElementById('esub').value);\n  const body = encodeURIComponent(document.getElementById('ebody').value);\n  window.open(`mailto:${to}?subject=${sub}&body=${body}`, '_self');\n}\n\nfunction emailBtnLabel() {\n  return activeRecip?.isFederal ? 'Open Contact Form' : 'Open in Email Client';\n}\n\nfunction refreshEmailBtn() {\n  const btn = document.getElementById('emailBtn');\n  if (btn) btn.textContent = emailBtnLabel();\n}\n\nfunction refreshTemplate() {\n  const name  = activeRecip?.name  || 'My Legislator';\n  const title = activeRecip?.title || '';\n  document.getElementById('ebody').value = TMPLS[activeTmpl](name, title);\n}\n\nfunction setTmpl(idx, btn) {\n  activeTmpl = idx;\n  document.querySelectorAll('.tmpl-btn').forEach(b => b.classList.remove('on'));\n  if (btn) btn.classList.add('on');\n  refreshTemplate();\n}\n\nfunction resetTmpl() {\n  setTmpl(activeTmpl, document.querySelectorAll('.tmpl-btn')[activeTmpl]);\n}\n\nfunction copyMsg(evt) {\n  const txt = document.getElementById('ebody').value;\n  const btn = evt.currentTarget;\n  if (navigator.clipboard) navigator.clipboard.writeText(txt).then(() => flash(btn));\n  else { document.getElementById('ebody').select(); document.execCommand('copy'); flash(btn); }\n}\n\nfunction flash(btn) {\n  const orig = btn.textContent;\n  btn.textContent = '\u2713 Copied!';\n  setTimeout(() => btn.textContent = orig, 2200);\n}\n\ninit();\n<\/script>\n<\/body>\n<\/html>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Find Your Legislators \u2014 Ohio TESOL Advocacy Ohio TESOL \u00b7 Advocacy Find Your Legislators Enter your address to find your federal and state legislators \u2014 then send them a message in support of multilingual learners. Look Up by Address or ZIP Code &#8230;.&nbsp;&nbsp;<a class=\" default\" href=\"https:\/\/ohiotesol.org\/web\/advocacy-find-your-legislators-tool\/\">Read More<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_bbp_topic_count":0,"_bbp_reply_count":0,"_bbp_total_topic_count":0,"_bbp_total_reply_count":0,"_bbp_voice_count":0,"_bbp_anonymous_reply_count":0,"_bbp_topic_count_hidden":0,"_bbp_reply_count_hidden":0,"_bbp_forum_subforum_count":0,"pagelayer_contact_templates":[],"_pagelayer_content":"","footnotes":""},"class_list":["post-41511","page","type-page","status-publish","hentry"],"aioseo_notices":[],"jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/ohiotesol.org\/web\/wp-json\/wp\/v2\/pages\/41511","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ohiotesol.org\/web\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/ohiotesol.org\/web\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/ohiotesol.org\/web\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/ohiotesol.org\/web\/wp-json\/wp\/v2\/comments?post=41511"}],"version-history":[{"count":1,"href":"https:\/\/ohiotesol.org\/web\/wp-json\/wp\/v2\/pages\/41511\/revisions"}],"predecessor-version":[{"id":41512,"href":"https:\/\/ohiotesol.org\/web\/wp-json\/wp\/v2\/pages\/41511\/revisions\/41512"}],"wp:attachment":[{"href":"https:\/\/ohiotesol.org\/web\/wp-json\/wp\/v2\/media?parent=41511"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}