-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathquote.html
More file actions
2036 lines (1916 loc) · 101 KB
/
Copy pathquote.html
File metadata and controls
2036 lines (1916 loc) · 101 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!DOCTYPE html>
<html lang="en-US">
<head>
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; style-src 'self' 'unsafe-inline'; font-src 'self' data:; img-src 'self' data: https:; script-src 'self' 'unsafe-inline'; connect-src 'self' https://formsubmit.co; form-action 'self'">
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="Request a quote from ShieldBox Security — professional event security in Philadelphia. Fill out the intake form and ShieldBox operations reviews every request personally.">
<title>Request a Quote | ShieldBox Security</title>
<link rel="icon" type="image/svg+xml" href="assets/icons/favicon/favicon.svg">
<link rel="icon" type="image/png" sizes="32x32" href="assets/icons/favicon/favicon-32.png" />
<link rel="icon" type="image/png" sizes="16x16" href="assets/icons/favicon/favicon-16.png" />
<link rel="apple-touch-icon" sizes="180x180" href="assets/icons/favicon/apple-touch-icon.png" />
<meta property="og:title" content="ShieldBox Security | Philadelphia Event Security">
<meta property="og:description" content="Request a quote for professional event security services in Philadelphia from ShieldBox Security.">
<meta property="og:type" content="website">
<meta property="og:url" content="https://shieldboxsecurity.com/quote.html">
<meta property="og:image" content="https://shieldboxsecurity.com/assets/icons/favicon/android-chrome-512.png">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="ShieldBox Security | Philadelphia Event Security">
<meta name="twitter:description" content="Request a quote for professional event security services in Philadelphia from ShieldBox Security.">
<meta name="twitter:image" content="https://shieldboxsecurity.com/assets/icons/favicon/android-chrome-512.png">
<link rel="canonical" href="https://shieldboxsecurity.com/quote.html">
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": ["LocalBusiness", "SecurityService"],
"name": "ShieldBox Security",
"legalName": "ShieldBox Security LLC",
"description": "Professional, armed and unarmed event security in Philadelphia. Trained personnel, visible presence, and disciplined protection for events, venues, and private clients.",
"url": "https://shieldboxsecurity.com/",
"email": "shieldbox.sec@gmail.com",
"telephone": "+1-267-276-5287",
"address": {
"@type": "PostalAddress",
"addressLocality": "Philadelphia",
"addressRegion": "PA",
"addressCountry": "US"
},
"areaServed": [
{ "@type": "City", "name": "Philadelphia", "sameAs": "https://en.wikipedia.org/wiki/Philadelphia" },
{ "@type": "State", "name": "Pennsylvania" }
],
"contactPoint": [
{
"@type": "ContactPoint",
"contactType": "sales",
"email": "shieldbox.sec@gmail.com",
"telephone": "+1-267-276-5287",
"areaServed": ["PA"],
"availableLanguage": ["English"]
}
],
"serviceType": ["Event Security", "Crowd Management", "Talent Protection", "Overnight Watch"],
"priceRange": "$$"
}
</script>
<link rel="stylesheet" href="css/fonts.css" />
<link rel="stylesheet" href="css/shared.css">
<link rel="stylesheet" href="css/quote-form.css">
</head>
<body>
<a class="skip-link" href="#intakeForm">Skip to intake form</a>
<nav class="site-nav" aria-label="Main navigation">
<a href="index.html" class="nav-back">← Back to ShieldBox</a>
<a class="nav-brand" href="index.html">
<svg width="24" height="28" viewBox="0 0 48 56" fill="none" aria-hidden="true">
<path d="M24 2C24 2 4 10 4 10V28C4 42 14 52 24 54C34 52 44 42 44 28V10L24 2Z" stroke="var(--ink)" stroke-width="1.8" fill="none" />
<path d="M24 10C24 10 10 16 10 16V28C10 38 16 46 24 48C32 46 38 38 38 28V16L24 10Z" stroke="var(--ink)" stroke-width="1.4" fill="none" opacity="0.55" />
</svg>
<span class="nav-wordmark">shield<span>box</span></span>
</a>
<div class="nav-links">
<a href="index.html#services" class="nav-link-desktop">Services</a>
<a href="event-quote-request.html" class="nav-link-desktop">Brief Example</a>
</div>
<button class="nav-toggle" type="button" aria-expanded="false" aria-controls="navPanel" aria-label="Open menu">
<span class="nav-toggle-bar" aria-hidden="true"></span>
<span class="nav-toggle-bar" aria-hidden="true"></span>
<span class="nav-toggle-bar" aria-hidden="true"></span>
</button>
<div class="nav-panel" id="navPanel">
<a href="index.html">Home</a>
<a href="index.html#services">Services</a>
<a href="event-quote-request.html">Brief Example</a>
<a href="tel:+12672765287" class="nav-panel-contact">Call +1 267-276-5287</a>
<a href="mailto:shieldbox.sec@gmail.com" class="nav-panel-contact">shieldbox.sec@gmail.com</a>
</div>
</nav>
<noscript>
<style>
/* Without JS the hamburger cannot open, so fall back to showing the
links inline rather than leaving the nav unusable. */
@media (max-width: 640px) {
.nav-toggle { display: none !important; }
.nav-link-desktop { display: inline-flex !important; }
}
</style>
</noscript>
<!-- =========================================================
QUOTE REQUEST (standalone page)
========================================================= -->
<div class="quote-section quote-section-standalone" id="quoteStart">
<div class="layout">
<div class="stack">
<!-- DIRECT OPS CONTACT -->
<section class="section" aria-labelledby="summaryHeading">
<div class="section-head">
<span class="section-icon">R</span>
<h2 id="summaryHeading" class="section-title">ShieldBox Intake Desk</h2>
<span class="section-note">Direct Contact</span>
</div>
<div class="section-body">
<div class="property-grid">
<div class="property">
<div class="property-label">Intake Email</div>
<div class="property-value"><a href="mailto:shieldbox.sec@gmail.com">shieldbox.sec@gmail.com</a></div>
</div>
<div class="property">
<div class="property-label">Intake Phone</div>
<div class="property-value"><a href="tel:+12672765287">+1 267-276-5287</a></div>
</div>
<div class="property">
<div class="property-label">Review Process</div>
<div class="property-value">Every request reviewed personally</div>
</div>
<div class="property">
<div class="property-label">Service Focus</div>
<div class="property-value">Private events, concerts, and corporate gatherings</div>
</div>
<div class="property">
<div class="property-label">Proposal Delivery</div>
<div class="property-value">Itemized staffing and pricing recommendation</div>
</div>
</div>
<div class="notes-box">
<div class="notes-title">Submission Routing</div>
<p class="notes-copy">Use the form below to send your event requirements directly to ShieldBox operations. Include venue restrictions, insurance requirements, and any production contacts so the final quote can be turned around without follow-up delays.</p>
</div>
</div>
</section>
<!-- CLIENT & EVENT -->
<section class="section" id="overview" aria-labelledby="overviewHeading">
<div class="section-head">
<span class="section-icon">A</span>
<h2 id="overviewHeading" class="section-title">Client & Event Overview</h2>
</div>
<div class="section-body">
<nav class="progress-bar" id="progressBar" aria-label="Quote progress">
<a href="#overview" class="progress-step" data-track="contact" aria-label="Contact"><span class="step-dot"></span><span>Contact</span></a>
<span class="progress-sep"></span>
<a href="#schedule" class="progress-step" data-track="schedule" aria-label="Schedule"><span class="step-dot"></span><span>Schedule</span></a>
<span class="progress-sep"></span>
<a href="#scope" class="progress-step" data-track="scope" aria-label="Scope"><span class="step-dot"></span><span>Scope</span></a>
<span class="progress-sep"></span>
<a href="#billing" class="progress-step" data-track="billing" aria-label="Billing"><span class="step-dot"></span><span>Billing</span></a>
<span class="progress-sep"></span>
<a href="#next" class="progress-step" data-track="submit" aria-label="Submit"><span class="step-dot"></span><span>Submit</span></a>
</nav>
<div class="intake-restore" id="intakeRestore" hidden>
<span>Welcome back. Restore your last contact details and playbook?</span>
<button class="tiny-action" id="restoreFieldsBtn" type="button">Restore</button>
<button class="tiny-action" id="dismissRestoreBtn" type="button">Dismiss</button>
</div>
<section class="playbook-panel" aria-labelledby="playbookHeading">
<div class="playbook-head">
<div>
<div class="playbook-eyebrow">One Click Event Playbooks</div>
<h3 class="playbook-title" id="playbookHeading">Start from a coverage pattern</h3>
</div>
<p class="playbook-copy">Apply a proven starting point, then adjust any field before you send the request.</p>
</div>
<div class="playbook-grid" id="playbookGrid" role="list" aria-label="Event playbooks"></div>
<p class="playbook-applied" id="playbookApplied" hidden></p>
</section>
<form id="intakeForm" class="intake-form" novalidate aria-labelledby="intakeFormTitle">
<h3 id="intakeFormTitle" class="form-title">Required Intake Fields</h3>
<p class="form-help">Complete the required values below. When you submit, the intake routes directly to ShieldBox ops at <a href="mailto:shieldbox.sec@gmail.com">shieldbox.sec@gmail.com</a>. For time sensitive coordination, call <a href="tel:+12672765287">+1 267-276-5287</a>.</p>
<div class="form-grid">
<div class="form-field">
<label for="fieldName">Name</label>
<input id="fieldName" name="name" type="text" required autocomplete="name" placeholder="Primary contact full name" aria-describedby="errFieldName" />
<p id="errFieldName" class="field-note field-error" hidden></p>
</div>
<div class="form-field">
<label for="fieldPhone">Phone</label>
<input id="fieldPhone" name="phone" type="tel" required autocomplete="tel" placeholder="Best callback number" pattern="[\d\s\-\+\(\)]{7,20}" title="Phone number" aria-describedby="errFieldPhone" />
<p id="errFieldPhone" class="field-note field-error" hidden></p>
</div>
<div class="form-field">
<label for="fieldEmail">Email</label>
<input id="fieldEmail" name="email" type="email" required autocomplete="email" placeholder="name@company.com" aria-describedby="errFieldEmail emailSuggestion" />
<p id="errFieldEmail" class="field-note field-error" hidden></p>
<p id="emailSuggestion" class="field-note is-warn" hidden></p>
</div>
<div class="form-field">
<label for="fieldLeadSource">How did you hear about us?</label>
<select id="fieldLeadSource" name="lead_source">
<option value="" selected>Select one (optional)</option>
<option value="Google search">Google search</option>
<option value="Referral / word of mouth">Referral / word of mouth</option>
<option value="Social media">Social media</option>
<option value="Venue recommendation">Venue recommendation</option>
<option value="Worked with ShieldBox before">Worked with ShieldBox before</option>
<option value="Other">Other</option>
</select>
</div>
<div class="form-field">
<label for="fieldDate">Event Date</label>
<input id="fieldDate" name="event_date" type="date" required aria-describedby="errFieldDate" />
<p id="errFieldDate" class="field-note field-error" hidden></p>
</div>
<div class="form-field">
<label for="fieldLocation">Event Location</label>
<input id="fieldLocation" name="event_location" type="text" required placeholder="Venue name or full street address" aria-describedby="errFieldLocation" />
<p id="errFieldLocation" class="field-note field-error" hidden></p>
</div>
<div class="form-field">
<label for="fieldDuration">Event Duration</label>
<input id="fieldDuration" name="event_duration" type="number" min="1" max="72" step="0.5" required placeholder="e.g. 4" aria-describedby="errFieldDuration durationHint durationFormatNote" />
<p id="errFieldDuration" class="field-note field-error" hidden></p>
<p id="durationHint" class="field-note">Hours on site (half-hour increments)</p>
<p id="durationFormatNote" class="field-note is-warn" hidden>Use decimal hours, e.g. 2.5 for 2 hours 30 minutes</p>
</div>
<div class="form-field">
<label for="fieldAttendance">Expected Attendance</label>
<input id="fieldAttendance" name="expected_attendance" type="number" min="1" max="10000" required placeholder="Estimated guest count" aria-describedby="errFieldAttendance attendanceWarning" />
<p id="errFieldAttendance" class="field-note field-error" hidden></p>
<p id="attendanceWarning" class="field-note is-warn" hidden>Large event — custom quote recommended</p>
</div>
<div class="form-field">
<label for="fieldEventType">Event Type</label>
<select id="fieldEventType" name="event_type" required aria-describedby="errFieldEventType">
<option value="" disabled selected>Select event type</option>
<option value="Corporate / Conference">Corporate / Conference</option>
<option value="Concert / Live Music">Concert / Live Music</option>
<option value="Private Party / Wedding">Private Party / Wedding</option>
<option value="Festival / Outdoor Event">Festival / Outdoor Event</option>
<option value="Sporting Event">Sporting Event</option>
<option value="Nonprofit / Fundraiser">Nonprofit / Fundraiser</option>
<option value="Trade Show / Expo">Trade Show / Expo</option>
<option value="Other">Other</option>
</select>
<p id="errFieldEventType" class="field-note field-error" hidden></p>
</div>
<div class="form-field">
<label for="fieldVenueType">Indoor / Outdoor</label>
<select id="fieldVenueType" name="venue_type" required aria-describedby="errFieldVenueType">
<option value="" disabled selected>Select venue type</option>
<option value="Indoor">Indoor</option>
<option value="Outdoor">Outdoor</option>
<option value="Mixed (Indoor + Outdoor)">Mixed (Indoor + Outdoor)</option>
</select>
<p id="errFieldVenueType" class="field-note field-error" hidden></p>
</div>
</div>
<details class="optional-fields">
<summary>
Add optional organizer details
<span>Organization name and internal event name are helpful, but not required to get the request submitted.</span>
</summary>
<div class="optional-fields-body">
<div class="form-grid">
<div class="form-field">
<label for="fieldOrganization">Organization / Client</label>
<input id="fieldOrganization" name="organization" type="text" autocomplete="organization" placeholder="Company, venue group, or private client" />
</div>
<div class="form-field">
<label for="fieldEventName">Event Name</label>
<input id="fieldEventName" name="event_name" type="text" placeholder="Show, conference, or private event name" />
</div>
</div>
</div>
</details>
<div class="visually-hidden" aria-hidden="true">
<label for="fieldWebsiteTrap">Website</label>
<input id="fieldWebsiteTrap" name="company_url" type="text" tabindex="-1" autocomplete="off" aria-hidden="true" />
<input type="hidden" id="fieldSubmissionToken" name="_token" value="" />
</div>
<input name="_subject" type="hidden" value="ShieldBox Quote Request" />
<div class="form-actions">
<button id="validateIntakeButton" class="tiny-action" type="button">Check Required Fields</button>
<p id="validationMessage" class="validation-msg" role="status" aria-live="polite"></p>
<p id="nextPrompt" class="next-prompt" hidden></p>
</div>
</form>
<div class="simple-table-wrap">
<table class="simple-table" aria-label="Client and event overview">
<thead>
<tr>
<th scope="col">Field</th>
<th scope="col">Client Input</th>
</tr>
</thead>
<tbody>
<tr><td>Organization / Client</td><td id="summaryOrganization">—</td></tr>
<tr><td>Point of Contact</td><td id="summaryName">—</td></tr>
<tr><td>Email</td><td id="summaryEmail">—</td></tr>
<tr><td>Phone</td><td id="summaryPhone">—</td></tr>
<tr><td>Event Name</td><td id="summaryEventName">—</td></tr>
<tr><td>Event Type</td><td id="summaryEventType">General event security request</td></tr>
<tr><td>Venue Address</td><td id="summaryLocation">—</td></tr>
<tr><td>Indoor / Outdoor</td><td id="summaryVenueType">—</td></tr>
<tr><td>Event Date</td><td id="summaryDate">—</td></tr>
<tr><td>Expected Attendance</td><td id="summaryAttendance">—</td></tr>
<tr><td>Coverage Hours</td><td id="summaryDuration">—</td></tr>
<tr><td>Alcohol Served</td><td id="summaryAlcohol">Not specified in intake</td></tr>
<tr><td>VIP or Talent Present</td><td id="summaryVip">No VIP / talent coverage selected</td></tr>
</tbody>
</table>
</div>
<div class="core-fields" aria-label="Core fields">
<span class="core-chip">Name</span>
<span class="core-chip">Phone</span>
<span class="core-chip">Email</span>
<span class="core-chip">Event Date</span>
<span class="core-chip">Event Location</span>
<span class="core-chip">Event Duration</span>
<span class="core-chip">Expected Attendance</span>
<span class="core-chip">Event Type</span>
<span class="core-chip">Indoor / Outdoor</span>
</div>
</div>
</section>
<!-- SCHEDULE -->
<section class="section" id="schedule" aria-labelledby="scheduleHeading">
<div class="section-head">
<span class="section-icon">B</span>
<h2 id="scheduleHeading" class="section-title">Schedule & Logistics</h2>
</div>
<div class="section-body">
<p class="intro-copy">Please list the specific windows where ShieldBox presence is required.</p>
<div class="check-grid" role="group" aria-label="Schedule coverage checklist">
<label class="check-item">
<input id="schedule_loadin" type="checkbox" name="schedule_loadin" checked />
<span>
<span class="check-label">Load-In / Setup</span>
<span class="check-copy">Pre-event setup and equipment staging window</span>
</span>
</label>
<label class="check-item">
<input id="schedule_doors" type="checkbox" name="schedule_doors" checked />
<span>
<span class="check-label">Main Event Doors</span>
<span class="check-copy">Guest arrival and credential verification</span>
</span>
</label>
<label class="check-item">
<input id="schedule_coverage" type="checkbox" name="schedule_coverage" checked />
<span>
<span class="check-label">Event Coverage Window</span>
<span class="check-copy">Active event security coverage period</span>
</span>
</label>
<label class="check-item">
<input id="schedule_loadout" type="checkbox" name="schedule_loadout" checked />
<span>
<span class="check-label">Load-Out / Strike</span>
<span class="check-copy">Post-event teardown and venue clear</span>
</span>
</label>
<label class="check-item">
<input id="schedule_overnight" type="checkbox" name="schedule_overnight" checked />
<span>
<span class="check-label">Overnight Gear Watch</span>
<span class="check-copy">Overnight equipment and venue monitoring</span>
</span>
</label>
</div>
<aside class="tip-box" aria-label="Schedule tip">
Tip: Use the format Date | Start - End (example: Mar 28, 2026 | 12:00 PM - 4:00 PM).
</aside>
</div>
</section>
<!-- SCOPE -->
<section class="section" id="scope" aria-labelledby="scopeHeading">
<div class="section-head">
<span class="section-icon">C</span>
<h2 id="scopeHeading" class="section-title">Security Scope</h2>
</div>
<div class="section-body">
<p class="intro-copy">Select the primary functions required.</p>
<div class="check-grid" role="group" aria-label="Security scope checklist">
<label class="check-item">
<input id="scope_access" type="checkbox" name="scope_access" value="Access Control" />
<span>
<span class="check-label">Access Control</span>
<span class="check-copy">VIP areas, backstage, and credentials.</span>
<span class="scope-suggest" hidden data-scope-suggest="access">Suggested for this event size</span>
</span>
</label>
<label class="check-item">
<input id="scope_frontofhouse" type="checkbox" name="scope_frontofhouse" value="Front of House" />
<span>
<span class="check-label">Front of House</span>
<span class="check-copy">Entry screening, bag checks, and metal detection.</span>
<span class="scope-suggest" hidden data-scope-suggest="frontofhouse">Suggested for this event size</span>
</span>
</label>
<label class="check-item">
<input id="scope_perimeter" type="checkbox" name="scope_perimeter" value="Perimeter" />
<span>
<span class="check-label">Perimeter</span>
<span class="check-copy">Roaming patrols to secure the venue boundary.</span>
<span class="scope-suggest" hidden data-scope-suggest="perimeter">Suggested for 500+ guests</span>
</span>
</label>
<label class="check-item">
<input id="scope_talent" type="checkbox" name="scope_talent" value="Talent or Executive Protection" />
<span>
<span class="check-label">Talent or Executive Protection</span>
<span class="check-copy">Dedicated 1-on-1 escort for speakers or artists.</span>
<span class="scope-suggest" hidden data-scope-suggest="talent">Suggested for this event size</span>
</span>
</label>
<label class="check-item">
<input id="scope_crowd" type="checkbox" name="scope_crowd" value="Crowd Management" />
<span>
<span class="check-label">Crowd Management</span>
<span class="check-copy">High-density area monitoring and de-escalation.</span>
<span class="scope-suggest" hidden data-scope-suggest="crowd">Suggested for 500+ guests</span>
</span>
</label>
</div>
</div>
</section>
<!-- RISK -->
<section class="section" id="risk" aria-labelledby="riskHeading">
<div class="section-head">
<span class="section-icon">D</span>
<h2 id="riskHeading" class="section-title">Security Risk Snapshot</h2>
<span class="section-note">Auto Assessed</span>
</div>
<div class="section-body">
<div class="risk-grid" role="list" aria-label="Risk factors">
<div class="risk-item" role="listitem"><span class="risk-name">Crowd Density</span><span class="risk-level is-medium" id="riskAttendance">MEDIUM</span></div>
<div class="risk-item" role="listitem"><span class="risk-name">Alcohol</span><span class="risk-level is-medium" id="riskAlcohol">MEDIUM</span></div>
<div class="risk-item" role="listitem"><span class="risk-name">Duration</span><span class="risk-level is-medium" id="riskCrowd">MEDIUM</span></div>
<div class="risk-item" role="listitem"><span class="risk-name">Access Complexity</span><span class="risk-level is-medium" id="riskVenueComplexity">MEDIUM</span></div>
<div class="risk-item" role="listitem"><span class="risk-name">Overall Profile</span><span class="risk-level is-medium" id="riskOverall">MEDIUM</span></div>
</div>
<div class="recommend-box">
<div class="recommend-title">Recommended Coverage</div>
<div class="recommend-list">
<div class="recommend-row"><span>1 Site Lead</span><span id="staffSiteLead">x1</span></div>
<div class="recommend-row"><span>Event Security</span><span id="staffEventSecurity">x4</span></div>
<div class="recommend-row"><span>Entry Screeners</span><span id="staffEntryScreeners">x2</span></div>
<div class="recommend-row"><span>Overnight Watch</span><span id="staffOvernight">x1</span></div>
</div>
<p class="recommend-note" id="recommendNote">Preliminary staffing recommendation generated from intake signals. Final staffing is confirmed during ops review.</p>
</div>
</div>
</section>
<!-- BILLING -->
<section class="section" id="billing" aria-labelledby="billingHeading">
<div class="section-head">
<span class="section-icon">E</span>
<h2 id="billingHeading" class="section-title">Billing Preference</h2>
</div>
<div class="section-body">
<div class="billing-table-wrap">
<table class="billing-table" aria-label="Billing model selection">
<thead>
<tr>
<th scope="col">Model</th>
<th scope="col">Description</th>
<th scope="col">Selection</th>
</tr>
</thead>
<tbody id="billingRows" aria-label="Billing preference options">
<tr class="billing-row" data-model="hourly" data-rate="42">
<td><div class="billing-model">Hourly Rate <span class="billing-fit-tag" id="fitHourly" hidden>Best fit</span></div></td>
<td><div class="billing-desc">Best for flexible schedules — billed per guard, per hour</div></td>
<td>
<label class="billing-choice">
<input class="billing-input" type="radio" name="billingModel" value="hourly" />
<span class="billing-choice-text">Select</span>
</label>
</td>
</tr>
<tr class="billing-row" data-model="person" data-rate="40.625">
<td><div class="billing-model">Per Guard / Shift <span class="billing-fit-tag" id="fitPerson" hidden>Best fit</span></div></td>
<td><div class="billing-desc">Fixed cost per guard per 8-hour shift</div></td>
<td>
<label class="billing-choice">
<input class="billing-input" type="radio" name="billingModel" value="person" />
<span class="billing-choice-text">Select</span>
</label>
</td>
</tr>
<tr class="billing-row is-selected" data-model="flat" data-rate="368.75">
<td><div class="billing-model">Flat Event Rate <span class="billing-fit-tag" id="fitFlat" hidden>Best fit</span></div></td>
<td><div class="billing-desc">All-inclusive single price for the full run</div></td>
<td>
<label class="billing-choice">
<input class="billing-input" type="radio" name="billingModel" value="flat" checked />
<span class="billing-choice-text">Selected</span>
</label>
</td>
</tr>
</tbody>
</table>
</div>
<p class="billing-note">Final proposal pricing may vary based on site conditions, revised scope, venue rules, and client-driven schedule changes.</p>
<a href="#next" class="billing-next-link">Continue to final submission step</a>
</div>
</section>
<!-- PROMISE -->
<section class="promise-card" id="promise" aria-labelledby="promiseHeading">
<h2 class="promise-title" id="promiseHeading">Our Mission</h2>
<p class="promise-lead">Dependable, professional security that prioritizes safety, prevention, and peace of mind.</p>
<div class="promise-points">
<div>Maintaining a strong, visible presence to deter potential threats.</div>
<div>Responding quickly and effectively to any situation.</div>
<div>Representing our clients with professionalism and respect.</div>
<div>Creating safe environments without unnecessary force or escalation.</div>
</div>
<p class="promise-copy">ShieldBox Security was founded to raise the standard of professionalism in the security industry. Starting with a small, dedicated team, we built a reputation for being dependable, proactive, and ready to handle high-pressure situations. Every step of our growth has been driven by doing things the right way — staying alert, acting professionally, and putting the client first.</p>
</section>
<!-- NEXT STEP -->
<section class="next-step" id="next" aria-labelledby="nextHeading">
<h2 class="next-title" id="nextHeading">Next Step</h2>
<p class="next-copy">When you send your quote request, your intake routes directly to <a href="mailto:shieldbox.sec@gmail.com">shieldbox.sec@gmail.com</a>. If you need to flag an urgent change after submission, call <a href="tel:+12672765287">+1 267-276-5287</a>. ShieldBox reviews every request manually and follows up <strong>personally</strong>.</p>
<div class="next-actions">
<button id="requestButton" class="cta" type="submit" form="intakeForm" data-track="quote-form-submit">Submit</button>
<button id="previewBriefButton" class="cta cta-secondary" type="button">Preview Brief</button>
<button id="printButton" class="cta cta-secondary" type="button">Download as PDF</button>
</div>
<p class="next-helper">One primary action from here: submit the request. Everything above simply improves pricing accuracy and speeds ops review.</p>
<div class="next-turnaround">Manual review on every request | Ref: <span id="referencePreview">—</span></div>
</section>
</div>
<!-- SIDEBAR -->
<aside class="side-stack" aria-label="Quick reference">
<section class="side-card" aria-labelledby="quickNavHeading">
<h2 id="quickNavHeading" class="side-title">Quick Nav</h2>
<nav class="side-list" aria-label="Section quick links">
<a href="#overview">Client & Event</a>
<a href="#schedule">Schedule</a>
<a href="#scope">Scope</a>
<a href="#risk">Risk Snapshot</a>
<a href="#billing">Billing</a>
<a href="#promise">Promise</a>
<a href="#next">Next Step</a>
</nav>
</section>
<section class="side-card" aria-labelledby="summaryHeadingAside">
<h2 id="summaryHeadingAside" class="side-title">Summary</h2>
<ul class="summary-list">
<li>Capture the venue, contact, and event basics for ops review.</li>
<li>Define coverage windows per phase (load-in, doors, strike, overnight).</li>
<li>Select primary security functions for the quote.</li>
<li>Pick billing model to anchor the proposal.</li>
</ul>
<div class="summary-estimate">
<div class="summary-estimate-label">Estimated Range</div>
<div class="summary-estimate-value" id="summaryEstimateRange">$2,000 – $3,000</div>
<p class="summary-estimate-note" id="summaryEstimateNote">Typical starting range — varies by hours, guard count, and scope. Final pricing confirmed after review.</p>
</div>
</section>
</aside>
</div>
<div class="submission-confirmation" id="submissionConfirmation" hidden aria-hidden="true" inert>
<section class="section" aria-labelledby="confirmationHeading">
<div class="section-head">
<span class="section-icon">✓</span>
<h2 id="confirmationHeading" class="section-title" tabindex="-1">Quote Request Accepted</h2>
<span class="section-note">Proposal Queue</span>
</div>
<div class="section-body">
<p class="confirm-lead">Your intake was accepted for delivery to ShieldBox operations. Keep the reference below for any updates, venue addenda, or insurance requests you send after this step.</p>
<div class="confirm-reference" id="confirmationReference">SBX-00000000-0000</div>
<div class="confirm-grid">
<div class="confirm-item">
<div class="confirm-label">Ops Email</div>
<div class="confirm-value"><a href="mailto:shieldbox.sec@gmail.com">shieldbox.sec@gmail.com</a></div>
</div>
<div class="confirm-item">
<div class="confirm-label">Ops Phone</div>
<div class="confirm-value"><a href="tel:+12672765287">+1 267-276-5287</a></div>
</div>
<div class="confirm-item">
<div class="confirm-label">Follow-Up Window</div>
<div class="confirm-value">A ShieldBox team member will follow up personally.</div>
</div>
<div class="confirm-item">
<div class="confirm-label">Reply Contact</div>
<div class="confirm-value" id="confirmationClientEmail">—</div>
</div>
</div>
<p class="confirm-copy">If anything changes before the final quote is issued, email <a href="mailto:shieldbox.sec@gmail.com">shieldbox.sec@gmail.com</a> or call <a href="tel:+12672765287">+1 267-276-5287</a> and include the reference above so operations can update the same request.</p>
<div class="confirm-actions">
<button id="previewConfirmationButton" class="cta cta-secondary" type="button">Preview Brief</button>
<button id="printConfirmationButton" class="cta cta-secondary" type="button">Download as PDF</button>
<button id="newRequestButton" class="cta" type="button">Start Another Quote</button>
</div>
</div>
</section>
</div>
</div>
</div>
<footer class="site-footer">
<div class="footer-brand">
<div class="footer-name">ShieldBox Security</div>
<address>
Philadelphia, PA & surrounding counties<br />
<a id="footerEmail" href="#"></a><br />
<a href="tel:+12672765287">+1 267-276-5287</a>
</address>
Based in Philadelphia, serving Pennsylvania. Out-of-state events considered case-by-case, subject to state licensing.
</div>
<div class="footer-note">
Protect people. Support our clients. Uphold a standard of professionalism our clients can count on.<br />
Quote requests are reviewed manually and followed up personally.
</div>
</footer>
<div id="toast" role="status" aria-live="polite" aria-atomic="true" hidden>
<strong id="toastTitle">Submission status</strong>
<span id="toastMessage">Please try again or email shieldbox.sec@gmail.com or call +1 267-276-5287.</span>
</div>
<script src="js/nav.js" defer></script>
<script>
(() => {
/* ---- Motion helpers ---- */
const reduceMotionQuery = window.matchMedia("(prefers-reduced-motion: reduce)");
const feedbackTimers = new WeakMap();
function flashFeedback(el, kind = "success") {
if (!el) return;
const klass = kind === "error" ? "feedback-error" : "feedback-success";
el.classList.remove("feedback-success", "feedback-error");
void el.offsetWidth;
el.classList.add(klass);
if (feedbackTimers.has(el)) clearTimeout(feedbackTimers.get(el));
feedbackTimers.set(el, setTimeout(() => {
el.classList.remove(klass);
feedbackTimers.delete(el);
}, reduceMotionQuery.matches ? 20 : 200));
}
function bindPressFeedback(selector) {
document.querySelectorAll(selector).forEach(el => {
if (el.dataset.pressBound === "true") return; /* camelCase "pressBound" becomes data-press-bound in DOM */
el.dataset.pressBound = "true";
const release = () => el.classList.remove("is-pressing");
el.addEventListener("pointerdown", event => {
if (event.pointerType === "mouse" && event.button !== 0) return;
el.classList.add("is-pressing");
});
el.addEventListener("pointerup", release);
el.addEventListener("pointerleave", release);
el.addEventListener("pointercancel", release);
el.addEventListener("blur", release);
el.addEventListener("keyup", release);
el.addEventListener("keydown", event => {
if (event.key === " " || event.key === "Enter") el.classList.add("is-pressing");
});
});
}
function markFieldState(field, state) {
const wrapper = field && field.closest(".form-field");
if (!wrapper) return;
wrapper.classList.remove("is-success", "is-error");
if (state === "success") wrapper.classList.add("is-success");
if (state === "error") wrapper.classList.add("is-error");
/* Announce the failure to assistive tech, not just the eye. Without this
a screen reader user hears the label and nothing about what is wrong,
so the error is unreachable and the form cannot be completed. */
if (!field.willValidate) return;
const errorNote = document.getElementById(`err${field.id.charAt(0).toUpperCase()}${field.id.slice(1)}`);
if (state === "error") {
field.setAttribute("aria-invalid", "true");
if (errorNote) {
errorNote.textContent = field.validationMessage || "This field needs attention.";
errorNote.hidden = false;
}
} else {
field.removeAttribute("aria-invalid");
if (errorNote) {
errorNote.textContent = "";
errorNote.hidden = true;
}
}
}
bindPressFeedback(".nav-back, .nav-links a, .nav-feature, .nav-cta, .btn, .gallery-card, .svc-card, .quote-flow-step, .side-list a, .progress-step, .tiny-action, .billing-row, #scope .check-item, .mobile-action-dock a");
/* Form validation */
const intakeForm = document.getElementById("intakeForm");
const validateBtn = document.getElementById("validateIntakeButton");
const valMsg = document.getElementById("validationMessage");
const fieldOrganization = document.getElementById("fieldOrganization");
const fieldEventName = document.getElementById("fieldEventName");
const fieldName = document.getElementById("fieldName");
const fieldPhone = document.getElementById("fieldPhone");
const fieldEmail = document.getElementById("fieldEmail");
const fieldDate = document.getElementById("fieldDate");
const fieldLocation = document.getElementById("fieldLocation");
const fieldDuration = document.getElementById("fieldDuration");
const fieldAttendance = document.getElementById("fieldAttendance");
const fieldEventType = document.getElementById("fieldEventType");
const fieldVenueType = document.getElementById("fieldVenueType");
const fieldSubmissionToken = document.getElementById("fieldSubmissionToken");
const durationFormatNote = document.getElementById("durationFormatNote");
const attendanceWarning = document.getElementById("attendanceWarning");
const emailSuggestion = document.getElementById("emailSuggestion");
const requestBtn = document.getElementById("requestButton");
const previewBriefButton = document.getElementById("previewBriefButton");
const printBtn = document.getElementById("printButton");
const quoteSection = document.getElementById("quoteStart");
const submissionConfirmation = document.getElementById("submissionConfirmation");
const confirmationHeading = document.getElementById("confirmationHeading");
const confirmationReference = document.getElementById("confirmationReference");
const confirmationClientEmail = document.getElementById("confirmationClientEmail");
const referencePreview = document.getElementById("referencePreview");
const previewConfirmationButton = document.getElementById("previewConfirmationButton");
const printConfirmationButton = document.getElementById("printConfirmationButton");
const newRequestButton = document.getElementById("newRequestButton");
const quoteLayout = quoteSection ? quoteSection.querySelector(".layout") : null;
const quoteOpeners = Array.from(document.querySelectorAll("[data-open-intake='true']"));
const toast = document.getElementById("toast");
const toastTitle = document.getElementById("toastTitle");
const toastMessage = document.getElementById("toastMessage");
const summaryOrganization = document.getElementById("summaryOrganization");
const summaryName = document.getElementById("summaryName");
const summaryEmail = document.getElementById("summaryEmail");
const summaryPhone = document.getElementById("summaryPhone");
const summaryEventName = document.getElementById("summaryEventName");
const summaryEventType = document.getElementById("summaryEventType");
const summaryLocation = document.getElementById("summaryLocation");
const summaryVenueType = document.getElementById("summaryVenueType");
const summaryDate = document.getElementById("summaryDate");
const summaryAttendance = document.getElementById("summaryAttendance");
const summaryDuration = document.getElementById("summaryDuration");
const summaryAlcohol = document.getElementById("summaryAlcohol");
const summaryVip = document.getElementById("summaryVip");
const summaryEstimateRange = document.getElementById("summaryEstimateRange");
const summaryEstimateNote = document.getElementById("summaryEstimateNote");
const playbookGrid = document.getElementById("playbookGrid");
const playbookApplied = document.getElementById("playbookApplied");
const opsEmail = "shieldbox.sec@gmail.com";
const opsPhoneDisplay = "+1 267-276-5287";
const formSubmitEndpoint = "https://formsubmit.co/ajax/shieldbox.sec@gmail.com";
const briefPreviewKey = "sb-live-brief-preview";
const briefPreviewUrl = "event-quote-request.html?preview=live";
const quoteHashes = new Set(["#quoteStart", "#overview", "#schedule", "#scope", "#risk", "#billing", "#next"]);
const billingCatalog = {
hourly: { label: "Hourly Rate", price: "Quoted after review", unit: "per guard / hr" },
person: { label: "Per Guard / Shift", price: "Quoted after review", unit: "per 8-hr shift" },
flat: { label: "Flat Event Rate", price: "Quoted after review", unit: "all-inclusive" }
};
const playbookConfigs = {
concert_doors: {
label: "Concert Doors",
description: "Entry control, floor coverage, and backstage movement for indoor live music rooms.",
eventType: "Concert / Live Music",
venueType: "Indoor",
eventName: "Concert Doors Coverage",
attendance: 650,
duration: 6,
billing: "flat",
schedule: ["schedule_loadin", "schedule_doors", "schedule_coverage", "schedule_loadout"],
scheduleWindows: {
schedule_loadin: "3 hours before doors",
schedule_doors: "Doors open coverage",
schedule_coverage: "Main performance window",
schedule_loadout: "Post-show exit and strike"
},
scope: ["scope_access", "scope_frontofhouse", "scope_crowd", "scope_talent"]
},
wedding_reception: {
label: "Wedding Reception",
description: "Guest entry, room presence, and discreet issue response for private receptions.",
eventType: "Private Party / Wedding",
venueType: "Indoor",
eventName: "Wedding Reception Coverage",
attendance: 180,
duration: 5,
billing: "hourly",
schedule: ["schedule_doors", "schedule_coverage", "schedule_loadout"],
scheduleWindows: {
schedule_doors: "Guest arrival and credential check",
schedule_coverage: "Reception coverage window",
schedule_loadout: "Vendor clear and venue wrap"
},
scope: ["scope_access", "scope_frontofhouse", "scope_crowd"]
},
corporate_conference: {
label: "Corporate Conference",
description: "Front desk control, speaker movement, and credential support across a full conference day.",
eventType: "Corporate / Conference",
venueType: "Indoor",
eventName: "Corporate Conference Coverage",
attendance: 320,
duration: 8,
billing: "person",
schedule: ["schedule_loadin", "schedule_doors", "schedule_coverage", "schedule_loadout"],
scheduleWindows: {
schedule_loadin: "Morning access and registration setup",
schedule_doors: "Guest and staff arrival",
schedule_coverage: "Session coverage window",
schedule_loadout: "Speaker exit and strike"
},
scope: ["scope_access", "scope_frontofhouse", "scope_talent"]
},
festival_perimeter: {
label: "Festival Perimeter",
description: "Outdoor perimeter control, crowd movement, and overnight asset watch for multi-zone events.",
eventType: "Festival / Outdoor Event",
venueType: "Outdoor",
eventName: "Festival Perimeter Coverage",
attendance: 1200,
duration: 10,
billing: "flat",
schedule: ["schedule_loadin", "schedule_doors", "schedule_coverage", "schedule_loadout", "schedule_overnight"],
scheduleWindows: {
schedule_loadin: "Vendor ingress and perimeter setup",
schedule_doors: "Public entry and bag check",
schedule_coverage: "Festival live operations",
schedule_loadout: "Public egress and strike",
schedule_overnight: "Overnight asset watch"
},
scope: ["scope_access", "scope_frontofhouse", "scope_perimeter", "scope_crowd"]
}
};
let currentReference = "";
let lastSuccessfulSubmissionAt = 0;
let isSubmitting = false;
let durationColonHint = false;
let selectedPlaybookKey = "";
if (fieldDate) fieldDate.min = new Date().toISOString().split("T")[0];
intakeForm.querySelectorAll("input, select, textarea").forEach(el => {
el.addEventListener("blur", () => {
el.classList.add("touched");
if (!el.willValidate) return;
if (el.checkValidity() && String(el.value || "").trim()) {
markFieldState(el, "success");
} else if (!el.checkValidity()) {
markFieldState(el, "error");
flashFeedback(el.closest(".form-field"), "error");
}
});
});
if (fieldSubmissionToken) {
fieldSubmissionToken.value = Array.from(crypto.getRandomValues(new Uint8Array(4))).map(byte => byte.toString(16).padStart(2, "0")).join("");
}
const riskAttendance = document.getElementById("riskAttendance");
const riskAlcohol = document.getElementById("riskAlcohol");
const riskCrowd = document.getElementById("riskCrowd");
const riskVenueComplexity = document.getElementById("riskVenueComplexity");
const riskOverall = document.getElementById("riskOverall");
const staffSiteLead = document.getElementById("staffSiteLead");
const staffEventSecurity = document.getElementById("staffEventSecurity");
const staffEntryScreeners = document.getElementById("staffEntryScreeners");
const staffOvernight = document.getElementById("staffOvernight");
const recommendNote = document.getElementById("recommendNote");
function setVal(text, state) {
valMsg.textContent = text;
valMsg.classList.remove("is-ok", "is-warn");
if (state) valMsg.classList.add(state);
}
function buildReference() {
const d = new Date();
const pad = n => String(n).padStart(2, "0");
const hex = Array.from(crypto.getRandomValues(new Uint8Array(3))).map(b => b.toString(16).padStart(2, "0")).join("").toUpperCase();
return `SBX-${d.getFullYear()}${pad(d.getMonth() + 1)}${pad(d.getDate())}-${hex}`;
}
function firstInvalidField() {
return Array.from(intakeForm.elements).find(el => el instanceof HTMLElement && el.willValidate && !el.checkValidity()) || null;
}
function fieldLabel(field) {
const label = field && field.labels && field.labels[0];
return label ? label.textContent.trim().replace(/\s+/g, " ") : "This field";
}
function runValidation({ report = false, scroll = false } = {}) {
const valid = intakeForm.checkValidity();
/* Mark every invalid field, not just the first. A screen reader user
tabbing the form needs each one to announce itself as invalid. */
const invalidFields = Array.from(intakeForm.elements).filter(
el => el instanceof HTMLElement && el.willValidate && !el.checkValidity()
);
invalidFields.forEach(el => markFieldState(el, "error"));
if (valid) {
setVal("All required intake fields are complete.", "is-ok");
return true;
}
/* Name the first offending field in the live region. The old message
said only "complete required fields", which gave a non-sighted user
no way to locate the problem. */
const invalidField = invalidFields[0] || firstInvalidField();
const reason = String(invalidField && invalidField.validationMessage || "required").replace(/\.\s*$/, "");
const detail = invalidField
? `${invalidFields.length} field${invalidFields.length === 1 ? "" : "s"} need attention. First: ${fieldLabel(invalidField)} — ${reason}.`
: "Please complete required fields before proposal handoff.";
setVal(detail, "is-warn");
if (invalidField) {
flashFeedback(invalidField.closest(".form-field"), "error");
if (scroll) goToSection(invalidField, invalidField);
else if (report) invalidField.focus({ preventScroll: true });
}
if (report) intakeForm.reportValidity();
return false;
}
function roundToNearest50(value) {
return Math.max(50, Math.round(value / 50) * 50);
}
function refreshSubmissionToken() {
if (!fieldSubmissionToken) return;
fieldSubmissionToken.value = Array.from(crypto.getRandomValues(new Uint8Array(4))).map(byte => byte.toString(16).padStart(2, "0")).join("");
}
function syncDurationFormatNote() {
if (!durationFormatNote) return;
durationFormatNote.hidden = !(durationColonHint || String(fieldDuration.value || "").includes(":"));
}
function syncAttendanceWarning() {
if (!attendanceWarning) return;
attendanceWarning.hidden = !(Number(fieldAttendance.value || 0) > 5000);
}
function syncReference() {
if (referencePreview) referencePreview.textContent = currentReference;
if (confirmationReference) confirmationReference.textContent = currentReference;
}
function formatDate(value) {
if (!value) return "—";
const parsed = new Date(`${value}T00:00:00`);
if (Number.isNaN(parsed.getTime())) return value;
return parsed.toLocaleDateString("en-US", {
month: "short",
day: "numeric",
year: "numeric"
});
}
function setNodeValue(node, value, href) {
if (!node) return;
node.textContent = "";
if (!value) {
node.textContent = "—";
return;
}
if (href) {
const link = document.createElement("a");
link.href = href;
link.textContent = value;
node.appendChild(link);
return;
}
node.textContent = value;
}
function goToSection(target, focusEl) {
const el = typeof target === "string" ? document.querySelector(target) : target;
if (!el) return;
const reduceMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
el.scrollIntoView({ behavior: reduceMotion ? "auto" : "smooth", block: "start" });
if (focusEl) {
requestAnimationFrame(() => focusEl.focus({ preventScroll: true }));
}
}
function expandQuoteDesk({ scroll = true, focusField = true } = {}) {
if (!quoteSection) return;
quoteSection.classList.add("is-expanded");
if (quoteLayout) {