ReviewOS

also looking at this

stacks/lastsoulultra

LSU's own coaching surface, and what auditing the site turned up

#12
Merged glennmichael123 wants to merge claude/last-soul-ultra-web-6e0718 into main
86 files +3943 -1190

Review threads live on the whole diff, not on one commit, so none are shown here - a thread's line means something in the branch's final form, and painting it into an intermediate step would put it on code it is not about.

resources/views/contact.stx resources/partials/contact-body.stxcopied+6-8
Changes to resources/partials/contact-body.stx
@@ -1,10 +1,9 @@
1@extends('layouts/LSU')
2@section('content')
3<script server>
4import { productionPages } from '~/resources/data/production-pages'
5const currentPage = productionPages["/contact"]
6const canonicalPath = "/contact"
7</script>
1{{-- The questions page, shared by /contact and /faq.
2
3 The two views were byte-identical 238-line files. Both URLs are published
4 and both are linked from elsewhere, so neither can simply go; what could
5 go is the second copy of the answers, which is the thing that would have
6 drifted the first time somebody edited one of them. --}}
87<section class="lsu-scope-contact phero">
98<div class="lsu-scope-contact phero-copy">
109<div class="kicker lsu-scope-contact">We reply within 24 hours</div>
@@ -235,4 +234,3 @@ const canonicalPath = "/contact"
235234<a href="mailto:mail@lastsoulultra.com" class="btn btn-lg lsu-scope-contact">Email the team</a>
236235</div>
237236</section>
238@endsection
resources/views/contact.stxmodified+1-230
Changes to resources/views/contact.stx
@@ -5,234 +5,5 @@ import { productionPages } from '~/resources/data/production-pages'
55const currentPage = productionPages["/contact"]
66const canonicalPath = "/contact"
77</script>
8<section class="lsu-scope-contact phero">
9<div class="lsu-scope-contact phero-copy">
10<div class="kicker lsu-scope-contact">We reply within 24 hours</div>
11<h1 class="lsu-scope-contact">Contact &amp; FAQ</h1>
12</div>
13</section>
14<section class="contact-section lsu-scope-contact section">
15<div class="contact lsu-scope-contact shell">
16<div class="lsu-scope-contact mail">
17<div class="kicker-sm lsu-scope-contact">Email</div>
18<a href="mailto:mail@lastsoulultra.com" class="lsu-scope-contact mail-link"> mail@lastsoulultra.com </a>
19<p class="lsu-scope-contact mail-body">Entries, media and general questions. Up to 24 hours for a reply.</p>
20<button type="button" class="btn btn-outline lsu-scope-contact mail-copy" data-copy="mail@lastsoulultra.com" data-copied="Copied" aria-live="polite" hidden> Copy address </button>
21</div>
22<div class="follow lsu-scope-contact">
23<div class="kicker-sm lsu-scope-contact">Follow the race</div>
24<ul class="lsu-scope-contact">
25<li class="lsu-scope-contact">
26<a href="https://www.instagram.com/lastsoulultra" class="follow-row lsu-scope-contact">
27<span class="follow-text lsu-scope-contact">
28<span class="follow-name lsu-scope-contact"> Instagram · @lastsoulultra </span>
29<span class="follow-body lsu-scope-contact">Updates, stories and behind the scenes during the race.</span>
30</span>
31<span class="follow-arrow lsu-scope-contact" aria-hidden="true">
32↗
33</span>
34</a>
35</li>
36<li class="lsu-scope-contact">
37<a href="https://www.instagram.com/lastsoulultra" class="follow-row lsu-scope-contact">
38<span class="follow-text lsu-scope-contact">
39<span class="follow-name lsu-scope-contact"> Live coverage · Coming soon · @lastsoulultra </span>
40<span class="follow-body lsu-scope-contact">Live coverage is coming soon. Follow @lastsoulultra for updates.</span>
41</span>
42<span class="follow-arrow lsu-scope-contact" aria-hidden="true">
43↗
44</span>
45</a>
46</li>
47<li class="lsu-scope-contact">
48<a href="https://linktr.ee/lastsoulultra" class="follow-row lsu-scope-contact">
49<span class="follow-text lsu-scope-contact">
50<span class="follow-name lsu-scope-contact"> Everything else · linktr.ee </span>
51<span class="follow-body lsu-scope-contact">Streams, results service and partner channels.</span>
52</span>
53<span class="follow-arrow lsu-scope-contact" aria-hidden="true">
54↗
55</span>
56</a>
57</li>
58</ul>
59</div>
60</div>
61</section>
62<section id="faq" class="faq-section lsu-scope-contact">
63<div class="faq lsu-scope-contact shell">
64<nav class="faq-rail lsu-scope-contact" aria-label="Questions by topic">
65<ul class="lsu-scope-contact">
66<li class="lsu-scope-contact">
67<a href="#faq-1" data-rail="1" class="lsu-scope-contact">
68<span class="lsu-scope-contact">Athletes</span>
69<small class="lsu-scope-contact">8</small>
70</a>
71</li>
72<li class="lsu-scope-contact">
73<a href="#faq-2" data-rail="2" class="lsu-scope-contact">
74<span class="lsu-scope-contact">Athlete crew</span>
75<small class="lsu-scope-contact">3</small>
76</a>
77</li>
78<li class="lsu-scope-contact">
79<a href="#faq-3" data-rail="3" class="lsu-scope-contact">
80<span class="lsu-scope-contact">Spectators</span>
81<small class="lsu-scope-contact">4</small>
82</a>
83</li>
84</ul>
85</nav>
86<div class="faq-main lsu-scope-contact">
87<div id="faq-1" class="faq-group lsu-scope-contact" data-group="1">
88<div class="faq-head lsu-scope-contact">
89<h2 class="h2-sm lsu-scope-contact">Athletes</h2>
90<span class="faq-count lsu-scope-contact"> 8 questions </span>
91</div>
92<details class="faq-item lsu-scope-contact" name="lsu-faq">
93<summary class="lsu-scope-contact">
94<span class="faq-q lsu-scope-contact">How does the Last Soul Ultra work?</span>
95<span class="faq-mark lsu-scope-contact" aria-hidden="true">
96</span>
97</summary>
98<div class="faq-a lsu-scope-contact">It follows the backyard ultra format. Every hour, all runners start together on a 6.706 km loop. Anyone who does not finish the loop and return to the corral before the next hour is eliminated. The winner must complete one more loop than every other runner, within the hour. If no runner can do that, there is no winner. All other runners are recorded as DNF.</div>
99</details>
100<details class="faq-item lsu-scope-contact" name="lsu-faq">
101<summary class="lsu-scope-contact">
102<span class="faq-q lsu-scope-contact">When does the race start?</span>
103<span class="faq-mark lsu-scope-contact" aria-hidden="true">
104</span>
105</summary>
106<div class="faq-a lsu-scope-contact">Each race date and location is published on the World Series page once confirmed.</div>
107</details>
108<details class="faq-item lsu-scope-contact" name="lsu-faq">
109<summary class="lsu-scope-contact">
110<span class="faq-q lsu-scope-contact">Is there electricity, water or food?</span>
111<span class="faq-mark lsu-scope-contact" aria-hidden="true">
112</span>
113</summary>
114<div class="faq-a lsu-scope-contact">There is no electrical hookup. Water is provided in containers for each athlete. No organiser-provided race support is planned. This may change, but do not plan on it. Bring your own food, equipment and supplies. Your nutrition, recovery and race setup are your responsibility.</div>
115</details>
116<details class="faq-item lsu-scope-contact" name="lsu-faq">
117<summary class="lsu-scope-contact">
118<span class="faq-q lsu-scope-contact">What are the participation requirements?</span>
119<span class="faq-mark lsu-scope-contact" aria-hidden="true">
120</span>
121</summary>
122<div class="faq-a lsu-scope-contact">Before the start, every athlete signs a waiver. The document, including all terms and conditions, is made available ahead of time.</div>
123</details>
124<details class="faq-item lsu-scope-contact" name="lsu-faq">
125<summary class="lsu-scope-contact">
126<span class="faq-q lsu-scope-contact">Is there a time limit or maximum race duration?</span>
127<span class="faq-mark lsu-scope-contact" aria-hidden="true">
128</span>
129</summary>
130<div class="faq-a lsu-scope-contact">There is no overall time limit or fixed finish distance, but every loop has a strict one-hour limit. Miss a start or fail to finish within the hour, and your race is over. The race goes on until only one person is able to complete a loop.</div>
131</details>
132<details class="faq-item lsu-scope-contact" name="lsu-faq">
133<summary class="lsu-scope-contact">
134<span class="faq-q lsu-scope-contact">How is base camp organised?</span>
135<span class="faq-mark lsu-scope-contact" aria-hidden="true">
136</span>
137</summary>
138<div class="faq-a lsu-scope-contact">Each participant is allocated a 3 × 3 metre space, marked in advance and assigned first come, first served. As runners drop out, remaining camps may be moved closer to the start line.</div>
139</details>
140<details class="faq-item lsu-scope-contact" name="lsu-faq">
141<summary class="lsu-scope-contact">
142<span class="faq-q lsu-scope-contact">What mandatory gear is required?</span>
143<span class="faq-mark lsu-scope-contact" aria-hidden="true">
144</span>
145</summary>
146<div class="faq-a lsu-scope-contact">A working headlamp must be worn when running in twilight or darkness. Participation without this mandatory gear is not allowed.</div>
147</details>
148<details class="faq-item lsu-scope-contact" name="lsu-faq">
149<summary class="lsu-scope-contact">
150<span class="faq-q lsu-scope-contact">Who is participating?</span>
151<span class="faq-mark lsu-scope-contact" aria-hidden="true">
152</span>
153</summary>
154<div class="faq-a lsu-scope-contact">The field is made up of international ultrarunners, athletes, well-known sports personalities, content creators and athletes selected through entry requests.</div>
155</details>
156</div>
157<div id="faq-2" class="faq-group lsu-scope-contact" data-group="2">
158<div class="faq-head lsu-scope-contact">
159<h2 class="h2-sm lsu-scope-contact">Athlete crew</h2>
160<span class="faq-count lsu-scope-contact"> 3 questions </span>
161</div>
162<details class="faq-item lsu-scope-contact" name="lsu-faq">
163<summary class="lsu-scope-contact">
164<span class="faq-q lsu-scope-contact">How much support can an athlete receive?</span>
165<span class="faq-mark lsu-scope-contact" aria-hidden="true">
166</span>
167</summary>
168<div class="faq-a lsu-scope-contact">In base camp, crew can fully assist their athlete with setup, nutrition and preparation for the next loop. Once the athlete is on the course, any kind of support is prohibited. Handing over food or gear during a loop results in immediate disqualification.</div>
169</details>
170<details class="faq-item lsu-scope-contact" name="lsu-faq">
171<summary class="lsu-scope-contact">
172<span class="faq-q lsu-scope-contact">Can crew members enter the track?</span>
173<span class="faq-mark lsu-scope-contact" aria-hidden="true">
174</span>
175</summary>
176<div class="faq-a lsu-scope-contact">No. Crew are not allowed on the track. If the rule is broken, the athlete is automatically disqualified.</div>
177</details>
178<details class="faq-item lsu-scope-contact" name="lsu-faq">
179<summary class="lsu-scope-contact">
180<span class="faq-q lsu-scope-contact">How many crew members are allowed?</span>
181<span class="faq-mark lsu-scope-contact" aria-hidden="true">
182</span>
183</summary>
184<div class="faq-a lsu-scope-contact">You may register four crew members in total. Up to three may be on site at the same time; the fourth may rotate in. Having a crew is optional.</div>
185</details>
186</div>
187<div id="faq-3" class="faq-group lsu-scope-contact" data-group="3">
188<div class="faq-head lsu-scope-contact">
189<h2 class="h2-sm lsu-scope-contact">Spectators</h2>
190<span class="faq-count lsu-scope-contact"> 4 questions </span>
191</div>
192<details class="faq-item lsu-scope-contact" name="lsu-faq">
193<summary class="lsu-scope-contact">
194<span class="faq-q lsu-scope-contact">Can people watch the event in person?</span>
195<span class="faq-mark lsu-scope-contact" aria-hidden="true">
196</span>
197</summary>
198<div class="faq-a lsu-scope-contact">No. On-site spectators are not allowed, which keeps the race safe and the operation smooth.</div>
199</details>
200<details class="faq-item lsu-scope-contact" name="lsu-faq">
201<summary class="lsu-scope-contact">
202<span class="faq-q lsu-scope-contact">Where can I follow the race?</span>
203<span class="faq-mark lsu-scope-contact" aria-hidden="true">
204</span>
205</summary>
206<div class="faq-a lsu-scope-contact">Highlights, updates and information go out on @lastsoulultra, as well as the channels of Kim Gottwald and rappid. Live coverage is coming soon — follow @lastsoulultra for updates.</div>
207</details>
208<details class="faq-item lsu-scope-contact" name="lsu-faq">
209<summary class="lsu-scope-contact">
210<span class="faq-q lsu-scope-contact">Will the race be streamed live?</span>
211<span class="faq-mark lsu-scope-contact" aria-hidden="true">
212</span>
213</summary>
214<div class="faq-a lsu-scope-contact">Live coverage is coming soon. Follow @lastsoulultra for updates.</div>
215</details>
216<details class="faq-item lsu-scope-contact" name="lsu-faq">
217<summary class="lsu-scope-contact">
218<span class="faq-q lsu-scope-contact">Why is the location kept secret?</span>
219<span class="faq-mark lsu-scope-contact" aria-hidden="true">
220</span>
221</summary>
222<div class="faq-a lsu-scope-contact">The venue is withheld to guarantee the safety and smooth running of the event.</div>
223</details>
224</div>
225</div>
226</div>
227</section>
228<section class="cta lsu-scope-contact">
229<div class="cta-bg lsu-scope-contact" style="background-image:url(&#x27;/assets/lsu/images/rappid-47.webp&#x27;);background-position:center 35%" data-px="0.36">
230</div>
231<div class="cta-scrim lsu-scope-contact">
232</div>
233<div class="cta-copy lsu-scope-contact" data-px="-0.06">
234<h2 class="h2 lsu-scope-contact">Still have<br class="lsu-scope-contact">questions?</h2>
235<a href="mailto:mail@lastsoulultra.com" class="btn btn-lg lsu-scope-contact">Email the team</a>
236</div>
237</section>
8@include('contact-body')
2389@endsection
resources/views/faq.stxmodified+1-230
Changes to resources/views/faq.stx
@@ -5,234 +5,5 @@ import { productionPages } from '~/resources/data/production-pages'
55const currentPage = productionPages["/contact"]
66const canonicalPath = "/contact"
77</script>
8<section class="lsu-scope-contact phero">
9<div class="lsu-scope-contact phero-copy">
10<div class="kicker lsu-scope-contact">We reply within 24 hours</div>
11<h1 class="lsu-scope-contact">Contact &amp; FAQ</h1>
12</div>
13</section>
14<section class="contact-section lsu-scope-contact section">
15<div class="contact lsu-scope-contact shell">
16<div class="lsu-scope-contact mail">
17<div class="kicker-sm lsu-scope-contact">Email</div>
18<a href="mailto:mail@lastsoulultra.com" class="lsu-scope-contact mail-link"> mail@lastsoulultra.com </a>
19<p class="lsu-scope-contact mail-body">Entries, media and general questions. Up to 24 hours for a reply.</p>
20<button type="button" class="btn btn-outline lsu-scope-contact mail-copy" data-copy="mail@lastsoulultra.com" data-copied="Copied" aria-live="polite" hidden> Copy address </button>
21</div>
22<div class="follow lsu-scope-contact">
23<div class="kicker-sm lsu-scope-contact">Follow the race</div>
24<ul class="lsu-scope-contact">
25<li class="lsu-scope-contact">
26<a href="https://www.instagram.com/lastsoulultra" class="follow-row lsu-scope-contact">
27<span class="follow-text lsu-scope-contact">
28<span class="follow-name lsu-scope-contact"> Instagram · @lastsoulultra </span>
29<span class="follow-body lsu-scope-contact">Updates, stories and behind the scenes during the race.</span>
30</span>
31<span class="follow-arrow lsu-scope-contact" aria-hidden="true">
32↗
33</span>
34</a>
35</li>
36<li class="lsu-scope-contact">
37<a href="https://www.instagram.com/lastsoulultra" class="follow-row lsu-scope-contact">
38<span class="follow-text lsu-scope-contact">
39<span class="follow-name lsu-scope-contact"> Live coverage · Coming soon · @lastsoulultra </span>
40<span class="follow-body lsu-scope-contact">Live coverage is coming soon. Follow @lastsoulultra for updates.</span>
41</span>
42<span class="follow-arrow lsu-scope-contact" aria-hidden="true">
43↗
44</span>
45</a>
46</li>
47<li class="lsu-scope-contact">
48<a href="https://linktr.ee/lastsoulultra" class="follow-row lsu-scope-contact">
49<span class="follow-text lsu-scope-contact">
50<span class="follow-name lsu-scope-contact"> Everything else · linktr.ee </span>
51<span class="follow-body lsu-scope-contact">Streams, results service and partner channels.</span>
52</span>
53<span class="follow-arrow lsu-scope-contact" aria-hidden="true">
54↗
55</span>
56</a>
57</li>
58</ul>
59</div>
60</div>
61</section>
62<section id="faq" class="faq-section lsu-scope-contact">
63<div class="faq lsu-scope-contact shell">
64<nav class="faq-rail lsu-scope-contact" aria-label="Questions by topic">
65<ul class="lsu-scope-contact">
66<li class="lsu-scope-contact">
67<a href="#faq-1" data-rail="1" class="lsu-scope-contact">
68<span class="lsu-scope-contact">Athletes</span>
69<small class="lsu-scope-contact">8</small>
70</a>
71</li>
72<li class="lsu-scope-contact">
73<a href="#faq-2" data-rail="2" class="lsu-scope-contact">
74<span class="lsu-scope-contact">Athlete crew</span>
75<small class="lsu-scope-contact">3</small>
76</a>
77</li>
78<li class="lsu-scope-contact">
79<a href="#faq-3" data-rail="3" class="lsu-scope-contact">
80<span class="lsu-scope-contact">Spectators</span>
81<small class="lsu-scope-contact">4</small>
82</a>
83</li>
84</ul>
85</nav>
86<div class="faq-main lsu-scope-contact">
87<div id="faq-1" class="faq-group lsu-scope-contact" data-group="1">
88<div class="faq-head lsu-scope-contact">
89<h2 class="h2-sm lsu-scope-contact">Athletes</h2>
90<span class="faq-count lsu-scope-contact"> 8 questions </span>
91</div>
92<details class="faq-item lsu-scope-contact" name="lsu-faq">
93<summary class="lsu-scope-contact">
94<span class="faq-q lsu-scope-contact">How does the Last Soul Ultra work?</span>
95<span class="faq-mark lsu-scope-contact" aria-hidden="true">
96</span>
97</summary>
98<div class="faq-a lsu-scope-contact">It follows the backyard ultra format. Every hour, all runners start together on a 6.706 km loop. Anyone who does not finish the loop and return to the corral before the next hour is eliminated. The winner must complete one more loop than every other runner, within the hour. If no runner can do that, there is no winner. All other runners are recorded as DNF.</div>
99</details>
100<details class="faq-item lsu-scope-contact" name="lsu-faq">
101<summary class="lsu-scope-contact">
102<span class="faq-q lsu-scope-contact">When does the race start?</span>
103<span class="faq-mark lsu-scope-contact" aria-hidden="true">
104</span>
105</summary>
106<div class="faq-a lsu-scope-contact">Each race date and location is published on the World Series page once confirmed.</div>
107</details>
108<details class="faq-item lsu-scope-contact" name="lsu-faq">
109<summary class="lsu-scope-contact">
110<span class="faq-q lsu-scope-contact">Is there electricity, water or food?</span>
111<span class="faq-mark lsu-scope-contact" aria-hidden="true">
112</span>
113</summary>
114<div class="faq-a lsu-scope-contact">There is no electrical hookup. Water is provided in containers for each athlete. No organiser-provided race support is planned. This may change, but do not plan on it. Bring your own food, equipment and supplies. Your nutrition, recovery and race setup are your responsibility.</div>
115</details>
116<details class="faq-item lsu-scope-contact" name="lsu-faq">
117<summary class="lsu-scope-contact">
118<span class="faq-q lsu-scope-contact">What are the participation requirements?</span>
119<span class="faq-mark lsu-scope-contact" aria-hidden="true">
120</span>
121</summary>
122<div class="faq-a lsu-scope-contact">Before the start, every athlete signs a waiver. The document, including all terms and conditions, is made available ahead of time.</div>
123</details>
124<details class="faq-item lsu-scope-contact" name="lsu-faq">
125<summary class="lsu-scope-contact">
126<span class="faq-q lsu-scope-contact">Is there a time limit or maximum race duration?</span>
127<span class="faq-mark lsu-scope-contact" aria-hidden="true">
128</span>
129</summary>
130<div class="faq-a lsu-scope-contact">There is no overall time limit or fixed finish distance, but every loop has a strict one-hour limit. Miss a start or fail to finish within the hour, and your race is over. The race goes on until only one person is able to complete a loop.</div>
131</details>
132<details class="faq-item lsu-scope-contact" name="lsu-faq">
133<summary class="lsu-scope-contact">
134<span class="faq-q lsu-scope-contact">How is base camp organised?</span>
135<span class="faq-mark lsu-scope-contact" aria-hidden="true">
136</span>
137</summary>
138<div class="faq-a lsu-scope-contact">Each participant is allocated a 3 × 3 metre space, marked in advance and assigned first come, first served. As runners drop out, remaining camps may be moved closer to the start line.</div>
139</details>
140<details class="faq-item lsu-scope-contact" name="lsu-faq">
141<summary class="lsu-scope-contact">
142<span class="faq-q lsu-scope-contact">What mandatory gear is required?</span>
143<span class="faq-mark lsu-scope-contact" aria-hidden="true">
144</span>
145</summary>
146<div class="faq-a lsu-scope-contact">A working headlamp must be worn when running in twilight or darkness. Participation without this mandatory gear is not allowed.</div>
147</details>
148<details class="faq-item lsu-scope-contact" name="lsu-faq">
149<summary class="lsu-scope-contact">
150<span class="faq-q lsu-scope-contact">Who is participating?</span>
151<span class="faq-mark lsu-scope-contact" aria-hidden="true">
152</span>
153</summary>
154<div class="faq-a lsu-scope-contact">The field is made up of international ultrarunners, athletes, well-known sports personalities, content creators and athletes selected through entry requests.</div>
155</details>
156</div>
157<div id="faq-2" class="faq-group lsu-scope-contact" data-group="2">
158<div class="faq-head lsu-scope-contact">
159<h2 class="h2-sm lsu-scope-contact">Athlete crew</h2>
160<span class="faq-count lsu-scope-contact"> 3 questions </span>
161</div>
162<details class="faq-item lsu-scope-contact" name="lsu-faq">
163<summary class="lsu-scope-contact">
164<span class="faq-q lsu-scope-contact">How much support can an athlete receive?</span>
165<span class="faq-mark lsu-scope-contact" aria-hidden="true">
166</span>
167</summary>
168<div class="faq-a lsu-scope-contact">In base camp, crew can fully assist their athlete with setup, nutrition and preparation for the next loop. Once the athlete is on the course, any kind of support is prohibited. Handing over food or gear during a loop results in immediate disqualification.</div>
169</details>
170<details class="faq-item lsu-scope-contact" name="lsu-faq">
171<summary class="lsu-scope-contact">
172<span class="faq-q lsu-scope-contact">Can crew members enter the track?</span>
173<span class="faq-mark lsu-scope-contact" aria-hidden="true">
174</span>
175</summary>
176<div class="faq-a lsu-scope-contact">No. Crew are not allowed on the track. If the rule is broken, the athlete is automatically disqualified.</div>
177</details>
178<details class="faq-item lsu-scope-contact" name="lsu-faq">
179<summary class="lsu-scope-contact">
180<span class="faq-q lsu-scope-contact">How many crew members are allowed?</span>
181<span class="faq-mark lsu-scope-contact" aria-hidden="true">
182</span>
183</summary>
184<div class="faq-a lsu-scope-contact">You may register four crew members in total. Up to three may be on site at the same time; the fourth may rotate in. Having a crew is optional.</div>
185</details>
186</div>
187<div id="faq-3" class="faq-group lsu-scope-contact" data-group="3">
188<div class="faq-head lsu-scope-contact">
189<h2 class="h2-sm lsu-scope-contact">Spectators</h2>
190<span class="faq-count lsu-scope-contact"> 4 questions </span>
191</div>
192<details class="faq-item lsu-scope-contact" name="lsu-faq">
193<summary class="lsu-scope-contact">
194<span class="faq-q lsu-scope-contact">Can people watch the event in person?</span>
195<span class="faq-mark lsu-scope-contact" aria-hidden="true">
196</span>
197</summary>
198<div class="faq-a lsu-scope-contact">No. On-site spectators are not allowed, which keeps the race safe and the operation smooth.</div>
199</details>
200<details class="faq-item lsu-scope-contact" name="lsu-faq">
201<summary class="lsu-scope-contact">
202<span class="faq-q lsu-scope-contact">Where can I follow the race?</span>
203<span class="faq-mark lsu-scope-contact" aria-hidden="true">
204</span>
205</summary>
206<div class="faq-a lsu-scope-contact">Highlights, updates and information go out on @lastsoulultra, as well as the channels of Kim Gottwald and rappid. Live coverage is coming soon — follow @lastsoulultra for updates.</div>
207</details>
208<details class="faq-item lsu-scope-contact" name="lsu-faq">
209<summary class="lsu-scope-contact">
210<span class="faq-q lsu-scope-contact">Will the race be streamed live?</span>
211<span class="faq-mark lsu-scope-contact" aria-hidden="true">
212</span>
213</summary>
214<div class="faq-a lsu-scope-contact">Live coverage is coming soon. Follow @lastsoulultra for updates.</div>
215</details>
216<details class="faq-item lsu-scope-contact" name="lsu-faq">
217<summary class="lsu-scope-contact">
218<span class="faq-q lsu-scope-contact">Why is the location kept secret?</span>
219<span class="faq-mark lsu-scope-contact" aria-hidden="true">
220</span>
221</summary>
222<div class="faq-a lsu-scope-contact">The venue is withheld to guarantee the safety and smooth running of the event.</div>
223</details>
224</div>
225</div>
226</div>
227</section>
228<section class="cta lsu-scope-contact">
229<div class="cta-bg lsu-scope-contact" style="background-image:url(&#x27;/assets/lsu/images/rappid-47.webp&#x27;);background-position:center 35%" data-px="0.36">
230</div>
231<div class="cta-scrim lsu-scope-contact">
232</div>
233<div class="cta-copy lsu-scope-contact" data-px="-0.06">
234<h2 class="h2 lsu-scope-contact">Still have<br class="lsu-scope-contact">questions?</h2>
235<a href="mailto:mail@lastsoulultra.com" class="btn btn-lg lsu-scope-contact">Email the team</a>
236</div>
237</section>
8@include('contact-body')
2389@endsection
tests/questions.test.tsadded+47-0
Changes to tests/questions.test.ts
@@ -0,0 +1,47 @@
1import { describe, expect, it } from 'bun:test'
2import { resolve } from 'node:path'
3import { processDirectives } from '@stacksjs/stx'
4
5/**
6 * /contact and /faq are the same page under two published URLs. They used to
7 * be two byte-identical 238-line views, which is the arrangement where one of
8 * them silently stops matching the other the first time an answer is edited.
9 */
10
11async function render(view: string): Promise<string> {
12 const path = resolve(`resources/views/${view}.stx`)
13 return processDirectives(await Bun.file(path).text(), {}, path, {
14 enabled: true,
15 cache: false,
16 componentsDir: resolve('resources/components'),
17 layoutsDir: resolve('resources/layouts'),
18 partialsDir: resolve('resources/partials'),
19 }, new Set())
20}
21
22describe('the questions page', () => {
23 it('renders the same answers at both URLs', async () => {
24 // stx stamps each render with its own scope id, which is not content.
25 const scrub = (html: string): string => html.replace(/[a-z0-9]{6,}(?=["'\s])/gi, '')
26
27 expect(scrub(await render('faq'))).toBe(scrub(await render('contact')))
28 })
29
30 it('keeps one copy of the answers, not one per view', async () => {
31 for (const view of ['contact', 'faq'])
32 expect((await Bun.file(`resources/views/${view}.stx`).text()).split('\n').length).toBeLessThan(15)
33
34 const body = await Bun.file('resources/partials/contact-body.stx').text()
35 expect(body).toContain('How does the Last Soul Ultra work?')
36 })
37
38 it('still answers the fifteen questions', async () => {
39 const html = await render('contact')
40 expect([...html.matchAll(/class="faq-q[^"]*">/g)]).toHaveLength(15)
41 })
42
43 it('canonicalises both to /contact', async () => {
44 for (const view of ['contact', 'faq'])
45 expect(await render(view)).toContain('rel="canonical" href="https://lastsoulultra.com/contact"')
46 })
47})