PageSourceSearch

https://weapons.com/

html weapons.com collected 2026-10-04 06:30:22 UTC 58,955 bytes, 750 lines download raw bytes

1<!DOCTYPE html>
2<html lang="en">
3<head>
4<meta charset="utf-8">
5<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
6<title>Weapons.com — Training, certification and careers</title>
7<meta name="description" content="The national directory for firearms training, carry permits, professional certifications and industry careers, organized by state.">
8<link rel="canonical" href="https://weapons.com/">
9<script type="application/ld+json">
10{
11  "@context": "https://schema.org",
12  "@graph": [
13    {
14      "@type": "WebSite",
15      "@id": "https://weapons.com/#website",
16      "name": "Weapons.com",
17      "url": "https://weapons.com/",
18      "description": "The national directory for firearms training, carry permits, professional certifications and industry careers, organized by state. Listings are launching state by state.",
19      "publisher": {
20        "@id": "https://weapons.com/#organization"
21      }
22    },
23    {
24      "@type": "Organization",
25      "@id": "https://weapons.com/#organization",
26      "name": "Weapons.com",
27      "url": "https://weapons.com/",
28      "description": "Weapons.com provides educational information and a directory of third-party providers.",
29      "logo": "https://weapons.com/weapons-brand-logo.png",
30      "sameAs": [
31        "https://x.com/weapons_com",
32        "https://www.instagram.com/weapons_com/"
33      ]
34    }
35  ]
36}
37</script>
37
38<meta property="og:type" content="website">
39<meta property="og:site_name" content="Weapons.com">
40<meta property="og:locale" content="en_US">
41<meta property="og:url" content="https://weapons.com/">
42<meta property="og:title" content="Weapons.com — Trained. Licensed. Hired.">
43<meta property="og:description" content="Explore firearms training, carry permits, certifications and careers by state. Listings are launching state by state.">
44<meta property="og:image" content="https://weapons.com/social-preview-brand.png">
45<meta property="og:image:secure_url" content="https://weapons.com/social-preview-brand.png">
46<meta property="og:image:type" content="image/png">
47<meta property="og:image:width" content="1200">
48<meta property="og:image:height" content="630">
49<meta property="og:image:alt" content="Weapons.com — Trained. Licensed. Hired. Launching state by state.">
50<meta name="twitter:card" content="summary_large_image">
51<meta name="twitter:title" content="Weapons.com — Trained. Licensed. Hired.">
52<meta name="twitter:description" content="Explore firearms training, carry permits, certifications and careers by state. Listings are launching state by state.">
53<meta name="twitter:image" content="https://weapons.com/social-preview-brand.png">
54<meta name="twitter:image:alt" content="Weapons.com — Trained. Licensed. Hired. Launching state by state.">
55<link rel="icon" type="image/png" sizes="192x192" href="/weapons-brand-icon.png">
56<link rel="shortcut icon" href="/favicon.ico">
57<link rel="apple-touch-icon" href="/weapons-brand-icon.png">
58<link rel="preconnect" href="https://fonts.googleapis.com">
59<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
60<link href="https://fonts.googleapis.com/css2?family=Barlow+Condensed:wght@500;600;700;800&family=Barlow:wght@400;500;600&display=swap" rel="stylesheet">
61<style>
62:root{
63  --steel:#1A232A; --steel-2:#232F37; --steel-3:#2E3C45;
64  --fog:#EDEFEC;
64 --panel:#FFFFFF; --ink:#1A232A; --muted:#5A6770; --line:#CDD3CF;
65  --brass:#C8973A; --brass-hi:#E2B764; --brass-ink:#7A5716; --olive:#55653E; --olive-soft:#E2E7D8;
66  --on-dark:#E9ECE8; --on-dark-muted:#A7B2B8; --focus:#3D7FC2; --error:#B3261E;
67  --display:"Barlow Condensed","Arial Narrow",Arial,sans-serif;
68  --body:"Barlow","Helvetica Neue",Arial,sans-serif;
69  box-sizing:border-box;
70  padding-top:env(safe-area-inset-top,0px);
71  padding-bottom:env(safe-area-inset-bottom,0px);
72}
73@media (prefers-color-scheme:dark){
74  :root:not([data-theme="light"]){
75    --fog:#12191E; --panel:#1C262D; --ink:#E6EAE6; --muted:#9AA6AD; --line:#33424B;
76    --brass-ink:#E2B764; --olive:#A6B887; --olive-soft:#26301F; --focus:#7DB1E8; --error:#FFB4AB;
77  }
78}
79:root[data-theme="dark"]{
80  --fog:#12191E; --panel:#1C262D; --ink:#E6EAE6; --muted:#9AA6AD; --line:#33424B;
81  --brass-ink:#E2B764; --olive:#A6B887; --olive-soft:#26301F; --focus:#7DB1E8; --error:#FFB4AB;
82}
83*,*::before,*::after{box-sizing:inherit}
84html{scroll-padding-top:calc(104px + env(safe-area-inset-top,0px));-webkit-text-size-adjust:100%}
85body{margin:0;background:var(--fog);color:var(--ink);font:400 17px/1.55 var(--body)}
86img,svg{max-width:100%}
87a{color:inherit}
88:focus-visible{outline:3px solid var(--focus);outline-offset:2px}
89.wrap{max-width:1180px;margin:0 auto;padding:0 22px}
90.sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0)}
91.bar{position:absolute;top:env(safe-area-inset-top,0px);left:0;right:0;z-index:5}
92.bar .wrap{display:flex;align-items:center;justify-content:space-between;gap:16px;height:104px}
93.logo{display:block;flex:none;text-decoration:none}
94.logo img{display:block;width:280px;height:auto}
95.bar nav a{font-weight:500;text-decoration:none;margin-left:26px;color:var(--on-dark-muted)}
96.bar nav a:hover{color:var(--on-dark)}
97.bar nav a.cta{white-space:nowrap;color:var(--steel);background:var(--brass-hi);padding:9px 16px;border-radius:3px;font-weight:600}
98.bar nav a.cta .sm{display:none}
99@media (max-width:760px){.bar .wrap{height:88px;gap:12px}.bar .logo img{width:clamp(170px,54vw,220px)}.bar nav a:not(.cta){display:none}.bar nav a.cta{font-size:14px;padding:8px 12px;margin-left:0}.bar nav a.cta .lg{display:none}.bar nav a.cta .sm{display:inline}}
100.hero{position:relative;background:var(--steel);color:var(--on-dark);overflow:hidden;isolation:isolate}
101.hero .photo{position:absolute;inset:0;z-index:-2;background:
102 radial-gradient(ellipse at 88% 38%,rgba(200,151,58,.20),transparent 37%),
103 repeating-linear-gradient(145deg,transparent 0 65px,rgba(226,183,100,.025) 66px 67px),
104 linear-gradient(135deg,#25343d 0%,#1a232a 48%,#10181e 100%)}
105.hero .shade{position:absolute;inset:0;z-index:-1;background:linear-gradient(100deg,rgba(26,35,42,.38),transparent 70%),linear-gradient(0deg,var(--steel),transparent 30%)}
106.hero .rings{position:absolute;z-index:-1;right:-180px;top:50%;width:900px;height:900px;transform:translateY(-50%);pointer-events:none}
107.hero .inner{display:grid;grid-template-columns:1.05fr .95fr;gap:48px;align-items:center;padding-top:144px;padding-bottom:80px}
108@media (max-width:980px){.hero .inner{grid-template-columns:1fr;padding-top:120px;padding-bottom:56px;gap:32px}.hero .rings{right:-420px}}
109.hero h1{font:800 clamp(52px,8.4vw,108px)/.88 var(--display);margin:0 0 22px;letter-spacing:-.01em;text-transform:uppercase}
110.hero h1 .line{display:block}
111.hero h1 .line:nth-child(2){color:transparent;-webkit-text-stroke:2px var(--brass-hi)}
112.hero p.lede{font-size:19px;color:var(--on-dark-muted);max-width:46ch;margin:0 0 30px}
113.proof{display:flex;flex-wrap:wrap;gap:12px 28px;margin:0;padding:0;list-style:none}
114.proof li{display:flex;gap:10px;align-items:center;color:var(--on-dark);font-weight:500}
115.proof svg{width:20px;height:20px;flex:none;color:var(--brass-hi)}
116@media (prefers-reduced-motion:no-preference){.hero h1 .line{animation:slam .6s cubic-bezier(.2,.8,.2,1) both}
116.hero h1 .line:nth-child(2){animation-delay:.08s}.hero h1 .line:nth-child(3){animation-delay:.16s}.hero .rings circle{animation:draw 1.6s ease-out both}}
117@keyframes slam{from{opacity:0;transform:translateY(24px)}to{opacity:1;transform:none}}
118@keyframes draw{from{stroke-dashoffset:2400}to{stroke-dashoffset:0}}
119.intake{background:var(--panel);color:var(--ink);border-radius:6px;padding:26px;box-shadow:0 30px 60px -20px rgba(0,0,0,.55);border-top:4px solid var(--brass)}
120.progress{display:flex;gap:6px;margin-bottom:16px}
121.progress i{flex:1;height:4px;border-radius:2px;background:var(--line)}
122.progress i.on{background:var(--brass)}
123.qhead{font:700 28px/1.1 var(--display);margin:0 0 4px}
124.qsub{color:var(--muted);margin:0 0 16px;font-size:15px}
125.options{display:grid;grid-template-columns:1fr 1fr;gap:8px}
126@media (max-width:460px){.options{grid-template-columns:1fr}}
127.opt{all:unset;cursor:pointer;display:flex;gap:12px;align-items:flex-start;border:1.5px solid var(--line);border-radius:4px;padding:12px;background:var(--fog);transition:border-color .15s,transform .15s}
128.opt:hover{border-color:var(--brass);transform:translateY(-1px)}
129.opt:focus-visible{outline:3px solid var(--focus);outline-offset:2px}
130.opt svg{width:26px;height:26px;flex:none;color:var(--brass-ink);margin-top:2px}
131.opt b{display:block;font:600 19px/1.15 var(--display)}
132.opt small{display:block;color:var(--muted);font-size:13px;margin-top:2px;line-height:1.35}
133.chips{display:flex;flex-wrap:wrap;gap:8px}
134.chip{all:unset;cursor:pointer;border:1.5px solid var(--line);border-radius:999px;padding:8px 14px;font-weight:500;font-size:15px}
135.chip:hover{border-color:var(--brass)}
136.chip[aria-pressed="true"]{background:var(--ink);color:var(--panel);border-color:var(--ink)}
137.chip:focus-visible{outline:3px solid var(--focus);outline-offset:2px}
138.field{margin:0 0 16px}
139.field label{display:block;font-weight:600;margin-bottom:6px}
140select,input[type=email]{font:inherit;color:var(--ink);background:var(--fog);border:1.5px solid var(--line);border-radius:4px;padding:10px 12px;width:100%;max-width:340px}
141.actions{display:flex;gap:10px;align-items:center;margin-top:18px;flex-wrap:wrap}
142.btn{all:unset;cursor:pointer;font:700 19px/1 var(--display);letter-spacing:.02em;padding:14px 22px;border-radius:3px;background:var(--brass);color:#1B1406;text-transform:uppercase}
143.btn:hover{background:var(--brass-hi)}
144.btn:disabled{opacity:.4;cursor:not-allowed}
145.btn.ghost{background:transparent;color:var(--muted);padding:14px 6px;font:500 15px var(--body);text-transform:none}
146.btn:focus-visible{outline:3px solid var(--focus);outline-offset:2px}
147.result h3{font:700 20px/1.2 var(--display);margin:16px 0 6px;color:var(--brass-ink)}
148.result ul{margin:0;padding-left:18px}
149.result li{margin:3px 0}
150.note{font-size:14px;color:var(--muted)}
151.ok{color:var(--olive);font-weight:600}
152.err{color:var(--error);font-weight:600}
153.hp{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}
154@media (prefers-reduced-motion:no-preference){.step{animation:rise .25s ease-out}}
155@keyframes rise{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}
156.how{background:var(--steel-2);color:var(--on-dark)}
157.how ol{list-style:none;margin:0;padding:0;display:grid;grid-template-columns:repeat(3,1fr)}
158.how li{padding:26px 26px 26px 0;display:grid;grid-template-columns:auto 1fr;gap:16px;align-items:start;border-right:1px solid var(--steel-3)}
159.how li+li{padding-left:26px}.how li:last-child{border-right:0}
160@media (max-width:760px){.how ol{grid-template-columns:1fr}.how li,.how li+li{padding:18px 0;border-right:0;border-bottom:1px solid var(--steel-3)}}
161.how .num{font:800 46px/.8 var(--display);color:var(--brass-hi)}
162.how b{display:block;font:700 22px/1.1 var(--display);margin-bottom:4px}
163.how p{margin:0;color:var(--on-dark-muted);font-size:15px}
164section.block{padding:84px 0}
165.shead{display:flex;justify-content:space-between;align-items:end;gap:20px;flex-wrap:wrap;margin-bottom:30px}
166.shead h2{font:800 clamp(36px,5.4vw,60px)/.95 var(--display);margin:0;text-transform:uppercase}
167.shead p{margin:10px 0 0;color:var(--muted);max-width:52ch}
168.tiles{display:grid;grid-template-columns:repeat(4,1fr);gap:14px}
169.directory-category summary{box-sizing:border-box;min-height:100%;list-style:none}
170.directory-category[data-featured="true"]{grid-column:span 2}
171@media (max-width:520px){.directory-category[data-featured="true"]{grid-column:auto}}
172.directory-category summary::-webkit-details-marker{display:none}
173.directory-category[open] summary{min-height:0}
174.directory-category ul{padding-left:20px}
175.directory-category li{margin:8px 0}
176.st[href]{text-decoration:none}
177@media (max-width:980px){.tiles{grid-template-columns:repeat(2,1fr)}}
178@media (max-width:520px){.tiles{grid-template-columns:1fr}}
179.tile{all:unset;cursor:pointer;position:relative;background:var(--panel);border:1px solid var(--line);border-radius:6px;padding:22px 20px 20px;display:flex;flex-direction:column;gap:10px;min-height:190px;overflow:hidden;transition:border-color .15s,transform .15s}
180.tile:hover{border-color:var(--brass);transform:translateY(-2px)}
181.tile:focus-visible{outline:3px solid var(--focus);outline-offset:2px}
182.tile[aria-expanded="true"]{border-color:var(--brass);box-shadow:inset 0 -4px 0 var(--brass)}
183.tile svg.ic{width:40px;height:40px;color:var(--brass-ink)}
184.tile h3{font:700 25px/1.05 var(--display);margin:0}
185.tile p{margin:0;color:var(--muted);font-size:14.5px;line-height:1.45}
186.tile .count{margin-top:auto;font-size:13px;font-weight:600;color:var(--olive)}
187.tile.featured{grid-column:span 2;background:var(--steel);color:var(--on-dark);border-color:var(--steel)}
188.tile.featured p{color:var(--on-dark-muted)}
189.tile.featured svg.ic,.tile.featured .count{color:var(--brass-hi)}
190.tile.dark{grid-column:auto}
191.tile.featured .bg{position:absolute;right:-60px;bottom:-80px;width:280px;height:280px;opacity:.12;color:var(--brass-hi);pointer-events:none}
192@media (max-width:520px){.tile.featured{grid-column:auto}}
193.panel{grid-column:1/-1;background:var(--panel);border:1px solid var(--brass);border-radius:6px;padding:22px}
194.panel h4{font:700 24px/1.1 var(--display);margin:0 0 12px}
195.sub{display:grid;grid-template-columns:repeat(auto-fill,minmax(250px,1fr));gap:2px 28px}
196.sub a{display:flex;justify-content:space-between;gap:10px;padding:10px 0;border-bottom:1px dashed var(--line);text-decoration:none}
197.sub a:hover{color:var(--brass-ink)}
198.sub a em{font-style:normal;font-size:12.5px;color:var(--muted);white-space:nowrap}
199.mapwrap{display:grid;grid-template-columns:minmax(0,1.4fr) minmax(0,.6fr);gap:40px;align-items:center;min-width:0}
200@media (max-width:900px){.mapwrap{grid-template-columns:1fr}}
201.mapwrap>div{min-width:0}
202.map-scroller{width:100%;max-width:100%;overflow-x:auto;overscroll-behavior-inline:contain}
203.tilemap{display:grid;grid-template-columns:repeat(11,minmax(44px,1fr));gap:5px}
204.map-hint{display:none;color:var(--muted);font-size:13px;margin:8px 0 0}
205@media (max-width:900px){.tilemap{min-width:550px}.map-hint{display:block}.st{font-size:15px}}
206.st{all:unset;cursor:pointer;aspect-ratio:1;display:grid;place-items:center;font:700 clamp(11px,1.5vw,16px)/1 var(--display);background:var(--panel);border:1px solid var(--line);border-radius:3px;color:var(--muted);transition:background .12s,color .12s}
207.st:hover{background:var(--olive-soft);color:var(--ink);border-color:var(--olive)}
208.st:focus-visible{outline:3px solid var(--focus);outline-offset:1px}
209.st[aria-pressed="true"]{background:var(--brass);border-color:var(--brass);color:#1B1406}
210.stateinfo h3{font:800 44px/.95 var(--display);margin:0 0 10px;text-transform:uppercase}
211.stateinfo p{color:var(--muted);margin:0 0 18px}
212.stateinfo ul{list-style:none;padding:0;margin:0 0 22px}
213.stateinfo li{padding:9px 0;border-bottom:1px solid var(--line);display:flex;justify-content:space-between;gap:10px}
214.stateinfo li span{color:var(--muted);font-size:14px}
215.pro{background:var(--steel);color:var(--on-dark);position:relative;overflow:hidden;isolation:isolate}
216.pro .inner{display:grid;grid-template-columns:1fr 1fr;gap:40px;padding-top:84px;padding-bottom:84px;align-items:center}
217@media (max-width:860px){.pro .inner{grid-template-columns:1fr;padding-top:60px;padding-bottom:60px}}
218.pro h2{font:800 clamp(38px,5.4vw,62px)/.92 var(--display);margin:0 0 16px;text-transform:uppercase}
219.pro p{color:var(--on-dark-muted);max-width:46ch;margin:0 0 26px}
220.pro ul{list-style:none;padding:0;margin:0;display:grid;gap:12px}
221.pro li{background:var(--steel-2);border-left:3px solid var(--brass-hi);padding:16px 18px;border-radius:0 4px 4px 0}
222.pro li b{display:block;font:700 21px/1.1 var(--display);margin-bottom:2px}
223.pro li span{color:var(--on-dark-muted);font-size:15px}
224.pro .grid-bg{position:absolute;inset:0;z-index:-1;opacity:.07;background-image:linear-gradient(var(--on-dark) 1px,transparent 1px),linear-gradient(90deg,var(--on-dark) 1px,transparent 1px);background-size:44px 44px}
225footer{background:var(--steel);color:var(--on-dark-muted);border-top:1px solid var(--steel-3);padding:40px 0 48px;font-size:14px}
226footer .row{display:flex;justify-content:space-between;gap:24px;flex-wrap:wrap;margin-bottom:20px}
227footer .logo img{width:260px;max-width:100%}
228footer nav a{margin-right:20px;text-decoration:none}
229footer nav a:hover{color:var(--on-dark)}
230footer .social-links{display:flex;gap:10px;align-items:center}
231footer .social-links a{display:grid;place-items:center;width:44px;height:44px;margin:0;border:1px solid var(--steel-3);border-radius:4px;background:var(--steel-2);color:var(--on-dark-muted)}
232footer .social-links a:hover{color:var(--brass-hi);border-color:var(--brass)}
233footer .social-links svg{width:21px;height:21px}
234footer p{max-width:80ch;margin:0}
235.toast{position:fixed;left:50%;bottom:0;transform:translateX(-50%);margin-bottom:calc(16px + env(safe-area-inset-bottom,0px));background:var(--ink);color:var(--panel);padding:11px 18px;border-radius:4px;font-size:15px;opacity:0;pointer-events:none;transition:opacity .2s;z-index:10}
236.toast.show{opacity:1}
237</style>
238</head>
239<body>
240<svg width="0" height="0" style="position:absolute" aria-hidden="true">
241  <defs>
242    <symbol id="i-target" viewBox="0 0 24 24"><g fill="none" stroke="currentColor" stroke-width="1.6"><circle cx="12" cy="12" r="9.5"/><circle cx="12" cy="12" r="5.5"/><circle cx="12" cy="12" r="1.6" fill="currentColor"/><path d="M12 0v4M12 20v4M0 12h4M20 12h4"/></g></symbol>
243    <symbol id="i-card" viewBox="0 0 24 24"><g fill="none" stroke="currentColor" stroke-width="1.6"><rect x="2" y="5" width="20" height="14" rx="2"/><circle cx="8" cy="11" r="2.3"/><path d="M4.8 16c.6-1.8 1.8-2.6 3.2-2.6s2.6.8 3.2 2.6M14 10h5M14 13.5h4"/></g></symbol>
244    <symbol id="i-badge" viewBox="0 0 24 24"><g fill="none" stroke="currentColor" stroke-width="1.6"><path d="M12 2l8 3v6c0 5-3.4 9-8 11-4.6-2-8-6-8-11V5z"/><path d="M8.5 12l2.4 2.4L15.8 9.5"/></g></symbol>
245    <symbol id="i-pin" viewBox="0 0 24 24"><g fill="none" stroke="currentColor" stroke-width="1.6"><path d="M12 22s-7-6.2-7-12a7 7 0 0114 0c0 5.8-7 12-7 12z"/><circle cx="12" cy="10" r="2.6"/></g></symbol>
246    <symbol id="i-case" viewBox="0 0 24 24"><g fill="none" stroke="currentColor" stroke-width="1.6"><rect x="2.5" y="7" width="19" height="13" rx="2"/><path d="M8.5 7V5a2 2 0 012-2h3a2 2 0 012 2v2M2.5 12.5h19M11 12.5v2h2v-2"/></g></symbol>
247    <symbol id="i-scale" viewBox="0 0 24 24"><g fill="none" stroke="currentColor" stroke-width="1.6"><path d="M12 3v18M7 21h10M4 6h16M6.5 6L3 13a3.5 3.5 0 007 0zM17.5 6L14 13a3.5 3.5 0 007 0z"/></g></symbol>
248    <symbol id="i-cross" viewBox="0 0 24 24"><g fill="none" stroke="currentColor" stroke-width="1.6"><circle cx="12" cy="12" r="7.5"/><path d="M12 1.5v6M12 16.5v6M1.5 12h6M16.5 12h6"/></g></symbol>
249    <symbol id="i-store" viewBox="0 0 24 24"><g fill="none" stroke="currentColor" stroke-width="1.6"><path d="M3 9l1.5-5h15L21 9M3 9h18v2.2a2.8 2.8 0 01-5.2 1.4 3 3 0 01-5.4 0A2.8 2.8 0 013 11.2zM4.5 13.5V21h15v-7.5M10 21v-5h4v5"/></g></symbol>
250    <symbol id="i-compass" viewBox="0 0 24 24"><g fill="none" stroke="currentColor" stroke-width="1.6"><circle cx="12" cy="12" r="9.5"/><path d="M15.5 8.5l-2 5-5 2 2-5z"/></g></symbol>
251    <symbol id="i-check" viewBox="0 0 24 24"><path d="M4 12.5l5 5L20 6.5" fill="none" stroke="currentColor" stroke-width="2.4"/></symbol>
252  </defs>
253</svg>
254<header class="bar">
255  <div class="wrap">
256    <a class="logo" href="#top" aria-label="Weapons.com home"><img src="/weapons-brand-logo.png" width="1410" height="400" alt="Weapons.com — National directory: training, permits, careers"></a>
257    <nav aria-label="Main">
258      <a href="#directory">Directory</a>
259      <a href="#states">States</a>
260      <a href="#directory" data-jump="careers">Careers</a>
261      <a class="cta" href="#pros"><span class="lg">List your business</span><span class="sm">For pros</span></a>
262    </nav>
263  </div>
264</header>
265<main id="top">
266<section class="hero" aria-labelledby="h1">
267  <div class="photo" aria-hidden="true"></div>
268  <div class="shade" aria-hidden="true"></div>
269  <svg class="rings" viewBox="0 0 900 900" aria-hidden="true">
270    <g fill="none" stroke="#E2B764" stroke-dasharray="2400">
271      <circle cx="450" cy="450" r="440" stroke-width="1" opacity=".22"/>
272      <circle cx="450" cy="450" r="360" stroke-width="1" opacity=".28"/>
273      <circle cx="450" cy="450" r="280" stroke-width="1.2" opacity=".34"/>
274      <circle cx="450" cy="450" r="200" stroke-width="1.4" opacity=".4"/>
275      <circle cx="450" cy="450" r="120" stroke-width="1.6" opacity=".5"/>
276      <circle cx="450" cy="450" r="44" stroke-width="2" opacity=".6"/>
277    </g>
278    <g stroke="#E2B764" opacity=".3"><path d="M450 0v380M450 520v380M0 450h380M520 450h380"/></g>
279  </svg>
280  <div class="wrap inner">
281    <div>
282      <h1 id="h1"><span class="line">Trained.</span><span class="line">Licensed.</span><span class="line">Hired.</span></h1>
283      <p class="lede">The national directory for firearms training, carry permits, professional certifications and industry careers. Tell us what you need and we'll map the path for your state.</p>
284      <ul class="proof">
285        <li><svg><use href="#i-check"/></svg>All 50 states and DC</li>
286        <li><svg><use href="#i-check"/></svg>Listings opening state by state</li>
287        <li><svg><use href="#i-check"/></svg>Free to explore</li>
288      </ul>
289    </div>
290    <div class="intake" id="intake" aria-live="polite">
291      <div class="step">
292        <div class="progress" aria-hidden="true"><i class="on"></i><i></i><i></i></div>
293        <p class="qhead">What brings you here?</p>
294        <p class="qsub">Three taps to your personalized path.</p>
295        <div class="options">
296          <a class="opt" href="#directory" data-intent="permit"><svg aria-hidden="true"><use href="#i-card"/></svg><span><b>Get my carry permit</b><small>First permit, renewal or non-resident</small></span></a>
297          <a class="opt" href="#directory" data-intent="training"><svg aria-hidden="true"><use href="#i-target"/></svg><span><b>Find a class</b><small>Instructors and skill-building</small></span></a>
298          <a class="opt" href="#directory" data-intent="cert"><svg aria-hidden="true"><use href="#i-badge"/></svg><span><b>Get certified</b><small>Security, instructor, RSO, LE</small></span></a>
299          <a class="opt" href="#directory" data-intent="job"><svg aria-hidden="true"><use href="#i-case"/></svg><span><b>Find a job</b><small>Security, training, ranges, retail</small></span></a>
300          <a class="opt" href="#directory" data-intent="laws"><svg aria-hidden="true"><use href="#i-scale"/></svg><span><b>Check the laws</b><small>My state or travel</small></span></a>
301          <a class="opt" href="#directory" data-intent="gear"><svg aria-hidden="true"><use href="#i-cross"/></svg><span><b>Compare prices</b><small>Ammo, optics, gear</small></span></a>
302          <a class="opt" href="#pros" data-intent="business"><svg aria-hidden="true"><use href="#i-store"/></svg><span><b>List my business</b><small>Instructors, ranges, employers</small></span></a>
303          <a class="opt" href="#directory" data-intent="explore"><svg aria-hidden="true"><use href="#i-compass"/></svg><span><b>Just looking</b><small>History, collecting, curiosity</small></span></a>
304        </div>
305        <noscript><p class="note">Explore the directory topics below. Enable JavaScript for a personalized state path and launch notifications.</p></noscript>
306      </div>
307    </div>
308  </div>
309</section>
310<section class="how" aria-label="How it works">
311  <div class="wrap"><ol>
312    <li><span class="num">1</span><div><b>Pick your goal</b><p>Permit, class, certification, job or the law.</p></div></li>
313    <li><span class="num">2</span><div><b>Choose your state</b><p>Requirements change at every state line.</p></div></li>
314    <li><span class="num">3</span><div><b>Get your path</b><p>Explore the relevant topics and get notified when listings open.</p></div></li>
315  </ol></div>
316</section>
317<section class="block" id="directory" aria-labelledby="dirh">
318  <div class="wrap">
319    <div class="shead">
320      <div>
321        <h2 id="dirh">The directory</h2>
322        <p>Explore licenses, certifications, programs and careers by state. Provider listings are opening soon.</p>
323      </div>
324      <div class="field" style="margin:0">
325        <label for="dirstate">Filter by state</label>
326        <select id="dirstate" disabled>
327          <option value="">All states</option>
328          <option>Alabama</option><option>Alaska</option><option>Arizona</option><option>Arkansas</option>
329          <option>California</option><option>Colorado</option><option>Connecticut</option><option>Delaware</option>
330          <option>District of Columbia</option><option>Florida</option><option>Georgia</option><option>Hawaii</option>
331          <option>Idaho</option><option>Illinois</option><option>Indiana</option><option>Iowa</option>
332          <option>Kansas</option><option>Kentucky</option><option>Louisiana</option><option>Maine</option>
333          <option>Maryland</option><option>Massachusetts</option><option>Michigan</option><option>Minnesota</option>
334          <option>Mississippi</option><option>Missouri</option><option>Montana</option><option>Nebraska</option>
335          <option>Nevada</option><option>New Hampshire</option><option>New Jersey</option><option>New Mexico</option>
336          <option>New York</option><option>North Carolina</option><option>North Dakota</option><option>Ohio</option>
337          <option>Oklahoma</option><option>Oregon</option><option>Pennsylvania</option><option>Rhode Island</option>
338          <option>South Carolina</option><option>South Dakota</option><option>Tennessee</option><option>Texas</option>
339          <option>Utah</option><option>Vermont</option><option>Virginia</option><option>Washington</option>
340          <option>West Virginia</option><option>Wisconsin</option><option>Wyoming</option>
341        </select>
342      </div>
343    </div>
344    <!-- Initial HTML is the source for the enhanced directory taxonomy. -->
345    <div class="tiles" id="tiles">
346      <details class="directory-category" data-cat="licenses" data-icon="i-card" data-featured="true" id="cat-licenses">
347        <summary class="tile featured"><svg class="bg" aria-hidden="true"><use href="#i-card"/></svg><svg class="ic" aria-hidden="true"><use href="#i-card"/></svg><h3>Licenses and permits</h3><p>Carry permits, purchase permits and safety certificates. Explore the requirements and steps in your state.</p><span class="count">7 topics</span></summary>
348        <div class="panel"><p>Provider listings are opening soon. Topics to explore:</p><ul>
349          <li>Concealed carry permit (CCW / CPL / LTC)</li>
350          <li>Carry permit renewal</li>
351          <li>Non-resident carry permits</li>
352          <li>Purchase and ownership permits</li>
353          <li>Firearm safety certificates</li>
354          <li>Carry reciprocity by state</li>
355          <li>Permitless carry states</li>
356        </ul></div>
357      </details>
358      <details class="directory-category" data-cat="certs" data-icon="i-badge" id="cat-certs">
359        <summary class="tile"><svg class="ic" aria-hidden="true"><use href="#i-badge"/></svg><h3>Professional certifications</h3><p>Credentials for people who carry, teach or supervise for a living.</p><span class="count">7 topics</span></summary>
360        <div class="panel"><p>Provider listings are opening soon. Topics to explore:</p><ul>
361          <li>Armed security officer license</li>
362          <li>Armed guard requalification</li>
363          <li>Firearms instructor certification</li>
364          <li>Range safety officer</li>
365          <li>Law enforcement firearms qualification</li>
366          <li>Executive protection</li>
367          <li>Armorer certification</li>
368        </ul></div>
369      </details>
370      <details class="directory-category" data-cat="programs" data-icon="i-target" id="cat-programs">
371        <summary class="tile"><svg class="ic" aria-hidden="true"><use href="#i-target"/></svg><h3>Training programs</h3><p>Classes from first-time owner to advanced tactics.</p><span class="count">
37110 topics</span></summary>
372        <div class="panel"><p>Provider listings are opening soon. Topics to explore:</p><ul>
373          <li>Basic pistol</li>
374          <li>Defensive handgun</li>
375          <li>Rifle and carbine</li>
376          <li>Shotgun</li>
377          <li>Low-light shooting</li>
378          <li>Force-on-force scenarios</li>
379          <li>Trauma and bleeding control</li>
380          <li>Hunter education</li>
381          <li>Women-only classes</li>
382          <li>Youth programs</li>
383        </ul></div>
384      </details>
385      <details class="directory-category" data-cat="providers" data-icon="i-pin" id="cat-providers">
386        <summary class="tile"><svg class="ic" aria-hidden="true"><use href="#i-pin"/></svg><h3>Instructors and ranges</h3><p>Find instructors, training companies and ranges as listings open.</p><span class="count">6 topics</span></summary>
387        <div class="panel"><p>Provider listings are opening soon. Topics to explore:</p><ul>
388          <li>Find an instructor</li>
389          <li>Find a training company</li>
390          <li>Indoor ranges</li>
391          <li>Outdoor ranges</li>
392          <li>Private lessons</li>
393          <li>Group and corporate training</li>
394        </ul></div>
395      </details>
396      <details class="directory-category" data-cat="careers" data-icon="i-case" data-dark="true" id="cat-careers">
397        <summary class="tile featured dark"><svg class="ic" aria-hidden="true"><use href="#i-case"/></svg><h3>Careers</h3><p>Explore jobs that require firearms credentials and pathways to qualify.</p><span class="count">7 topics</span></summary>
398        <div class="panel"><p>Provider listings are opening soon. Topics to explore:</p><ul>
399          <li>Armed security officer</li>
400          <li>Firearms instructor</li>
401          <li>Range safety officer</li>
402          <li>Gunsmith</li>
403          <li>Armorer</li>
404          <li>Firearms retail and FFL staff</li>
405          <li>Executive protection agent</li>
406        </ul></div>
407      </details>
408      <details class="directory-category" data-cat="laws" data-icon="i-scale" id="cat-laws">
409        <summary class="tile"><svg class="ic" aria-hidden="true"><use href="#i-scale"/></svg><h3>Laws and travel</h3><p>Plain-language topics for carry, storage and transport.</p><span class="count">5 topics</span></summary>
410        <div class="panel"><p>Provider listings are opening soon. Topics to explore:</p><ul>
411          <li>State carry laws</li>
412          <li>Transporting firearms across states</li>
413          <li>Flying with firearms</li>
414          <li>Storage requirements</li>
415          <li>Where carry is prohibited</li>
416        </ul></div>
417      </details>
418      <details class="directory-category" data-cat="gear" data-icon="i-cross" id="cat-gear">
419        <summary class="tile"><svg class="ic" aria-hidden="true"><use href="#i-cross"/></svg><h3>Gear and ammo</h3><p>Price tracking and comparisons, opening after launch.</p><span class="count">4 topics</span></summary>
420        <div class="panel"><p>Coming soon after launch. Topics to explore:</p><ul>
421          <li>Ammo price tracker</li>
422          <li>Optics comparisons</li>
423          <li>Holsters and carry gear</li>
424          <li>Safes and storage</li>
425        </ul></div>
426      </details>
427    </div>
428  </div>
429</section>
430<section class="block" id="states" aria-labelledby="sth" style="padding-top:0">
431  <div class="wrap">
432    <div class="shead"><div><h2 id="sth">Start with your state</h2><p>Carry, purchase and training rules differ across all 50 states and DC. Pick yours.</p></div></div>
433    <div class="mapwrap">
434      <div>
435        <div class="map-scroller" tabindex="0" aria-label="Scroll to see more states">
436          <!-- Real in-page links without JavaScript; enhanced to state selectors. -->
437          <div class="tilemap" id="tilemap" role="group" aria-label="Choose a state">
438            <a class="st" href="#stateinfo" data-name="Alaska" data-col="0" data-row="0" style="grid-column:1;grid-row:1" aria-label="Alaska" title="Alaska">AK</a>
439            <a class="st" href="#stateinfo" data-name="Maine" data-col="10" data-row="0" style="grid-column:11;grid-row:1" aria-label="Maine" title="Maine">ME</a>
440            <a class="st" href="#stateinfo" data-name="Wisconsin" data-col="5" data-row="1" style="grid-column:6;grid-row:2" aria-label="Wisconsin" title="Wisconsin">WI</a>
441            <a class="st" href="#stateinfo" data-name="Vermont" data-col="9" data-row="1" style="grid-column:10;grid-row:2" aria-label="Vermont" title="Vermont">VT</a>
442            <a class="st" href="#stateinfo" data-name="New Hampshire" data-col="10" data-row="1" style="grid-column:11;grid-row:2" aria-label="New Hampshire" title="New Hampshire">NH</a>
443            <a class="st" href="#stateinfo" data-name="Washington" data-col="0" data-row="2" style="grid-column:1;grid-row:3" aria-label="Washington" title="Washington">WA</a>
444            <a class="st" href="#stateinfo" data-name="Idaho" data-col="1" data-row="2" style="grid-column:2;grid-row:3" aria-label="Idaho" title="Idaho">ID</a>
445            <a class="st" href="#stateinfo" data-name="Montana" data-col="2" data-row="2" style="grid-column:3;grid-row:3" aria-label="Montana" title="Montana">
445MT</a>
446            <a class="st" href="#stateinfo" data-name="North Dakota" data-col="3" data-row="2" style="grid-column:4;grid-row:3" aria-label="North Dakota" title="North Dakota">ND</a>
447            <a class="st" href="#stateinfo" data-name="Minnesota" data-col="4" data-row="2" style="grid-column:5;grid-row:3" aria-label="Minnesota" title="Minnesota">MN</a>
448            <a class="st" href="#stateinfo" data-name="Illinois" data-col="5" data-row="2" style="grid-column:6;grid-row:3" aria-label="Illinois" title="Illinois">IL</a>
449            <a class="st" href="#stateinfo" data-name="Michigan" data-col="6" data-row="2" style="grid-column:7;grid-row:3" aria-label="Michigan" title="Michigan">MI</a>
450            <a class="st" href="#stateinfo" data-name="New York" data-col="8" data-row="2" style="grid-column:9;grid-row:3" aria-label="New York" title="New York">NY</a>
451            <a class="st" href="#stateinfo" data-name="Massachusetts" data-col="9" data-row="2" style="grid-column:10;grid-row:3" aria-label="Massachusetts" title="Massachusetts">MA</a>
452            <a class="st" href="#stateinfo" data-name="Oregon" data-col="0" data-row="3" style="grid-column:1;grid-row:4" aria-label="Oregon" title="Oregon">OR</a>
453            <a class="st" href="#stateinfo" data-name="Nevada" data-col="1" data-row="3" style="grid-column:2;grid-row:4" aria-label="Nevada" title="Nevada">NV</a>
454            <a class="st" href="#stateinfo" data-name="Wyoming" data-col="2" data-row="3" style="grid-column:3;grid-row:4" aria-label="Wyoming" title="Wyoming">WY</a>
455            <a class="st" href="#stateinfo" data-name="South Dakota" data-col="3" data-row="3" style="grid-column:4;grid-row:4" aria-label="South Dakota" title="South Dakota">SD</a>
456            <a class="st" href="#stateinfo" data-name="Iowa" data-col="4" data-row="3" style="grid-column:5;grid-row:4" aria-label="Iowa" title="Iowa">IA</a>
457            <a class="st" href="#stateinfo" data-name="Indiana" data-col="5" data-row="3" style="grid-column:6;grid-row:4" aria-label="Indiana" title="Indiana">IN</a>
458            <a class="st" href="#stateinfo" data-name="Ohio" data-col="6" data-row="3" style="grid-column:7;grid-row:4" aria-label="Ohio" title="Ohio">OH</a>
459            <a class="st" href="#stateinfo" data-name="Pennsylvania" data-col="7" data-row="3" style="grid-column:8;grid-row:4" aria-label="Pennsylvania" title="Pennsylvania">PA</a>
460            <a class="st" href="#stateinfo" data-name="New Jersey" data-col="8" data-row="3" style="grid-column:9;grid-row:4" aria-label="New Jersey" title="New Jersey">NJ</a>
461            <a class="st" href="#stateinfo" data-name="Connecticut" data-col="9" data-row="3" style="grid-column:10;grid-row:4" aria-label="Connecticut" title="Connecticut">CT</a>
462            <a class="st" href="#stateinfo" data-name="Rhode Island" data-col="10" data-row="3" style="grid-column:11;grid-row:4" aria-label="Rhode Island" title="Rhode Island">RI</a>
463            <a class="st" href="#stateinfo" data-name="California" data-col="0" data-row="4" style="grid-column:1;grid-row:5" aria-label="California" title="California">CA</a>
464            <a class="st" href="#stateinfo" data-name="Utah" data-col="1" data-row="4" style="grid-column:2;grid-row:5" aria-label="Utah" title="Utah">UT</a>
465            <a class="st" href="#stateinfo" data-name="Colorado" data-col="2" data-row="4" style="grid-column:3;grid-row:5" aria-label="Colorado" title="Colorado">CO</a>
466            <a class="st" href="#stateinfo" data-name="Nebraska" data-col="3" data-row="4" style="grid-column:4;grid-row:5" aria-label="Nebraska" title="Nebraska">NE</a>
467            <a class="st" href="#stateinfo" data-name="Missouri" data-col="4" data-row="4" style="grid-column:5;grid-row:5" aria-label="Missouri" title="Missouri">MO</a>
468            <a class="st" href="#stateinfo" data-name="Kentucky" data-col="5" data-row="4" style="grid-column:6;grid-row:5" aria-label="Kentucky" title="Kentucky">KY</a>
469            <a class="st" href="#stateinfo" data-name="West Virginia" data-col="6" data-row="4" style="grid-column:7;grid-row:5" aria-label="West Virginia" title="West Virginia">WV</a>
470            <a class="st" href="#stateinfo" data-name="Virginia" data-col="7" data-row="4" style="grid-column:8;grid-row:5" aria-label="Virginia" title="Virginia">VA</a>
471            <a class="st" href="#stateinfo" data-name="Maryland" data-col="8" data-row="4" style="grid-column:9;grid-row:5" aria-label="Maryland" title="Maryland">MD</a>
472            <a class="st" href="#stateinfo" data-name="Delaware" data-col="9" data-row="4" style="grid-column:10;grid-row:5" aria-label="Delaware" title="Delaware">DE</a>
473            <a class="st" href="#stateinfo" data-name="Arizona" data-col="1" data-row="5" style="grid-column:2;grid-row:6" aria-label="Arizona" title="Arizona">AZ</a>
474            <a class="st" href="#stateinfo" data-name="New Mexico" data-col="2" data-row="5" style="grid-column:3;grid-row:6" aria-label="New Mexico" title="New Mexico">NM</a>
475            <a class="st" href="#stateinfo" data-name="Kansas" data-col="3" data-row="5" style="grid-column:4;grid-row:6" aria-label="Kansas" title="Kansas">KS</a>
476            <a class="st" href="#stateinfo" data-name="Arkansas" data-col="4" data-row="5" style="grid-column:5;grid-row:6" aria-label="Arkansas" title="Arkansas">AR</a>
477            <a class="st" href="#stateinfo" data-name="Tennessee" data-col="5" data-row="5" style="grid-column:6;grid-row:6" aria-label="Tennessee" title="Tennessee">TN</a>
478            <a class="st" href="#stateinfo" data-name="North Carolina" data-col="6" data-row="5" style="grid-column:7;grid-row:6" aria-label="North Carolina" title="North Carolina">NC</a>
479            <a class="st" href="#stateinfo" data-name="South Carolina" data-col="7" data-row="5" style="grid-column:8;grid-row:6" aria-label="South Carolina" title="South Carolina">SC</a>
480            <a class="st" href="#stateinfo" data-name="District of Columbia" data-col="8" data-row="5" style="grid-column:9;grid-row:6" aria-label="District of Columbia" title="District of Columbia">DC</a>
481            <a class="st" href="#stateinfo" data-name="Oklahoma" data-col="3" data-row="6" style="grid-column:4;grid-row:7" aria-label="Oklahoma" title="Oklahoma">OK</a>
482            <a class="st" href="#stateinfo" data-name="Louisiana" data-col="4" data-row="6" style="grid-column:5;grid-row:7" aria-label="Louisiana" title="Louisiana">LA</a>
483            <a class="st" href="#stateinfo" data-name="Mississippi" data-col="5" data-row="6" style="grid-column:6;grid-row:7" aria-label="Mississippi" title="Mississippi">MS</a>
484            <a class="st" href="#stateinfo" data-name="Alabama" data-col="6" data-row="6" style="grid-column:7;grid-row:7" aria-label="Alabama" title="Alabama">AL</a>
485            <a class="st" href="#stateinfo" data-name="Georgia" data-col="7" data-row="6" style="grid-column:8;grid-row:7" aria-label="Georgia" title="Georgia">GA</a>
486            <a class="st" href="#stateinfo" data-name="Hawaii" data-col="0" data-row="7" style="grid-column:1;grid-row:8" aria-label="Hawaii" title="Hawaii">HI</a>
487            <a class="st" href="#stateinfo" data-name="Texas" data-col="3" data-row="7" style="grid-column:4;grid-row:8" aria-label="Texas" title="Texas">TX</a>
488            <a class="st" href="#stateinfo" data-name="Florida" data-col="8" data-row="7" style="grid-column:9;grid-row:8" aria-label="Florida" title="Florida">FL</a>
489          </div>
490        </div>
491        <p class="map-hint">Swipe sideways to see all states.</p>
492      </div>
493      <div class="stateinfo" id="stateinfo" aria-live="polite">
494        <h3>Pick a state</h3>
495        <p>Select any state to explore topics and set the filter across the site. Topics to explore as listings go live across all 50 states and DC:</p>
496        <ul><li>Carry and purchase permits<span>Requirements and steps</span></li><li>Training<span>Classes and instructors</span></li><li>Professional licenses<span>Security and instructor</span></li><li>Industry jobs<span>Career paths</span></li></ul>
497        <noscript><p>State links lead to this shared topic overview. Enable JavaScript to select a state and personalize your path. Provider listings are opening state by state.</p></noscript>
498      </div>
499    </div>
500  </div>
501</section>
502<section class="pro" id="pros" aria-labelledby="proh">
503  <div class="grid-bg" aria-hidden="true"></div>
504  <div class="wrap inner">
505    <div>
506      <h2 id="proh">Teach, run a range or hire?</h2>
507      <p>Listings are planned state by state. Tell us about your business and get notified when your state opens.</p>
508      <button class="btn" id="listBtn">Register interest</button>
509    </div>
510    <ul>
511      <li><b>Instructors</b><span>Connect with students searching in your area when listings open.</span></li>
512      <li><b>Ranges and training companies</b><span>Show your courses, schedule and facilities when available.</span></li>
513      <li><b>Security companies and employers</b><span>Reach candidates looking for roles in the industry.</span></li>
514    </ul>
515  </div>
516</section>
517</main>
518<footer>
519  <div class="wrap">
520    <div class="row">
521      <a class="logo" href="#top" aria-label="Weapons.com home"><img src="/weapons-brand-logo.png" width="1410" height="400" alt="Weapons.com — National directory: training, permits, careers" loading="lazy"></a>
522      <nav aria-label="Footer"><a href="#directory">Directory</a><a href="#states">States</a><a href="#pros">List your business</a><a href="/privacy">Privacy</a></nav>
523      <nav class="social-links" aria-label="Social media">
524        <a href="https://x.com/weapons_com" target="_blank" rel="noopener noreferrer" aria-label="Weapons.com on X (@weapons_com), opens in a new tab" title="X: @weapons_com"><svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M18.901 1.153h3.68l-8.04 9.19L24 22.846h-7.406l-5.8-7.584-6.639 7.584H.473l8.6-9.835L0 1.154h7.594l5.243 6.932 6.064-6.933ZM17.61 20.644h2.039L6.486 3.24H4.298L17.61 20.644Z"/></svg></a>
525        <a href="https://www.instagram.com/weapons_com/" target="_blank" rel="noopener noreferrer" aria-label="Weapons.com on Instagram (@weapons_com), opens in a new tab" title="Instagram: @weapons_com"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" aria-hidden="true"><rect x="3" y="3" width="18" height="18" rx="5"/><circle cx="12" cy="12" r="4"/><circle cx="17.5" cy="6.5" r="1" fill="currentColor" stroke="none"/></svg></a>
526      </nav>
527    </div>
528    <p>Weapons.com provides educational information and a directory of third-party providers. Laws vary by state and change often; confirm requirements with your state agency before you apply, buy or carry.</p>
529  </div>
530</footer>
531<div class="toast" id="toast" role="status"></div>
532
533<script src="/analytics.js"></script>
vendor: 1 bytes, line 533
533
534<script>
535/* ---------- Data ---------- */
536// Read the initial HTML before enhancing it, so crawler and interactive content stay in sync.
537const TILES=[...document.querySelectorAll("#tilemap .st")].map(t=>[
538  t.textContent.trim(),Number(t.dataset.col),Number(t.dataset.row),t.dataset.name
539]);
540const STATES=TILES.map(t=>t[3]).sort();
541
542const CATEGORIES=[...document.querySelectorAll("#tiles .directory-category")].map(c=>({
543  id:c.dataset.cat,icon:c.dataset.icon,title:c.querySelector("h3").textContent,
544  featured:c.dataset.featured==="true",dark:c.dataset.dark==="true",
545  desc:c.querySelector("summary p").textContent,
546  items:[...c.querySelectorAll("li")].map(li=>li.textContent)
547}));
548
549const INTENTS=[
550  {id:"permit",icon:"i-card",label:"Get my carry permit",hint:"First permit, renewal or non-resident",
551  q:"Where are you in the process?",chips:["Haven't started","Need the class","Applied, waiting","Renewing","Non-resident permit"],cats:["licenses","programs","providers"]},
552  {id:"training",icon:"i-target",label:"Find a class",hint:"Instructors and skill-building",
553  q:"What level are you at?",chips:["Never fired a gun","New owner","Some experience","Advanced","Instructor-level"],cats:["programs","providers"]},
554  {id:"cert",icon:"i-badge",label:"Get certified",hint:"Security, instructor, RSO, LE",
555  q:"Which credential?",chips:["Armed security","Firearms instructor","Range safety officer","Law enforcement","Executive protection","Not sure yet"],cats:["certs","providers","careers"]},
556  {id:"job",icon:"i-case",label:"Find a job",hint:"Security, training, ranges, retail",
557  q:"What kind of role?",chips:["Armed security","Instructor","Range staff","Gunsmith / armorer","Retail / FFL","Protection work"],cats:["careers","certs"]},
558  {id:"laws",icon:"i-scale",label:"Check the laws",hint:"My state or travel",
559  q:"What do you need to know?",chips:["Carry rules","Traveling with a firearm","Buying a firearm","Storage","Reciprocity"],cats:["laws","licenses"]},
560  {id:"gear",icon:"i-cross",label:"Compare prices",hint:"Ammo, optics, gear",
561  q:"What are you shopping for?",chips:["Ammo","Handgun","Rifle","Optics","Holsters","Safes"],cats:["gear"]},
562  {id:"business",icon:"i-store",label:"List my business",hint:"Instructors, ranges, employers",
563  q:"What do you run?",chips:["Independent instructor","Training company","Range","Security company","Retailer / FFL"],cats:["providers","careers"]},
564  {id:"explore",icon:"i-compass",label:"Just looking",hint:"History, collecting, curiosity",
565  q:"What interests you most?",chips:["Military history","Collecting","Knives and edged weapons","Archery","Martial arts weapons"],cats:["laws"]}
566];
567
568/* ---------- Recording ---------- */
569let session;
570try{session=sessionStorage.getItem("wc_session")}catch(e){}
571if(!session){session=Math.random().toString(36).slice(2,10)+Date.now().toString(36);try{sessionStorage.setItem("wc_session",session)}catch(e){}}
572function recordEvent(type,data){
573  const names={intent:"goal_selected",detail:"path_generated",dir_state:"state_selected",result_link:"result_topic_clicked",category_open:"category_opened",topic_click:"topic_clicked",list_click:"business_interest_started"};
574  if(names[type])window.trackSiteEvent(names[type],type==="dir_state"?{state:data.state,source:data.topic}:data);
575  const body=JSON.stringify({type,session,referrer:document.referrer||null,...data});
576  try{
577    fetch("/api/events",{method:"POST",headers:{"Content-Type":"application/json"},body,keepalive:true}).catch(()=>{});
578  }catch(e){}
579}
580async function saveSignup(payload){
581  const dimensions={intent:payload.intent,detail:payload.detail,state:payload.state};
582  const trackSignup=(name,extra={})=>
582{if(!payload.website)window.trackSiteEvent(name,{...dimensions,...extra})};
583  trackSignup("notification_signup_started");
584  try{
585    const r=await fetch("/api/signup",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({...payload,session})});
586    const j=await r.json().catch(()=>({}));
587    if(r.ok&&j.ok){trackSignup("notification_signup_completed");return{ok:true}}
588    trackSignup("notification_signup_failed",{reason:"server_response"});
589    return{ok:false,error:j.error||"Your signup didn't save. Try again in a minute."};
590  }catch(e){trackSignup("notification_signup_failed",{reason:"network"});return{ok:false,error:"Couldn't reach the server. Check your connection and try again."}}
591}
592
593/* ---------- Shared state ---------- */
594const state={step:1,intent:null,chip:null,st:"",email:""};
595const $=id=>document.getElementById(id);
596const box=$("intake");
597function el(html){const t=document.createElement("template");t.innerHTML=html.trim();return t.content}
598function bar(){return `<div class="progress" aria-hidden="true">${[1,2,3].map(n=>`<i class="${n<=state.step?"on":""}"></i>`).join("")}</div>`}
599function stateOptions(sel){return `<option value="">All states</option>`+STATES.map(s=>`<option ${s===sel?"selected":""}>${s}</option>`).join("")}
600function setState(name,source){
601  const changed=state.st!==name;
602  if(changed&&state.step===3){state.email=$("em")?.value.trim()||state.email}
603  state.st=name;$("dirstate").value=name;
604  document.querySelectorAll(".st").forEach(b=>b.setAttribute("aria-pressed",String(b.dataset.name===name)));
605  renderStateInfo();if(openId)renderTiles();
606  const sel=$("st");if(sel)sel.value=name;
607  const next=$("next");if(next)next.disabled=!(state.chip&&state.st);
608  if(changed&&state.step===3)render();
609  if(source)recordEvent("dir_state",{state:name,topic:source});
610}
611
612/* ---------- Intake ---------- */
613function render(){
614  box.innerHTML="";
615  if(state.step===1){
616    box.append(el(`<div class="step">${bar()}
617      <h2 class="qhead">What brings you here?</h2>
618      <p class="qsub">Three taps to your personalized path.</p>
619      <div class="options">${INTENTS.map(i=>`<button class="opt" data-intent="${i.id}"><svg aria-hidden="true"><use href="#${i.icon}"/></svg><span><b>${i.label}</b><small>${i.hint}</small></span></button>`).join("")}</div></div>`));
620    box.querySelectorAll("[data-intent]").forEach(b=>b.onclick=()=>{
621      state.intent=b.dataset.intent;state.chip=null;state.step=2;
622      recordEvent("intent",{intent:state.intent});render();
623    });
624  }else if(state.step===2){
625    const it=INTENTS.find(i=>i.id===state.intent);
626    box.append(el(`<div class="step">${bar()}
627      <h2 class="qhead">${it.q}</h2>
628      <p class="qsub">${it.label}</p>
629      <div class="chips" role="group" aria-label="${it.q}">${it.chips.map(c=>`<button class="chip" aria-pressed="${state.chip===c}">${c}</button>`).join("")}</div>
630      <div class="field" style="margin-top:18px"><label for="st">Which state?</label><select id="st">${stateOptions(state.st).replace("All states","Choose a state")}</select></div>
631      <div class="actions"><button class="btn" id="next" ${state.chip&&state.st?"":"disabled"}>Show my path</button><button class="btn ghost" id="back">Back</button></div></div>`));
632    const next=box.querySelector("#next");
633    const upd=()=>{next.disabled=!(state.chip&&state.st)};
634    box.querySelectorAll(".chip").forEach(c=>c.onclick=()=>{
635      state.chip=c.textContent;box.querySelectorAll(".chip").forEach(x=>x.setAttribute("aria-pressed",x===c));upd();
636    });
637    box.querySelector("#st").onchange=e=>{setState(e.target.value,"intake");upd()};
638    box.querySelector("#back").onclick=()=>{state.step=1;render()};
639    next.onclick=()=>{
640      recordEvent("detail",{intent:state.intent,detail:state.chip,state:state.st});
641      setState(state.st);
642      state.step=3;render();
643    };
644  }else{
645    const it=INTENTS.find(i=>i.id===state.intent);
646    const cats=it.cats.map(id=>CATEGORIES.find(c=>c.id===id));
647    box.append(el(`<div class="step result">${bar()}
648      <h2 class="qhead">Your path in ${state.st}</h2>
649      <p class="qsub">${it.label}: ${state.chip}</p>
650      ${cats.map(c=>`<h3>${c.title}</h3><ul>${c.items.slice(0,3).map(x=>`<li><a href="#directory" data-open="${c.id}">${x}</a></li>`).join("")}</ul>`).join("")}
651      <h3>Be first when ${state.st} goes live</h3>
652       <p class="note">Provider listings are opening state by state. Leave your email for updates when your state goes live. <a href="/privacy">How we handle your information</a>.</p>
653      <div class="hp" aria-hidden="true"><label>Website <input type="text" id="website" tabindex="-1" autocomplete="off"></label></div>
654      <div class="actions"><input type="email" id="em" placeholder="[email protected]" aria-label="Email address" value="${state.email}"><button class="btn" id="notify">Notify me</button><button class="btn ghost" id="restart">Start over</button></div>
655      <p class="note" id="msg"></p></div>`));
656    box.querySelectorAll("[data-open]").forEach(a=>a.onclick=e=>{e.preventDefault();recordEvent("result_link",{intent:state.intent,category:a.dataset.open,topic:a.textContent,state:state.st});openCat(a.dataset.open)});
657    box.querySelector("#restart").onclick=()=>{Object.assign(state,{step:1,intent:null,chip:null});render()};
658    box.querySelector("#notify").onclick=async(ev)=>{
659      const btn=ev.currentTarget;const v=box.querySelector("#em").value.trim();const msg=box.querySelector("#msg");
660      if(!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(v)){msg.textContent="Enter a valid email address, like [email protected].";msg.className="note err";return}
661      state.email=v;btn.disabled=true;btn.textContent="Saving…";
662      const r=await saveSignup({intent:state.intent,detail:state.chip,state:state.st,email:v,website:box.querySelector("#website").value});
663      btn.disabled=false;btn.textContent="Notify me";
664      if(r.ok){msg.textContent="You're on the list. We'll email you when "+state.st+" goes live.";msg.className="note ok";btn.disabled=true}
665      else{msg.textContent=r.error;msg.className="note err"}
666    };
667  }
668}
669
670/* ---------- Directory tiles ---------- */
671let openId=null;
672const reduced=()=>matchMedia("(prefers-reduced-motion: reduce)").matches;
673function renderTiles(){
674  const wrap=$("tiles");
675  wrap.innerHTML=CATEGORIES.map(c=>`<button class="tile${c.featured?" featured":""}${c.dark?" featured dark":""}" id="cat-${c.id}" data-cat="${c.id}" aria-expanded="${openId===c.id}" aria-controls="panel">
676    ${c.featured?`<svg class="bg" aria-hidden="true"><use href="#${c.icon}"/></svg>`:""}
677    <svg class="ic" aria-hidden="true"><use href="#${c.icon}"/></svg>
678    <h3>${c.title}</h3><p>${c.desc}</p><span class="count">${c.items.length} topics</span></button>`).join("");
679  wrap.querySelectorAll(".tile").forEach(t=>t.onclick=()=>{
680    const id=t.dataset.cat;openId=openId===id?null:id;
681    if(openId)recordEvent("category_open",{category:id,state:$("dirstate").value});
682    renderTiles();
683    if(openId){
684      $("cat-"+id).focus({preventScroll:true});
685      $("panel").scrollIntoView({behavior:reduced()?"auto":"smooth",block:"nearest"});
686    }
687    else $("cat-"+id).focus({preventScroll:true});
688  });
689  if(openId){
690    const c=CATEGORIES.find(x=>x.id===openId);
691    const tile=$("cat-"+openId);
692    const st=$("dirstate").value;
693    const panel=el(`<div class="panel" id="panel" role="region" aria-label="${c.title} topics"><h4>${c.title}${st?" in "+st:""}</h4><div class="sub">${c.items.map(x=>`<a href="#" data-item="${x}" data-cat="${c.id}">${x}<em>${c.id==="gear"?"Coming soon":"Listings soon"}</em></a>`).join("")}</div></div>`);
694    // Insert the panel after the last tile in this row.
695    const tiles=[...wrap.querySelectorAll(".tile")];const top=tile.offsetTop;
696    let after=tile;for(const t of tiles){if(t.offsetTop===top)after=t}
697    after.after(panel);
698    wrap.querySelectorAll("[data-item]").forEach(a=>a.onclick=e=>{
699      e.preventDefault();const s=$("dirstate").value;
700      recordEvent("topic_click",{category:a.dataset.cat,topic:a.dataset.item,state:s});
701      toast((s?s+": ":"")+a.dataset.item+" listings are opening soon.");
702    });
703  }
704}
705function openCat(id){
706  if(!CATEGORIES.some(c=>c.id===id))return;
707  openId=id;recordEvent("category_open",{category:id,state:$("dirstate").value});renderTiles();
708  $("cat-"+id).scrollIntoView({behavior:reduced()?"auto":"smooth",block:"start"});
709  $("cat-"+id).focus({preventScroll:true});
710}
711
712/* ---------- State tile map ---------- */
713function renderMap(){
714  const m=$("tilemap");
715  m.innerHTML=TILES.map(([ab,c,r,name])=>`<button class="st" style="grid-column:${c+1};grid-row:${r+1}" data-name="${name}" aria-pressed="${state.st===name}" aria-label="${name}" title="${name}">${ab}</button>`).join("");
716  m.querySelectorAll(".st").forEach(b=>b.onclick=()=>setState(b.dataset.name,"map"));
717}
718function renderStateInfo(){
719  const s=state.st;const box2=$("stateinfo");
720   if(!s){box2.innerHTML=`<h3>Pick a state</h3><p>Select any state to explore topics and set the filter across the site. Topics to explore as listings go live across all 50 states and DC:</p>
721     <ul><li>Carry and purchase permits<span>Requirements and steps</span></li><li>Training<span>Classes and instructors</span></li><li>Professional licenses<span>Security and instructor</span></li><li>Industry jobs<span>Career paths</span></li></ul>`;return}
722  box2.innerHTML=`<h3>${s}</h3><p>Topics to explore as ${s} listings go live:</p>
723    <ul><li>Carry and purchase permits<span>Requirements and steps</span></li><li>Training<span>Classes and instructors</span></li><li>Professional licenses<span>Security and instructor</span></li><li>Industry jobs<span>Career paths</span></li></ul>
724    <button class="btn" id="startState">Start my ${s} path</button>`;
725  $("startState").onclick=()=>{
726    window.trackSiteEvent("state_path_started",{state:s,source:"map"});
727    state.step=state.intent?2:1;render();
728    $("intake").scrollIntoView({behavior:reduced()?"auto":"smooth",block:"start"});
729  };
730}
731
732/* ---------- Wiring ---------- */
733$("dirstate").innerHTML=stateOptions("");
734$("dirstate").disabled=false;
735$("dirstate").onchange=e=>setState(e.target.value,"filter");
736document.querySelectorAll("[data-jump]").forEach(a=>a.onclick=e=>{e.preventDefault();openCat(a.dataset.jump)});
737$("listBtn").onclick=()=>{
738  recordEvent("list_click",{});
739  Object.assign(state,{step:2,intent:"business",chip:null});render();
740  $("intake").scrollIntoView({behavior:reduced()?"auto":"smooth",block:"start"});
741  setTimeout(()=>$("st")?.focus({preventScroll:true}),reduced()?0:550);
742};
743
744let tt;function toast(t){const e=$("toast");e.textContent=t;e.classList.add("show");clearTimeout(tt);tt=setTimeout(()=>e.classList.remove("show"),2600)}
745let rt;addEventListener("resize",()=>{clearTimeout(rt);rt=setTimeout(()=>{if(openId)renderTiles()},150)});
746
747render();renderTiles();renderMap();renderStateInfo();
748</script>
vendor: 1 bytes, line 748
748
749<script src="https://i.replit.com/script.js" async="" data-website-id="be04f150-6b9d-4b13-80f6-0fa435715126"></script>
749</body>
750</html>

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.