You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

977 lines
26 KiB

3 years ago
3 years ago
3 years ago
  1. <template>
  2. <div class="white-bkg">
  3. <header>
  4. <div class="header__col">
  5. <button class="btn btn--primary" @click="goBack">
  6. <svg
  7. xmlns="http://www.w3.org/2000/svg"
  8. class="icon icon-tabler icon-tabler-chevrons-left"
  9. width="24"
  10. height="24"
  11. viewBox="0 0 24 24"
  12. stroke-width="3"
  13. stroke="#ffffff"
  14. fill="none"
  15. stroke-linecap="round"
  16. stroke-linejoin="round"
  17. >
  18. <path stroke="none" d="M0 0h24v24H0z" fill="none" />
  19. <polyline points="11 7 6 12 11 17" />
  20. <polyline points="17 7 12 12 17 17" />
  21. </svg>
  22. back
  23. </button>
  24. </div>
  25. <div class="header__col">
  26. <Logo />
  27. </div>
  28. <div class="header__col" />
  29. </header>
  30. <main class="main-with-header">
  31. <ChosenFlights
  32. :selected-orig="selectedOrig"
  33. :selected-dest="selectedDest"
  34. :departure="formattedDate($route.params.departure)"
  35. :departure-time="
  36. selectedSchedule &&
  37. selectedSchedule.fields &&
  38. selectedSchedule.fields.Departure_TimeL
  39. "
  40. style="margin: 0 1rem;"
  41. />
  42. <div class="schedule-wrapper">
  43. <ul class="schedule-grid">
  44. <li
  45. v-for="schedule in schedules"
  46. :key="schedule.fields.Record_ID"
  47. :class="[
  48. 'grid__row',
  49. { grid__row: selectedSchedule.id == schedule.id },
  50. ]"
  51. >
  52. <div class="row__check">
  53. <label class="radio radio--sched" :for="schedule.id">
  54. <input :id="schedule.id" type="radio" name="schedules" />
  55. <span @click="selectSchedule(schedule)">
  56. <svg
  57. xmlns="http://www.w3.org/2000/svg"
  58. class="icon icon-tabler icon-tabler-check"
  59. width="24"
  60. height="24"
  61. viewBox="0 0 24 24"
  62. stroke-width="3"
  63. stroke="#ffffff"
  64. fill="none"
  65. stroke-linecap="round"
  66. stroke-linejoin="round"
  67. >
  68. <path stroke="none" d="M0 0h24v24H0z" fill="none" />
  69. <path d="M5 12l5 5l10 -10" />
  70. </svg>
  71. </span>
  72. </label>
  73. </div>
  74. <div class="row__dep">
  75. <label class="text--muni">
  76. {{ selectedOrig.municipality }}
  77. </label>
  78. <h1 class="text--time">
  79. {{ schedule.fields.Departure_TimeL }}
  80. </h1>
  81. </div>
  82. <div class="row__trip">
  83. <svg
  84. xmlns="http://www.w3.org/2000/svg"
  85. class="icon icon-tabler icon-tabler-arrow-right-circle"
  86. width="100"
  87. height="100"
  88. viewBox="0 0 24 24"
  89. stroke-width="1.5"
  90. stroke="#007fff"
  91. fill="none"
  92. stroke-linecap="round"
  93. stroke-linejoin="round"
  94. >
  95. <path stroke="none" d="M0 0h24v24H0z" fill="none" />
  96. <path d="M18 15l3 -3l-3 -3" />
  97. <circle cx="5" cy="12" r="2" />
  98. <path d="M7 12h14" />
  99. </svg>
  100. </div>
  101. <div class="row__arr">
  102. <label class="text--muni">
  103. {{ selectedDest.municipality }}
  104. </label>
  105. <h1 class="text--time">
  106. {{ schedule.fields.Arrival_TimeL }}
  107. </h1>
  108. </div>
  109. <div class="row__info">
  110. <h2 class="text--carrier">
  111. {{ schedule.fields.Carrier_Name }}
  112. </h2>
  113. <span
  114. v-if="schedule.fields.Flight_Number"
  115. class="text--flight-num"
  116. >
  117. Flight No. {{ schedule.fields.Flight_Number }}
  118. </span>
  119. <span class="text--dow">
  120. {{ schedule.fields.Frequency_Convert }}
  121. </span>
  122. <span class="badge--avail">
  123. Available until
  124. <strong>{{
  125. formattedDate(schedule.fields.Effective_End)
  126. }}</strong>
  127. </span>
  128. </div>
  129. </li>
  130. </ul>
  131. </div>
  132. <div
  133. :class="[
  134. 'flyout-container',
  135. { 'flyout-container--hide': !selectedSchedule.id },
  136. { 'flyout-container--show': selectedSchedule.id },
  137. ]"
  138. >
  139. <div class="flyout">
  140. <button
  141. v-if="
  142. selectedSchedule &&
  143. selectedSchedule.fields &&
  144. selectedSchedule.fields.IsExpedia &&
  145. selectedSchedule.fields.IsExpedia[0] !== 'true' &&
  146. selectedSchedule.fields.Carrier_Name !==
  147. 'Copper Valley Air Service'
  148. "
  149. class="btn btn--primary"
  150. @click="goToCarrier"
  151. >
  152. see flights
  153. </button>
  154. <div
  155. v-if="
  156. selectedSchedule &&
  157. selectedSchedule.fields &&
  158. selectedSchedule.fields.IsExpedia &&
  159. (selectedSchedule.fields.IsExpedia[0] === 'true' ||
  160. selectedSchedule.fields.Carrier_Name ===
  161. 'Copper Valley Air Service')
  162. "
  163. class="form-row"
  164. >
  165. <label for="">How Many Adults?</label>
  166. <v-select
  167. v-model="numAdult"
  168. :options="[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]"
  169. />
  170. </div>
  171. <div
  172. v-if="
  173. selectedSchedule &&
  174. selectedSchedule.fields &&
  175. selectedSchedule.fields.IsExpedia &&
  176. (selectedSchedule.fields.IsExpedia[0] === 'true' ||
  177. selectedSchedule.fields.Carrier_Name ===
  178. 'Copper Valley Air Service')
  179. "
  180. class="form-row"
  181. >
  182. <label for="">How Many Children?</label>
  183. <v-select
  184. v-model="numChild"
  185. :options="[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]"
  186. />
  187. </div>
  188. <div
  189. v-if="
  190. selectedSchedule &&
  191. selectedSchedule.fields &&
  192. selectedSchedule.fields.Carrier_Name ===
  193. 'Copper Valley Air Service'
  194. "
  195. class="alert--flights"
  196. >
  197. <h3>
  198. You'll be flying with<br>
  199. <strong>Copper Valley Air Service</strong>,<br>a great local
  200. airline!
  201. </h3>
  202. <!-- <p>
  203. Copper Valley is a small, family run airline that not only
  204. provides bi-weekly air-taxi flights, but also mail delivery,
  205. sight-seeing, and adventure flights to remote areas of Alaska.
  206. </p> -->
  207. <p>
  208. To book with Copper Valley, enter your contact info below and they
  209. will contact you directly to finish your booking.
  210. </p>
  211. </div>
  212. <div
  213. v-if="
  214. selectedSchedule &&
  215. selectedSchedule.fields &&
  216. selectedSchedule.fields.Carrier_Name ===
  217. 'Copper Valley Air Service'
  218. "
  219. class="form-row form-row--two-columns"
  220. >
  221. <input
  222. type="text"
  223. name="firstName"
  224. placeholder="first name"
  225. v-model="firstName"
  226. :class="[{'input--error': firstNameTouched && !firstName}]"
  227. @focus="firstNameTouched = true"
  228. />
  229. <input
  230. type="text"
  231. name="lastName"
  232. placeholder="last name"
  233. v-model="lastName"
  234. :class="[{'input--error': lastNameTouched && !lastName}]"
  235. @focus="lastNameTouched = true"
  236. />
  237. </div>
  238. <div
  239. v-if="
  240. selectedSchedule &&
  241. selectedSchedule.fields &&
  242. selectedSchedule.fields.Carrier_Name ===
  243. 'Copper Valley Air Service'
  244. "
  245. class="form-row"
  246. >
  247. <input
  248. type="email"
  249. name="email"
  250. placeholder="email address"
  251. v-model="email"
  252. required
  253. @input="validateEmail"
  254. :class="[{'input--error': emailError}]"
  255. />
  256. <span class="alert--error">
  257. {{ emailError }}
  258. </span>
  259. </div>
  260. <div
  261. v-if="
  262. selectedSchedule &&
  263. selectedSchedule.fields &&
  264. selectedSchedule.fields.Carrier_Name ===
  265. 'Copper Valley Air Service'
  266. "
  267. class="form-row"
  268. >
  269. <VuePhoneNumberInput
  270. v-model="phone"
  271. required
  272. @update="validatePhone"
  273. show-code-on-list
  274. @phone-number-focused="phoneTouched = true" />
  275. <!-- <input
  276. type="tel"
  277. name="tel"
  278. placeholder="phone number"
  279. v-model="phone"
  280. required
  281. @blur="validatePhone"
  282. /> -->
  283. <span v-if="phoneTouched" class="alert--error">
  284. {{ phoneError }}
  285. </span>
  286. </div>
  287. <button
  288. v-if="
  289. selectedSchedule &&
  290. selectedSchedule.fields &&
  291. selectedSchedule.fields.IsExpedia &&
  292. selectedSchedule.fields.IsExpedia[0] === 'true'
  293. "
  294. class="btn btn--primary"
  295. @click="book"
  296. >
  297. book now!
  298. </button>
  299. <button
  300. v-if="
  301. selectedSchedule &&
  302. selectedSchedule.fields &&
  303. selectedSchedule.fields.Carrier_Name ===
  304. 'Copper Valley Air Service'
  305. "
  306. :disabled="(emailError + phoneError).length > 0 || !firstName || !lastName"
  307. class="btn btn--primary"
  308. @click="contactCarrier"
  309. >
  310. contact carrier <svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-send" width="24" height="24" viewBox="0 0 24 24" stroke-width="3" stroke="#000000" fill="none" stroke-linecap="round" stroke-linejoin="round">
  311. <path stroke="none" d="M0 0h24v24H0z" fill="none"/>
  312. <line x1="10" y1="14" x2="21" y2="3" />
  313. <path d="M21 3l-6.5 18a0.55 .55 0 0 1 -1 0l-3.5 -7l-7 -3.5a0.55 .55 0 0 1 0 -1l18 -6.5" />
  314. </svg>
  315. </button>
  316. <div v-if="mailSent" class="alert--sent">
  317. Thanks! You will be contacted shortly.
  318. </div>
  319. </div>
  320. </div>
  321. </main>
  322. </div>
  323. </template>
  324. <script>
  325. export default {
  326. data () {
  327. return {
  328. schedules: [],
  329. startingDate: '',
  330. selectedSchedule: {},
  331. selectedDays: [],
  332. selectedOrig: {},
  333. selectedDest: {},
  334. numAdult: 1,
  335. numChild: 0,
  336. firstName: '',
  337. lastName: '',
  338. email: '',
  339. phone: '',
  340. firstNameTouched: false,
  341. lastNameTouched: false,
  342. emailTouched: false,
  343. phoneTouched: false,
  344. emailError: '',
  345. phoneError: '',
  346. mailSent: false
  347. }
  348. },
  349. async fetch () {
  350. // console.log(this.$route.params.o)
  351. const today = new Date().toLocaleDateString('en-CA')
  352. const scheduleFetchFilterFormula = `AND(Is_Current="Yes",Origin_IATA="${this.$route.params.o}",Destination_IATA="${this.$route.params.d}",Effective_End>"${today}",SEARCH("${new Date(this.$route.params.departure).getUTCDay()}",Frequency)>0)`
  353. // console.log(scheduleFetchFilterFormula)
  354. const scheduleFetchSort = '&sort[0][field]=Departure_TimeL&sort[0][direction]=asc'
  355. const response = await fetch(`https://api.airtable.com/v0/appiQwfVZixRgRICe/Schedule?filterByFormula=${scheduleFetchFilterFormula}${scheduleFetchSort}`, {
  356. method: 'GET',
  357. headers: {
  358. 'Content-Type': 'application/x-www-form-urlencoded',
  359. Authorization: 'Bearer keyJ2ht64ZSN57AG1'
  360. }
  361. })
  362. const data = await response.json()
  363. // console.log(data)
  364. this.schedules = [...data.records]
  365. },
  366. mounted () {
  367. //this.$segment.page('flights');
  368. this.$segment.track('flights__mount-page', {
  369. origin: this.$route.params.o,
  370. destination: this.$route.params.d,
  371. departureDate: this.$route.params.departure,
  372. });
  373. const emailCookie = this.$cookies.get('email')
  374. if(emailCookie){
  375. this.$segment.identify(emailCookie, {
  376. email: emailCookie
  377. });
  378. const newUser =
  379. {
  380. fields: {
  381. Email: emailCookie,
  382. CreatedDate: new Date(),
  383. Type: 'portier-login',
  384. Site: 'https://iflylocal.com/'
  385. }
  386. }
  387. const res = await fetch(`https://api.airtable.com/v0/appiQwfVZixRgRICe/User/`, {
  388. method: 'POST',
  389. headers: {
  390. 'Content-Type': 'application/json',
  391. Authorization: 'Bearer keyJ2ht64ZSN57AG1'
  392. },
  393. body: JSON.stringify(newUser)
  394. })
  395. }
  396. },
  397. created () {
  398. // console.log(this.$route.path)
  399. if (this.$route && this.$route.params && this.$route.params.o) {
  400. this.fetchSingleAirport(this.$route.params.o, true)
  401. }
  402. if (this.$route && this.$route.params && this.$route.params.d) {
  403. this.fetchSingleAirport(this.$route.params.d, false)
  404. }
  405. },
  406. methods: {
  407. formattedDate (date) {
  408. const thisDate = new Date(date)
  409. const month = thisDate.toLocaleString('en-us', { month: 'short' })
  410. const year = ((thisDate.getUTCFullYear() !== new Date().getUTCFullYear()) ? ', ' + thisDate.getUTCFullYear() : '')
  411. return month + ' ' + thisDate.getUTCDate() + year
  412. },
  413. daysList (days) {
  414. const list = days.split(', ').map((day) => {
  415. const name = day.toLowerCase().slice(0, -1)
  416. let num
  417. switch (name) {
  418. case 'su':
  419. num = 0
  420. break
  421. case 'mo':
  422. num = 1
  423. break
  424. case 'tu':
  425. num = 2
  426. break
  427. case 'we':
  428. num = 3
  429. break
  430. case 'th':
  431. num = 4
  432. break
  433. case 'fr':
  434. num = 5
  435. break
  436. case 'sa':
  437. num = 6
  438. break
  439. default:
  440. break
  441. }
  442. return {
  443. name,
  444. num
  445. }
  446. })
  447. return list.sort(function (a, b) {
  448. return a.num - b.num
  449. })
  450. },
  451. goBack () {
  452. this.$segment.track('flights__go_back', {
  453. origin: this.$route.params.o,
  454. destination: this.$route.params.d,
  455. departureDate: this.$route.params.departure,
  456. })
  457. //this.$router.go(-1)
  458. this.$router.push({
  459. path: '/dates/' + this.$route.params.o + "/" + this.$route.params.d
  460. })
  461. },
  462. // book2 (schedule) {
  463. // if (schedule.fields.IsExpedia[0] === 'true') {
  464. // this.startingDate = new Date()
  465. // this.selectedSchedule = schedule.fields
  466. // this.selectedDays = this.daysList(schedule.fields.Frequency_Convert)
  467. // } else {
  468. // window.open(schedule.fields['BookingLink (from Carriers_Alaska)'][0])
  469. // }
  470. // },
  471. book () {
  472. this.$segment.track('flights__book', {
  473. origin: this.selectedSchedule.fields.Origin_IATA[0],
  474. destination: this.selectedSchedule.fields.Destination_IATA[0],
  475. departureDate: this.$route.params.departure,
  476. departureTime: this.selectedSchedule.fields.Departure_TimeL,
  477. arrivalTime: this.selectedSchedule.fields.Arrival_TimeL,
  478. numAdult: this.numAdult,
  479. numChild: this.numChild,
  480. carrier: this.selectedSchedule.fields.Carrier_Name
  481. })
  482. window.open(`https://www.anrdoezrs.net/links/100449149/type/am/https://www.expedia.com/go/flight/search/oneway/${this.$route.params.departure}/${this.$route.params.departure}?langid=1033&FromAirport=${this.selectedSchedule.fields.Origin_IATA}&FromTime=${this.selectedSchedule.fields.Departure_TimeL}&ToTime=${this.selectedSchedule.fields.Arrival_TimeL}&ToAirport=${this.selectedSchedule.fields.Destination_IATA}&Class=3&NumAdult=${this.numAdult}&NumChild=${this.numChild}`)
  483. },
  484. goToCarrier () {
  485. this.$segment.track('flights__open_carrier', {
  486. origin: this.selectedSchedule.fields.Origin_IATA[0],
  487. destination: this.selectedSchedule.fields.Destination_IATA[0],
  488. departureDate: this.$route.params.departure,
  489. departureTime: this.selectedSchedule.fields.Departure_TimeL,
  490. arrivalTime: this.selectedSchedule.fields.Arrival_TimeL,
  491. numAdult: this.numAdult,
  492. numChild: this.numChild,
  493. carrier: this.selectedSchedule.fields.Carrier_Name
  494. })
  495. window.open(this.selectedSchedule.fields['BookingLink (from Carriers_Alaska)'][0])
  496. },
  497. async contactCarrier () {
  498. const newBooking =
  499. {
  500. fields: {
  501. ArrivalTime: this.selectedSchedule.fields.Arrival_TimeL,
  502. Carrier: this.selectedSchedule.fields.Carrier_Name,
  503. DepartureTime: this.selectedSchedule.fields.Departure_TimeL,
  504. Destination: this.selectedSchedule.fields.Destination_IATA[0],
  505. Origin: this.selectedSchedule.fields.Origin_IATA[0],
  506. CreatedDate: new Date(),
  507. FirstName: this.firstName,
  508. LastName: this.lastName,
  509. Phone: this.phone,
  510. Email: this.email,
  511. DepartureDate: this.$route.params.departure,
  512. NumAdult: this.numAdult,
  513. NumChild: this.numChild,
  514. }
  515. }
  516. const res = await fetch(`https://api.airtable.com/v0/appiQwfVZixRgRICe/CVAS_Booking/`, {
  517. method: 'POST',
  518. headers: {
  519. 'Content-Type': 'application/json',
  520. Authorization: 'Bearer key8ZVBxVZJL2Wp7y'
  521. },
  522. body: JSON.stringify(newBooking)
  523. })
  524. const json = await res.json()
  525. //this.guests = { ...await json }
  526. if(await json) {
  527. this.mailSent = true
  528. this.firstName = ''
  529. this.lastName = ''
  530. this.email = ''
  531. this.phone = ''
  532. this.firstNameTouched = false
  533. this.lastNameTouched = false
  534. this.emailTouched = false
  535. this.phoneTouched = false
  536. }
  537. },
  538. selectSchedule (schedule) {
  539. this.selectedSchedule = { ...schedule }
  540. this.$segment.track('flights__select_schedule', {
  541. origin: this.selectedSchedule.fields.Origin_IATA[0],
  542. destination: this.selectedSchedule.fields.Destination_IATA[0],
  543. departureDate: this.$route.params.departure,
  544. departureTime: this.selectedSchedule.fields.Departure_TimeL,
  545. arrivalTime: this.selectedSchedule.fields.Arrival_TimeL,
  546. carrier: this.selectedSchedule.fields.Carrier_Name
  547. })
  548. },
  549. clearSelectedSchedule () {
  550. // console.log('clear')
  551. this.startingDate = ''
  552. this.selectedSchedule = {}
  553. },
  554. async fetchSingleAirport(iata, isOrig) {
  555. const airportFetchFilterFormula =
  556. isOrig
  557. ? `AND(Is_Origin=1,{IsCurrent-AsOrigin}="Yes",Airport_IATA="${iata}")`
  558. : `AND(Is_Destination=1,{IsCurrent-AsDest}="Yes",Airport_IATA="${iata}")`
  559. const response = await fetch(`https://api.airtable.com/v0/appiQwfVZixRgRICe/Airports_IATA?filterByFormula=${airportFetchFilterFormula}`, {
  560. method: 'GET',
  561. headers: {
  562. 'Content-Type': 'application/x-www-form-urlencoded',
  563. Authorization: 'Bearer keyJ2ht64ZSN57AG1'
  564. }
  565. })
  566. const mapData = await response.json()
  567. const thisAirport = {
  568. iata: mapData.records[0].fields.Airport_IATA,
  569. lat: mapData.records[0].fields.Latitude_Deg,
  570. long: mapData.records[0].fields.Longitude_Deg,
  571. icon: mapData.records[0].fields.Icon_Url,
  572. name: mapData.records[0].fields.Airport_Name,
  573. municipality: mapData.records[0].fields.Municipality,
  574. type: mapData.records[0].fields.Type,
  575. search: mapData.records[0].fields.Search_Field
  576. }
  577. switch (isOrig) {
  578. case true:
  579. this.selectedOrig = { ...thisAirport }
  580. break
  581. case false:
  582. this.selectedDest = { ...thisAirport }
  583. break
  584. default:
  585. break
  586. }
  587. },
  588. validateEmail() {
  589. if (/(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])/.test(this.email)) {
  590. const emailArray = this.email.split('@')
  591. const name = emailArray[0]
  592. const fullDomain = emailArray[1]
  593. const domainArray = fullDomain.split('.')
  594. const domain = domainArray.slice(-2)[0]
  595. const tld = domainArray.slice(-1)[0]
  596. if(tld.length < 2 || domain.length < 2) {
  597. this.emailError = 'your email isn\'t valid';
  598. } else {
  599. this.emailError = '';
  600. }
  601. } else {
  602. this.emailError = 'your email isn\'t valid';
  603. }
  604. },
  605. validatePhone(data) {
  606. this.phoneIsValid = data.isValid
  607. if (data.isValid) {
  608. this.phoneError = '';
  609. } else {
  610. this.phoneError = 'your phone number isn\'t valid';
  611. }
  612. }
  613. }
  614. }
  615. </script>
  616. <style lang="scss" scoped>
  617. .main-with-header {
  618. margin-top: clamp(20px + 1.75rem, 4rem + 1.75rem, 50px + 1.75rem);
  619. }
  620. .schedule-wrapper {
  621. display: flex;
  622. flex-direction: column;
  623. align-items: center;
  624. }
  625. .schedule-grid {
  626. display: flex;
  627. flex-direction: column;
  628. gap: 1rem;
  629. margin: 2rem 2rem 2rem 2rem;
  630. }
  631. .grid__row {
  632. display: flex;
  633. flex-direction: row;
  634. align-items: center;
  635. gap: 1rem;
  636. padding: 1rem 1rem 1rem 4rem;
  637. flex-wrap: wrap;
  638. border-radius: 2rem;
  639. }
  640. .grid__row:nth-child(odd) {
  641. background: #eee;
  642. }
  643. label {
  644. font-size: 0.75rem;
  645. font-weight: 700;
  646. color: white;
  647. display: block;
  648. }
  649. .field__content {
  650. font-size: 1.5rem;
  651. }
  652. .dow-grid {
  653. width: 200px;
  654. display: grid;
  655. grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr 1fr;
  656. gap: 0.5rem;
  657. }
  658. .dow-grid__day {
  659. font-size: 0.8rem;
  660. border: 1px solid #ccc !important;
  661. display: flex;
  662. align-items: center;
  663. justify-content: center;
  664. border-radius: 3px !important;
  665. text-transform: capitalize;
  666. }
  667. .day--su {
  668. grid-column: 1 / span 1;
  669. }
  670. .day--mo {
  671. grid-column: 2 / span 1;
  672. }
  673. .day--tu {
  674. grid-column: 3 / span 1;
  675. }
  676. .day--we {
  677. grid-column: 4 / span 1;
  678. }
  679. .day--th {
  680. grid-column: 5 / span 1;
  681. }
  682. .day--fr {
  683. grid-column: 6 / span 1;
  684. }
  685. .day--sa {
  686. grid-column: 7 / span 1;
  687. }
  688. .row__trip {
  689. display: flex;
  690. align-items: center;
  691. }
  692. .row__trip svg {
  693. margin-bottom: -0.5rem;
  694. width: 3.5rem;
  695. height: 3.5rem;
  696. margin-left: -1rem;
  697. margin-right: -1rem;
  698. }
  699. .shape--trip {
  700. height: 0.4rem;
  701. width: 2rem;
  702. background: #007fff;
  703. display: block;
  704. margin-top: 1rem;
  705. position: relative;
  706. }
  707. .shape--trip::before {
  708. height: 0.8rem;
  709. width: 0.8rem;
  710. background: #fff;
  711. border: 0.02rem solid #007fff;
  712. border-radius: 999px;
  713. content: "";
  714. position: absolute;
  715. top: -0.15rem;
  716. left: -0.5rem;
  717. }
  718. .shape--trip::after {
  719. height: 0.8rem;
  720. width: 0.8rem;
  721. background: #007fff;
  722. border: 0.02rem solid #007fff;
  723. border-radius: 999px;
  724. content: "";
  725. position: absolute;
  726. top: -0.15rem;
  727. right: -0.5rem;
  728. }
  729. h1 {
  730. font-size: 3rem;
  731. line-height: 0.85;
  732. }
  733. h2 {
  734. font-size: 2rem;
  735. line-height: 1;
  736. }
  737. label.text--muni {
  738. color: #007fff;
  739. line-height: 1;
  740. padding-left: 0.3rem;
  741. }
  742. span.text--flight-num {
  743. font-weight: 700;
  744. margin-right: 0.5rem;
  745. }
  746. span.text--dow {
  747. font-weight: 300;
  748. font-size: 0.8rem;
  749. color: #007fff;
  750. }
  751. span.badge--avail {
  752. border-radius: 999px;
  753. border: 1px solid gray;
  754. color: gray;
  755. padding: 0.2em 0.8em;
  756. line-height: 1;
  757. font-size: 0.8rem;
  758. display: block;
  759. width: fit-content;
  760. }
  761. .radio span {
  762. border-radius: 999px;
  763. border: 3px solid #007fff;
  764. background-color: white;
  765. height: 2rem;
  766. width: 2rem;
  767. display: flex;
  768. position: relative;
  769. transition: all 0.3s;
  770. align-items: center;
  771. justify-content: center;
  772. }
  773. .radio span svg {
  774. transition: all 0.3s;
  775. stroke: #eee;
  776. }
  777. .radio span:hover {
  778. background: #007fff;
  779. }
  780. .radio input:checked + span {
  781. background: #007fff;
  782. }
  783. .radio input:checked + span svg {
  784. stroke: white;
  785. }
  786. .radio input {
  787. display: none;
  788. }
  789. .row__info {
  790. min-width: fit-content;
  791. }
  792. .row__check {
  793. margin-left: -3rem;
  794. }
  795. .form-row {
  796. display: flex;
  797. flex-direction: column;
  798. justify-content: stretch;
  799. }
  800. .form-row label {
  801. text-transform: uppercase;
  802. font-size: 1rem;
  803. font-weight: 300;
  804. }
  805. .form-row input {
  806. background: #eee;
  807. border-radius: 0.5rem 3rem 3rem 3rem;
  808. transition: 0.3s all;
  809. padding: 0.5em 0.8em;
  810. font-size: min(1rem, 18px);
  811. line-height: 1;
  812. }
  813. .form-row--two-columns {
  814. display: flex;
  815. flex-direction: row;
  816. flex-wrap: nowrap;
  817. column-gap: 1rem;
  818. }
  819. .form-row--two-columns input {
  820. width: 50%;
  821. }
  822. .form-row input:focus {
  823. border: 0;
  824. }
  825. .flyout {
  826. background: #007fff;
  827. border-radius: 3rem 3rem 0 0;
  828. padding: 3rem;
  829. pointer-events: all;
  830. width: clamp(450px, 50vw, 400px);
  831. display: flex;
  832. flex-direction: column;
  833. gap: 1rem;
  834. }
  835. .flyout .btn.btn--primary {
  836. background: white;
  837. color: black;
  838. }
  839. .flyout .btn.btn--primary:hover {
  840. background: #00ca00;
  841. color: #fff;
  842. }
  843. .flyout p {
  844. font-size: 1rem;
  845. line-height: 1.2;
  846. font-weight: 400;
  847. color: #fff;
  848. margin-bottom: 1rem;
  849. margin-left: 0.5rem;
  850. margin-right: 0.5rem;
  851. }
  852. .flyout p:last-child {
  853. margin-bottom: 0;
  854. }
  855. .flyout h3 {
  856. font-size: 1.5rem;
  857. line-height: 1;
  858. font-weight: 200;
  859. margin-bottom: 1rem;
  860. color: #fff;
  861. margin-left: 0.5rem;
  862. margin-right: 0.5rem;
  863. }
  864. .flyout h3 strong {
  865. font-weight: 600;
  866. }
  867. .btn:disabled {
  868. opacity: 0.2;
  869. background-color: #ddd;
  870. color: #222;
  871. cursor: not-allowed;
  872. pointer-events: none;
  873. }
  874. .form-row input.input--error {
  875. --stripe1: #ff69b433;
  876. --stripe2: #eee;
  877. // box-shadow: 0 0 0 0.2rem red;
  878. background: linear-gradient(135deg, var(--stripe1) 25%, var(--stripe2) 25%, var(--stripe2) 50%, var(--stripe1) 50%, var(--stripe1) 75%, var(--stripe2) 75%, var(--stripe2) 100%), var(--stripe2);
  879. background-size: 56.57px 56.57px;
  880. }
  881. .alert--error {
  882. text-align: center;
  883. color: white;
  884. font-size: 0.75rem;
  885. margin-top: 0.15rem;
  886. }
  887. .alert--sent {
  888. text-align: center;
  889. background-color: #00ca00;
  890. margin: 0 -3rem -3rem -3rem;
  891. text-transform: uppercase;
  892. font-size: 0.9rem;
  893. letter-spacing: 0.1rem;
  894. padding: 1rem;
  895. }
  896. </style>