PageSourceSearch

https://exoticca-3.netlify.app/

html exoticca-3.netlify.app collected 2026-10-03 10:42:55 UTC 35,100 bytes, 759 lines download raw bytes

1<!doctype html>
2<html lang="en">
3  <head>
4    <title>America’s Most Romantic Cozy Getaways - Exoticca</title>
5    <meta name="description" content="Use the map below to discover the most romantic, cozy getaway in each state.">
6    
7    <!-- Required meta tags -->
8    <meta charset="utf-8">
9    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
10    
11        
12    
12<script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
12
13
14    <!-- Bootstrap CSS -->
15    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
16    
17    <style>
18        *{box-sizing:border-box}.graph-wrap{max-width:1480px;margin:0 auto;padding:0 1rem;width:100%}body,p{text-align:center;font-size:18px}body{overflow-x:hidden}li{font-size:18px}.mobi{display:none}h1{margin:0}h1.he-outlined{color:#fff !important}h1.he-shadowed-black{text-shadow:0 10px 20px rgba(0, 0, 0, 0.5)}h1.he-italic{font-style:italic}h1 i{font-style:normal}h1#header{padding-bottom:0 !important}.banner{width:100%}.banner img{max-width:800px;width:100%;margin:0 auto;height:auto}.subheader,.footernote{font-size:20px;max-width:800px;width:100%}.subheader{margin-bottom:1.5rem}.footernote{margin:auto}.footernote a{font-size:12px;max-width:720px;padding:0.2rem;margin:auto;display:block}.footernote a:first-child{padding-top:1rem}.table_sub{font-size:20px;max-width:800px;width:100%}.table-wrap{max-width:1480px;margin:auto}.table-wrap table{font-size:16px;width:100%}.table-wrap table td{text-align:center;padding:0.5rem !important}.table-wrap table th{align-content:center;padding:0.5rem !important;text-align:center;vertical-align:middle !important;color:#fff}.table-wrap.tabcol-2{max-width:420px}.table-wrap.tabcol-3{max-width:800px}.table-wrap.tabcol-4{max-width:800px}.table-wrap.tabcol-5{max-width:1480px}.table-wrap.tabcol-6{max-width:1480px}.table-wrap.table-wrap.tabcol-8 table th{width:12.5%}.table-wrap.tabcol-8{width:100%;overflow-x:auto}@media (max-width:550px){.table-wrap table{font-size:12px;font-weight:500}.table-wrap{overflow:auto;width:100%}.table-wrap.mobile-table table th{display:none}.table-wrap.mobile-table table tr{display:block;border:1px solid #ccc}.table-wrap.mobile-table table tr:hover{background:transparent}.table-wrap.mobile-table table tr td{text-align:left;display:flex;border:none;padding:0 !important;justify-content:flex-start;align-items:center;font-size:14px}.table-wrap.mobile-table table tr td:hover{background:transparent !important}.table-wrap.mobile-table table tr td::before{content:attr(data-title) ": ";font-weight:bold;font-size:13px;height:60px;display:block;padding:10px;width:25%;color:#fff;text-align:center;align-content:center}.table-wrap.mobile-table table tr td span{display:block;width:75%;padding:10px}.table-wrap.mobile-table table tr:nth-child(even){background-color:#f3f3f3}}.extra-html{max-width:800px;margin:3rem auto 0}.extra-html h3,.extra-html h4,.extra-html b{font-weight:700}.extra-html p{padding:2rem;background:#fff;box-shadow:0px 0px 60px #ebe7e7;border-radius:10px;margin:1.5rem 0}a.logo-link{display:block;width:100%}a.logo-link img{width:100%;transition:0.2s}a.logo-link:hover img{transform:scale(1.1)}body.modal-open .modal-backdrop.fade.in{opacity:0.3}body.modal-open .modal.active{display:block;opacity:1}#shareModal .vertical-alignment-helper .modal-dialog.vertical-align-bottom,#embedModal .vertical-alignment-helper .modal-dialog.vertical-align-bottom{position:fixed;bottom:200px !important;left:0;right:0;margin:auto}.share-links .btn{background-color:#000;color:#fff;padding:0.75rem 3rem;margin:0 0.3rem;border:none;text-transform:uppercase;transition:0.2s;font-weight:600}.share-links .btn:hover{opacity:0.75}.info-box{display:flex;background:#eee;border-radius:40px;min-height:200px;max-width:800px;margin:2rem auto;padding:3rem;align-items:center;flex-direction:row}.info-box.reversed{flex-direction:row-reverse}.info-box .col{width:50%}.info-box .col img{width:100%;margin:auto;display:block}.notice{display:block;background:#f3f3f3;padding:3rem 4rem;color:#000;position:relative;margin:auto;z-index:9999;transition:0.2s}.notice i{display:block;height:40px;width:40px;background:#fff;color:black;line-height:40px;position:absolute;right:2%;top:1rem;bottom:1rem;margin:auto;font-style:normal;border-radius:50%;font-size:32px;transform:rotate(45deg);cursor:pointer}.notice.disabled{height:0;overflow:hidden;padding:0}.rounded .box{border-radius:2rem;overflow:hidden}.rounded .box span.num{border-radius:1rem}.credits{font-size:14px}.credits ul{padding:0}.credits i{display:block}.credits ul li{font-size:14px;list-style:none}@media screen and (max-width:800px){h1{font-size:4rem !important}.footernote p{font-size:0.75rem !important}}
18@media screen and (max-width:580px){a#openembed{display:none}a#openshare{width:80%;margin:0}h1{font-size:3rem !important}.he-retro-shaddow{letter-spacing:0.1em;font-size:2.5rem !important}.info-box{display:flex;flex-direction:column !important}.info-box .col{width:100%}.info-box .col img{margin-bottom:2rem !important}.credits ul li{font-size:11px !important;list-style:none}.graph-wrap{padding:1rem}.mobi{display:block}}@media screen and (max-width:401px){h1{font-size:2rem !important}.subheader,.footernote{font-size:18px;margin:1.5rem auto;max-width:800px;width:100%}.graph-wrap{padding:0.5rem}}    </style>
19
20    
21    <!-- GRAPH VAR CSS -->
22    <style>
23        
24    	  @font-face {
25			  font-family: 'OakesGrotesk-Bold' ;
26			  src: url('assets/OakesGrotesk-Bold.woff');
27		}
28			
29		  @font-face {
30			  font-family: 'OakesGrotesk-Regular' ;
31			  src: url('assets/OakesGrotesk-Regular.woff');
32		}
33	   
34   h1#header{ 
35        font-size: 3rem ; 
36        line-height: 1em ; 
37        color: #000000 ;
38        font-family: 'OakesGrotesk-Bold', serif;
39        font-weight: 100;
40    }
41    
42    h1#header i, h1#header span, h1#header b{ 
43        color:     }
44    
45    h2,h3,h4{ 
46      font-family: 'OakesGrotesk-Bold', serif !important; 
47      font-weight: 100;
48       
49    }
50    
51		/* Fonts*/
52    body,p,.subheader, .footernote{ 
53        font-family: 'OakesGrotesk-Regular', serif;
54        color: ; 
55        font-weight: 100;
56        font-size: 20px;
57    }
58    
59    
60
61            .logo-link{background: #000000; padding: 2rem; }
62            .logo-link{ border-radius: 1rem; }
63        
64    .he-shadowed-colour{ text-shadow: 0 10px 20px  #000000cc ;}
65    .he-outlined{ text-shadow: -2px -2px 0 #000000 ,  2px -2px 0 #000000 ,  -2px 2px 0 #000000 ,  2px 2px 0 #000000 ;}
66    .he-outlined-shaddow{ color: #fff !important; text-shadow:  0 5px 30px  #000000cc , -2px -2px 0 #000000 ,  2px -2px 0 #000000 ,  -2px 2px 0 #000000 ,  2px 2px 0 #000000 ;}
67    .he-retro-shaddow {
68        letter-spacing: .15em; text-transform: uppercase;
69        text-shadow: 3px 3px 0px #ffffff, 7px 7px 0px #00000035;
70    }
71    .he-retro-shaddow i{
72        letter-spacing: .15em; text-transform: uppercase;
73        text-shadow: 3px 3px 0px #ffffff, 7px 7px 0px 35;
74    }
75    .share-links .btn { background-color: #000000 !important;}
76    .share-links .btn { background-color:  !important;}
77    b,strong{ color: #000000; }
78    b,strong{ color: ; }
79   .keys span img{ width:  !important;}
80   
81   /*Spacing*/
82   h1#header,.subheader, .logo-link, .footer, .share-links, .graph-wrap{ padding: 2rem; padding: 1.5rem; margin: auto;}
83   .banner{ padding-top: 1.5rem;}
84   .table-wrap{ padding-top: 1.5rem; padding-bottom: 1.5rem;}
85   .box{margin-top: calc(1.5rem*2); margin-bottom: calc(1.5rem*2);}
86   .footernote p{margin-bottom: 0rem ; margin-bottom: calc(1.5rem*0.5); }
87   
88   /*Border Radius*/
89   a.logo-link, .share-links .btn, .popradius ,.rounded .box, .rounded .box .col2 span.num{ border-radius:0; border-radius: 15px !important;}
90   
91   /*Logo padding*/
92   a.logo-link{padding: 0; padding: 30px }
93   
94   
95   /*Tables*/
96   table th{ background-color: #000000 !important;} 
97   table th{ background-color:  !important;} 
98    
99   @media (max-width: 550px) {
100    .table-wrap table tr td::before {
101       background-color: #000000;
102       background-color: ;
103    }
104   }
105   
106       
107</style>
108  </head>
109  <body>
110
111    
112    
113<style>
114   .table_sub{margin: 1.5rem auto 1rem;}
115</style>
116
117<div class="preloader d-none">
118    <img src='assets/Banner2-1.svg' /></div>
119
120<div class="graph-wrap">
121
122    <!--[if lt IE 10]>
123    <p class="browserupgrade">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade
124        your browser</a> to improve your experience.</p>
125    <![endif]-->
126
127   <div class="graph map">
128
129                <h1 id="header" data-heading="America’s Most Romantic Cozy Getaways" class="  ">
130            America’s Most Romantic Cozy Getaways        </h1>
131                
132                <div class="banner">
133            <img src='assets/Banner2-1.svg' width='100' height='100' alt='' />        </div>
134        
135                <p class="subheader">
136            Use the map below to discover the most romantic, cozy getaway in each state.        </p>
137        
138        
139        
140<!-- CSS -->
141<style>
142
143    :root{
144         /* === EDIT YOUR MAP COLORS HERE === */
145         --state-fill: #f8d447;
146         --state-fill-hover: #f7efd9;
147         --state-stroke: #fff;
148         --state-stroke-hover: #fff;
149      }
150      
151    :root{--state-stroke-width: 1;--label-color: rgba(0, 0, 0, 1)}body{margin:0;font-family:system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, sans-serif}.wrap{max-width:1100px;margin:0 auto;padding:2rem 1rem}.map-card{padding:0rem;overflow:hidden}svg{width:100%;height:100%;display:block;touch-action:manipulation}.state{cursor:pointer;vector-effect:non-scaling-stroke;stroke:var(--state-stroke);stroke-width:var(--state-stroke-width);
151fill:var(--state-fill);transition:fill 120ms ease, stroke 120ms ease;outline:none}.state:hover,.state.is-active,.state:focus-visible{fill:var(--state-fill-hover);stroke:var(--state-stroke-hover)}.state-label{font-size:11px;font-weight:700;fill:var(--label-color);paint-order:stroke;stroke:var(--label-outline);stroke-width:3px;stroke-linejoin:round;pointer-events:none;user-select:none}.tooltip{position:fixed;z-index:9999;max-width:min(320px, calc(100vw - 24px));padding:2rem;border-radius:12px;background:white;color:#000000;box-shadow:0 10px 30px rgba(0, 0, 0, 0.2);pointer-events:none;opacity:0;transform:translateY(6px);transition:opacity 120ms ease, transform 120ms ease}.tooltip.is-open{opacity:1;transform:translateY(0)}.tooltip-close{position:absolute;top:8px;right:8px;width:28px;height:28px;border-radius:50%;border:none;background:#000;color:#fff;font-size:18px;line-height:1;cursor:pointer;display:none}@media (hover:none) and (pointer:coarse){.tooltip-close{display:block}}.tt-head{display:flex;align-items:center;gap:8px;width:100%;margin-bottom:6px;justify-content:center}.tt-icon{height:auto;display:block;object-fit:contain;position:absolute;top:-25px;left:0;right:0;margin:auto}.tooltip h4{margin:0;font-size:20px;line-height:1.2}.tooltip p{margin:0;font-size:16px;line-height:1.35;opacity:0.95}#map{width:100%;height:min(70vh, 600px);min-height:300px;position:relative}@media screen and (max-width:800px){#map{width:100%;height:min(50vh, 400px);min-height:250px;position:relative}}@media screen and (max-width:520px){#map{width:100%;height:min(30vh, 250px);min-height:200px;position:relative}}    
152    .stats-layer .heading, .stats-layer h4{ color: #f8d447;}
153   .tooltip{
154      padding-top: calc(60px + 10px);
155   }
156
157    div#Hawaii{
158p{ display: none}
159&::after{content: "No Data"; text-align: center; display:block;}
160}
161</style>
162
163
164<!-- HTML -->
165    <div class="preloader d-none">
166        <img src="assets/Icon-4.svg "> 
167    </div>
168   
169    
170   <div class="wrap">
171       <div class="map-card">
172         <div id="map"></div>
173       </div>
174   </div>
175   
176   <div id="tooltip" class="tooltip stats-layer popradius " role="dialog" aria-live="polite"></div>
177    
178
179
180<!-- JS -->
181
182<!-- Non-module, works on file:// as well -->
183  
183<script src="https://cdn.jsdelivr.net/npm/d3@7"></script>
183
184  
184<script src="https://cdn.jsdelivr.net/npm/topojson-client@3"></script>
184
185
186  
186<script>
187    const TOPO_URL = "https://cdn.jsdelivr.net/npm/us-atlas@3/states-10m.json";
188
189    // Global tooltip icon (PNG/JPG/SVG)
190    const TOOLTIP_ICON_URL = 'assets/Icon-4.svg';
191
192    // Map TopoJSON FIPS codes to state abbreviations
193    const FIPS_TO_ABBR = {
194      1:"AL",2:"AK",4:"AZ",5:"AR",6:"CA",8:"CO",9:"CT",10:"DE",
195      12:"FL",13:"GA",15:"HI",16:"ID",17:"IL",18:"IN",
196      19:"IA",20:"KS",21:"KY",22:"LA",23:"ME",24:"MD",25:"MA",
197      26:"MI",27:"MN",28:"MS",29:"MO",30:"MT",31:"NE",32:"NV",
198      33:"NH",34:"NJ",35:"NM",36:"NY",37:"NC",38:"ND",39:"OH",
199      40:"OK",41:"OR",42:"PA",44:"RI",45:"SC",46:"SD",47:"TN",
200      48:"TX",49:"UT",50:"VT",51:"VA",53:"WA",54:"WV",55:"WI",
201      56:"WY"
202    };
203
204    // State data keyed by abbreviation
205    const DATA = {
206        AL: { name:'Alabama',inhabitant :'Alabamians',stat_1:'Mentone' },
207AK: { name:'Alaska',inhabitant :'Alaskans',stat_1:'Homer' },
208AZ: { name:'Arizona',inhabitant :'Arizonans',stat_1:'Pinetop-Lakeside' },
209AR: { name:'Arkansas',inhabitant :' Arkansans',stat_1:'Eureka Springs' },
210CA: { name:'California',inhabitant :'Californians',stat_1:'Idyllwild' },
211CO: { name:'Colorado',inhabitant :'Coloradans',stat_1:'Ouray' },
212CT: { name:'Connecticut',inhabitant :'Nutmeggers',stat_1:'Litchfield' },
213DE: { name:'Delaware',inhabitant :'Delawareans',stat_1:'Lewes' },
214FL: { name:'Florida',inhabitant :'Floridians',stat_1:'Apalachicola' },
215GA: { name:'Georgia',inhabitant :'Georgians',stat_1:'Helen' },
216HI: { name:'Hawaii',inhabitant :'Hawaii residents',stat_1:'' },
217ID: { name:'Idaho',inhabitant :'Idahoans',stat_1:'Sandpoint' },
218IL: { name:'Illinois',inhabitant :'Illinoisans',stat_1:'Ottawa' },
219IN: { name:'Indiana',inhabitant :'Hoosiers',stat_1:'Nashville' },
220IA: { name:'Iowa',inhabitant :'Iowans',stat_1:'Spirit Lake' },
221KS: { name:'Kansas',inhabitant :'Kansans',stat_1:'Cottonwood Falls' },
222KY: { name:'Kentucky',inhabitant :'Kentuckians',stat_1:'Pine Mountain' },
223LA: { name:'Louisiana',inhabitant :'Louisianans',stat_1:'Abita Springs' },
224ME: { name:'Maine',inhabitant :'Mainers',stat_1:'Camden' },
225MD: { name:'Maryland',inhabitant :'Marylanders',stat_1:'St. Michaels' },
226MA: { name:'Massachusetts',inhabitant :'Bay Staters',stat_1:'Stockbridge' },
227MI: { name:'Michigan',inhabitant :'Michiganders',stat_1:'Harbor Springs' },
228MN: { name:'Minnesota',inhabitant :'Minnesotans',stat_1:'Ely' },
229MS: { name:'Mississippi',inhabitant :'Mississippians',stat_1:'Natchez' },
230MO: { name:'Missouri',inhabitant :'Missourians',stat_1:'Arrow Rock' },
231MT: { name:'Montana',inhabitant :'Montanans',stat_1:'Philipsburg' },
232NE: { name:'Nebraska',inhabitant :'Nebraskans',stat_1:'Brownville' },
233NV: { name:'Nevada',inhabitant :'Nevadans',stat_1:'Ely' },
234NH: { name:'New Hampshire',inhabitant :'Granite Staters',stat_1:'Sugar Hill' },
235NJ: { name:'New Jersey',inhabitant :'New Jerseyans',stat_1:'Cape May' },
236NM: { name:'New Mexico',inhabitant :'New Mexicans',stat_1:'Taos' },
237NY: { name:'New York', inhabitant :'New Yorkers',stat_1:'Lake Placid' },
238NC: { name:'North Carolina', inhabitant :'North Carolinians',stat_1:'Highlands' },
239ND: { name:'North Dakota',inhabitant :'North Dakotans',stat_1:'Bottineau' },
240OH: { name:'Ohio',inhabitant :'Ohioans',stat_1:'Granville' },
241OK: { name:'Oklahoma',inhabitant :'Oklahomans',stat_1:'Broken Bow' },
242OR: { name:'Oregon',inhabitant :'Oregonians',stat_1:'Sisters' },
243PA: { name:'Pennsylvania',inhabitant :'Pennsylvanians',stat_1:'Lititz' },
244RI: { name:'Rhode Island', inhabitant :'Rhode Islanders',stat_1:'Bristol' },
245SC: { name:'South Carolina',inhabitant :'South Carolinians',stat_1:'Travelers Rest' },
246SD: { name:'South Dakota',inhabitant :'South Dakotans',stat_1:'Deadwood' },
247TN: { name:'Tennessee',inhabitant :'Tennesseans',stat_1:'Gatlinburg' },
248TX: { name:'Texas',inhabitant :'Texans',stat_1:'Alpine' },
249UT: { name:'Utah',inhabitant :'Utahns',stat_1:'Midway' },
250VT: { name:'Vermont',inhabitant :'Vermonters',stat_1:'Waitsfield' },
251VA: { name:'Virginia',inhabitant :'Virginians',stat_1:'Floyd' },
252WA: { name:'Washington',inhabitant :'Washingtonians',stat_1:'La Conner' },
253WV: { name:'West Virginia',inhabitant :'West Virginians',stat_1:'Lewisburg' },
254WI: { name:'Wisconsin',inhabitant :'Wisconsinites',stat_1:'Minocqua' },
255WY: { name:'Wyoming',inhabitant :'Wyomingites',stat_1:'Dubois' }, 
256    };
257
258
259    const mapEl = document.getElementById("map");
260    const tooltip = document.getElementById("tooltip");
261
262    let activeEl = null;
263    let stickyOpen = false;
264    let cachedStates = null;
265    let cachedTopoFeature = null;
266
267    function getMeta(d){
268      const fips = +d.id;
269      const abbr = FIPS_TO_ABBR[fips];
270      const row = abbr ? DATA[abbr] : null;
271
272      if (!abbr || !row) {
273        return { abbr: abbr || "", name: "Unknown", inhabitant: "", stat_1: "" };
274      }
275
276      return {
277        abbr,
278        name: row.name,
279        inhabitant: row.inhabitant,
280        stat_1: row.stat_1,
281        stat_2: row.stat_2,
282        stat_3: row.stat_3,
283        stat_4: row.stat_4,
284      };
285    }
286
287    function tooltipHtml(a){
288       
289        var popuptext = a.stat_1+' was voted the coziest romantic getaway in '+a.name+'.';
290      return `
291      
292        <button class="tooltip-close" aria-label="Close tooltip">×</button>
293        <img class="tt-icon" src="${TOOLTIP_ICON_URL}"  width="120"  alt="" aria-hidden="true" style="top: -60px" />
294        <div id="${a.name}">
295           <div class="tt-head text-center ">
296             <h4>${a.name} (${a.abbr})</h4>
297           </div>
298           <p>`+ popuptext +`</p>
299        </div>
300      `;
301    }
302
303    function openTooltipAt(x, y, html) {
304      tooltip.innerHTML = html;
305      tooltip.classList.add("is-open");
306
307      const offset = 14;
308      const vw = window.innerWidth, vh = window.innerHeight;
309
310      tooltip.style.left = "0px";
311      tooltip.style.top = "0px";
312      const rect = tooltip.getBoundingClientRect();
313
314      let left = x + offset;
315      let top  = y + offset;
316
317      if (left + rect.width > vw - 10) left = vw - rect.width - 10;
318      if (top + rect.height > vh - 10) top = vh - rect.height - 10;
319      if (left < 10) left = 10;
320      if (top < 10) top = 10;
321
322      tooltip.style.left = left + "px";
323      tooltip.style.top  = top  + "px";
324    }
325
326    // Delegate close button click
327    tooltip.addEventListener("click", (e) => {
328      if (e.target && e.target.classList.contains("tooltip-close")) {
329        closeTooltip();
330      }
331    });
332
333    function closeTooltip() {
334      tooltip.classList.remove("is-open");
335      stickyOpen = false;
336      if (activeEl) activeEl.classList.remove("is-active");
337      activeEl = null;
338    }
339
340    function setActive(el) {
341      if (activeEl && activeEl !== el) activeEl.classList.remove("is-active");
342      activeEl = el;
343      if (activeEl) activeEl.classList.add("is-active");
344    }
345
346    function render(statesGeoJson) {
347      mapEl.innerHTML = "";
348      const width = mapEl.clientWidth;
349      const height = mapEl.clientHeight;
350
351      const svg = d3.select(mapEl)
352        .append("svg")
353        .attr("viewBox", `0 0 ${width} ${height}`)
354        .attr("preserveAspectRatio", "xMidYMid meet");
355
356      const projection = d3.geoAlbersUsa().fitSize([width, height], statesGeoJson);
357      const path = d3.geoPath(projection);
358
359      const g = svg.append("g");
360
361      // Draw states
362      const states = g.selectAll("path.state")
363        .data(statesGeoJson.features)
364        .enter()
365        .append("path")
366        .attr("class", "state")
367        .attr("d", path)
368        .attr("tabindex", 0)
369        .attr("role", "button")
370        .attr("aria-label", d => getMeta(d).name);
371
372      // Hover / move (desktop)
373      states.on("pointerenter", (event, d) => {
374        if (event.pointerType && event.pointerType !== "mouse") return;
375        if (stickyOpen) return;
376        const meta = getMeta(d);
377        setActive(event.currentTarget);
378        openTooltipAt(event.clientX, event.clientY, tooltipHtml(meta));
379      });
380
381      states.on("pointermove", (event, d) => {
382        if (event.pointerType && event.pointerType !== "mouse") return;
383        if (stickyOpen) return;
384        const meta = getMeta(d);
385        openTooltipAt(event.clientX, event.clientY, tooltipHtml(meta));
386      });
387
388      states.on("pointerleave", (event) => {
389        if (event.pointerType && event.pointerType !== "mouse") return;
390        if (stickyOpen) return;
391        closeTooltip();
392      });
393
394      // Tap/click (mobile + desktop)
395      // Use pointerdown for touch because mobile Safari/Chrome can drop or delay click events.
396      function openFromEvent(event, d) {
397        event.preventDefault();
398        event.stopPropagation();
399
400        const meta = getMeta(d);
401        const el = event.currentTarget;
402
403        // toggle same state
404        if (activeEl === el && stickyOpen) {
405          closeTooltip();
406          return;
407        }
408
409        stickyOpen = true;
410        setActive(el);
411
412        // On touch devices, lock tooltip to state centroid
413        let x, y;
414
415        if (event.pointerType === "touch" || event.pointerType === "pen") {
416          const [cx, cy] = path.centroid(d);
417          const svgRect = mapEl.querySelector("svg").getBoundingClientRect();
418          x = svgRect.left + cx;
419          y = svgRect.top + cy;
420        } else {
421          // Mouse: follow cursor
422          x = event.clientX;
423          y = event.clientY;
424        }
425
426        openTooltipAt(x, y, tooltipHtml(meta));
427      }
428
429      // Touch devices: pointerdown is the most reliable
430      states.on("pointerdown", (event, d) => {
431        if (event.pointerType === "touch" || event.pointerType === "pen") {
432          openFromEvent(event, d);
433        }
434      });
435
436      // Mouse devices: keep click as a fallback
437      states.on("click", (event, d) => {
438        if (event.pointerType === "mouse" || !event.pointerType) {
439          openFromEvent(event, d);
440        }
441      });
442
443      // Keyboard
444      states.on("keydown", (event, d) => {
445        if (event.key !== "Enter" && event.key !== " ") return;
446        event.preventDefault();
447        const meta = getMeta(d);
448
449        stickyOpen = true;
450        setActive(event.currentTarget);
451
452        const [cx, cy] = path.centroid(d);
453        const svgRect = mapEl.querySelector("svg").getBoundingClientRect();
454        openTooltipAt(svgRect.left + cx, svgRect.top + cy, tooltipHtml(meta));
455      });
456
457      // Labels (abbreviations)
458      // Some features can produce NaN centroids with the path centroid calc (projection returns null for some points).
459      // We compute a safe label position and only render labels when we have finite coordinates.
460      function safeLabelPos(feature) {
461        // First try the projected path centroid
462        const c = path.centroid(feature);
463        if (Number.isFinite(c[0]) && Number.isFinite(c[1])) return c;
464
465        // Fallback: project the geographic centroid
466        const gc = d3.geoCentroid(feature);
467        const p = projection(gc);
468        if (p && Number.isFinite(p[0]) && Number.isFinite(p[1])) return p;
469
470        // No safe position
471        return null;
472      }
473
474      const labelData = statesGeoJson.features
475        .map(f => {
476          const meta = getMeta(f);
477          if (!meta || meta.abbr === "??") return null; // skip DC / unknowns
478
479          const pos = safeLabelPos(f);
480          if (!pos) return null;
481
482          return { feature: f, pos, abbr: meta.abbr };
483        })
484        .filter(Boolean);
485
486      g.selectAll("text.state-label")
487        .data(labelData)
488        .enter()
489        .append("text")
490        .attr("class", "state-label")
491        .attr("x", d => d.pos[0])
492        .attr("y", d => d.pos[1])
493        .attr("text-anchor", "middle")
494        .attr("dominant-baseline", "central")
495        .text(d => d.abbr);
496
497      // cache for resize
498      cachedStates = statesGeoJson;
499    }
500
501    // Close when tapping/clicking outside a state
502    document.addEventListener(
503      "pointerdown",
504      (e) => {
505        // If the tap is on a state, let the state handler open the tooltip
506        if (e.target && e.target.closest && e.target.closest("path.state")) return;
507        closeTooltip();
508      },
509      { passive: true }
510    );
511
512    // Resize: re-render on container resize (keeps labels + paths correct)
513    new ResizeObserver(() => {
514      if (cachedStates) render(cachedStates);
515    }).observe(mapEl);
516
517    // Load and draw
518    d3.json(TOPO_URL).then(topo => {
519      const statesGeoJson = topojson.feature(topo, topo.objects.states);
520      cachedTopoFeature = statesGeoJson;
521      render(statesGeoJson);
522    });
523    
524  </script>
524
525  
526
527
528
529
530
531
532
533
534
535
536
537
538        
539        
540    </div>
541
542        <a class="logo-link" style="max-width:282px" href="https://www.exoticca.com/" target="_blank"
543        rel="Exoticca">
544        <img src='assets/exoticca-logo-white.svg' alt='' />    </a>
545    
546        <div class="footer">
547        <div class="footernote">
548            <p>Methodology: This study is based on a survey of 3,012 respondents conducted in January 2026, exploring which towns people consider the coziest romantic getaways in each state. Respondents were asked to identify destinations they associate with warmth, comfort, and an inviting romantic atmosphere. Responses were collected via an online panel and balanced across age, gender, and geographic region to reflect a broad cross-section of travellers nationwide. To ensure the results were representative, a two-step methodology was used, combining stratified sampling with post-stratification weighting aligned to national population benchmarks.</p>
549
550                    </div>
551    </div>
552    
553        <div class="share-links">
554
555                <a data-toggle="modal" href="#shareModal" class="btn btn-lg btn-primary btn-inline" id="openshare">Share</a>
556        
557                <a data-toggle="modal" href="#embedModal" class="btn btn-lg btn-primary btn-inline" id="openembed">Embed</a>
558            </div>
559
560    
561
562</div>       	
563	<!-- Modal - Share -->
564<div class="modal fade" id="shareModal" role="dialog">
565    <div class="vertical-alignment-helper">
566        <div class="modal-dialog vertical-align-bottom">
567            <!-- Modal content-->
568            <div class="modal-content">
569                <div class="modal-header" style="padding:20px 20px">
570
571                    <h4>
572                        <strong><span class="fa fa-code"></span> Share this on your website or blog</strong>
573                    </h4>
574                    <button type="button" class="close close-share" data-dismiss="modal">&times;</button>
575                </div>
576                <div class="modal-body">
577
578                    <!-- AddToAny BEGIN -->
579                       <div id="share-btns" class="a2a_kit a2a_kit_size_32 a2a_default_style" data-a2a-url="#">
580                           <a class="a2a_button_facebook"></a>
581                           <a class="a2a_button_twitter"></a>
582                           <a class="a2a_button_whatsapp"></a>
583                           <!--<a class="a2a_button_pinterest"></a>-->
584                           <a class="a2a_button_linkedin"></a>
585                           <a class="a2a_button_facebook_messenger"></a>
586                           <a class="a2a_button_telegram"></a>
587                           <a class="a2a_button_snapchat"></a>
588                           <!--<a class="a2a_button_viber"></a>-->
589                           <a class="a2a_button_wechat"></a>
590                           <a class="a2a_button_email"></a>
591                           <!--<a class="a2a_dd" href="https://www.addtoany.com/share"></a>-->
592                       </div>
593
594                </div>
595                <div class="modal-footer">
596                    <button type="submit" class="btn btn-default close-share" data-dismiss="modal">
597                        &times; Close
598                    </button>
599                </div>
600            </div>
601        </div>
602    </div>
603</div><!-- Modal - Embed -->
604<div class="modal fade" id="embedModal" role="dialog">
605    <div class="vertical-alignment-helper">
606        <div class="modal-dialog vertical-align-bottom">
607            <!-- Modal content-->
608            <div class="modal-content">
609                <div class="modal-header" style="padding:20px 20px">
610                    <h4>
611                        <strong><span class="fa fa-code"></span> Embed this on your website or blog</strong>
612                    </h4>
613                    <button type="button" class="close close-embed" data-dismiss="modal">&times;</button>
614                </div>
615                <div class="modal-body">
616                    <form role="form">
617                        <p>Copy the code below and paste it into the body of the HTML of your web page.</p>
618                        <div class="form-group">
619                            <textarea name="embedder" id="embedder" class="embedder form-control" cols="30" rows="6">&lt;iframe src=&quot;[SOURCE_URL]&quot; width=&quot;[FRAME_WIDTH]&quot; height=&quot;[FRAME_HEIGHT]&quot;id=&quot;data_map_iframe&quot; allowfullscreen allowtransparency=&quot;&quot; style=&quot;border:0;&quot;frameborder=&quot;0&quot;&gt;&lt;/iframe&gt;&lt;p style=&quot;text-align:center&quot;&gt;&lt;small&gt;Created by &lt;a href=&quot;[BRAND_URL]&quot; target=&quot;_blank&quot;&gt;[BRAND]&lt;/a&gt;&amp;nbsp;&amp;bull;&amp;nbsp;&lt;a href=&quot;[FULL_SIZE_URL]&quot; target=&quot;_blank&quot;&gt;Viewlarger version&lt;/a&gt; &lt;/small&gt;&lt;/p&gt;&lt;script&gt;window.addEventListener(&quot;message&quot;,function(e){e.data.hasOwnProperty(&quot;FrameHeight&quot;)&amp;&amp; (document.getElementById(&quot;data_map_iframe&quot;).style.height = e.data.FrameHeight+ 'px')}),document.getElementById(&quot;data_map_iframe&quot;).onload=function(){ document.getElementById(&quot;data_map_iframe&quot;).contentWindow.postMessage(&quot;FrameHeight&quot;,&quot;*&quot;)}; &lt;/script&gt;</textarea>
620                        </div>
621                    </form>
622                </div>
623                <div class="modal-footer">
624                    <button type="submit" class="btn btn-default close-embed" data-dismiss="modal">
625                        &times; Close
626                    </button>
627                </div>
628            </div>
629        </div>
630    </div>
631</div>
632
633
634    
634<script src="settings.js"></script>
634
635    
635<script async src="https://static.addtoany.com/menu/page.js"></script>
635
636    
636<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
636
637    
637<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
637
638    
639    
639<script>
640
641        $('.close-share').on('click touch', function(){
642    $('body').removeClass('modal-open');
643    $('#shareModal').removeClass('active');
644    $('.modal-backdrop').remove();
645})
646
647$('#openshare').on('click touch', function(){
648    $('#shareModal').addClass('active');
649})
650
651$('#share-btns').attr('data-a2a-url',projectSettings.fullSizeUrl);
652
653window.addEventListener("message", function (t) {
654        if ("FrameHeight" == t.data) {
655            var a = document.body,
656                i = document.documentElement,
657                e = Math.max(a.scrollHeight, a.offsetHeight, i.clientHeight, i.scrollHeight, i.offsetHeight);
658            e += 20, t.source.postMessage({
659                FrameHeight: e
660            }, "*")
661        }
662        });
663
664
665//Table JS
666jQuery(document).ready(function($) {
667  if ($('.table-wrap').length > 0) {
668    $('.table-wrap table').each(function() {
669      var $table = $(this);
670      var headings = [];
671
672      // Get headers from first row
673      $table.find('tbody tr:first-child th').each(function(index) {
674        headings[index] = $(this).text().trim();
675      });
676
677      // Loop through all rows after the first
678      $table.find('tbody tr:gt(0)').each(function() {
679        $(this).find('td').each(function(index) {
680          var $td = $(this);
681          if (headings[index]) {
682            $td.attr('data-title', headings[index]);
683          }
684
685          // Wrap existing content in a span if not already wrapped
686          if (!$td.children('span').length) {
687            $td.html('<span>' + $td.html().trim() + '</span>');
688          }
689        });
690      });
691    });
692  }
693});
694    $(document).ready(function(){
695        embedThis = function () {
696    if (void 0 != projectSettings) {
697        var t = $(".embedder"),
698            a = projectSettings.sourceUrl ? projectSettings.sourceUrl : window.location.href,
699            i = projectSettings.brandUrl ? projectSettings.brandUrl : window.location.hostname,
700            e = projectSettings.fullSizeUrl ? projectSettings.fullSizeUrl : window.location.href,
701            s = t.html().replace(/\[URL\]/g, a).replace(/\[SOURCE_URL\]/g, a).replace(/\[BRAND_URL\]/g, i).replace(/\[FULL_SIZE_URL\]/g, e).replace(/\[BRAND\]/g, projectSettings.brandTitle).replace(/\[FRAME_WIDTH\]/g, projectSettings.frameWidth ? projectSettings.frameWidth : "100%").replace(/\[FRAME_HEIGHT\]/g, projectSettings.frameHeight);
702        t.html(s);
703        var n = $(".site_link");
704        n.each(function () {
705            $(this).attr("href", projectSettings.brandUrl).attr("target", "_blank")
706        })
707    } else console.log("no project settings");
708    t.on("click", function () {
709        $(this).select()
710    })
711};
712
713
714$('.close-embed').on('click touch', function(){
715    $('body').removeClass('modal-open');
716    $('#embedModal').removeClass('active');
717    $('.modal-backdrop').remove();
718})
719
720
721
722$('#openembed').on('click touch', function(){
723    $('#embedModal').addClass('active');
724    embedThis();
725})
726        if ($('#embedModal').length){  embedThis(); }
727        
728        if (projectSettings.google_analytics.match('UA-')) {
729            // Google Analytics: change UA-XXXXX-X to be your site's ID.
730            (function (b, o, i, l, e, r) {
731                b.GoogleAnalyticsObject = l;
732                b[l] || (b[l] = function () {
733                    (b[l].q = b[l].q || []).push(arguments)
734                });
735                b[l].l = +new Date;
736                e = o.createElement(i);
737                r = o.getElementsByTagName(i)[0];
738                e.src = 'https://www.google-analytics.com/analytics.js';
739                r.parentNode.insertBefore(e, r)
740            }(window, document, 'script', 'ga'));
741            ga('create', projectSettings.google_analytics);
742            ga('send', 'pageview');
743            
744            if ($('.notice').length){
745                console.log('notice is true');
746                $('.notice i').on('touch click', function(){
747                    $('.notice').addClass('disabled');
748                })
749            }
750        }
751
752    });
753        
754   
755      </script>
755
756         <!--// export-->
757
758    </body>
759</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.