{"version":3,"mappings":"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","names":["EventTypes","defineAsyncComponent","__vitePreload","props","__props","dateTime","formatDate","formatTime","formatToString","useDateFormat","proxySource","useImageProxy","isNewDate","key","calendarQuery","gql","__default__","params","villusClient","resolve","reject","err","Datepicker","detectKeyboardUser","focusFirstChild","useA11y","ga4Event","useAnalytics","handleError","useHandleError","setMetaDescription","setMetaTitle","useMetaData","route","useRoute","store","useMainStore","setValue","appConfig","inject","allActiveDates","activeDates","ref","activeEvents","activeFilters","checkedDate","datepickerDisabled","datepickerRef","eventOccurrences","filterDropdown","moreDisabled","moreSlices","pickedDate","selected","selectedDate","selectedFilters","sliceEnd","sliceSize","sliceStart","totalCount","selectNav","useFilterInteractions","data","error","useQuery","title","today","loadData","nextTick","firstDate","computed","parseISO","watch","updateFilters","handleDate","setUrl","resetSlice","onMounted","filter","current","isActiveFilter","clearAll","getDay","date","monthNames","temp","event","noEventsFound","str","i","filters","isDeselected","base","url","setUserPick","toggle","type"],"ignoreList":[],"sources":["../../src/components/calendar/CalendarDay.vue","../../src/queries/CalendarQuery.js","../../src/components/calendar/CalendarSection.vue"],"sourcesContent":["<template>\n <section :class=\"$style.day\">\n <article\n v-if=\"formatToString(firstDate, true) !== formatDate(events[0].start, true)\"\n :class=\"$style.event\"\n >\n <h2 class=\"heading-3\">\n <time\n :class=\"$style.date\"\n :datetime=\"dateTime(firstDate)\"\n v-html=\"formatToString(firstDate, true)\"\n ></time>\n </h2>\n <p :class=\"$style.message\">There are no events scheduled for this day.</p>\n </article>\n <article v-for=\"(event, key) in events\" :key=\"key\" :class=\"$style.event\">\n <h2 v-if=\"isNewDate(key)\" class=\"heading-3\">\n <time\n :class=\"$style.date\"\n :datetime=\"dateTime(event.start)\"\n v-html=\"formatDate(event.start, true)\"\n ></time>\n </h2>\n <router-link\n v-if=\"event.featuredImage\"\n :class=\"$style.image\"\n :to=\"{ name: 'CalendarEvent', params: { slug: event.eventSlug } }\"\n :ga4-event=\"\n JSON.stringify({\n click_type: 'image',\n component: 'CalendarDay',\n content_group: 'calendar',\n gtm_tag: 'linked_image',\n file_name: `${event.featuredImage.node.sourceUrl.split('/').pop()}`,\n link_url: `${event.eventSlug}`,\n })\n \"\n >\n <picture>\n <img\n :alt=\"event.featuredImage.node.altText\"\n :class=\"[$style.img, 'aspect-image']\"\n :src=\"proxySource(event.featuredImage.node.sourceUrl, 400)\"\n :srcset=\"event.imageSrcset\"\n loading=\"lazy\"\n sizes=\"(min-width: 960px) 470px, 100vw\"\n />\n </picture>\n </router-link>\n <section :class=\"$style.text\">\n <header>\n <router-link\n :class=\"$style.title\"\n :to=\"{ name: 'CalendarEvent', params: { slug: event.eventSlug } }\"\n :ga4-event=\"\n JSON.stringify({\n click_type: 'title',\n component: 'CalendarDay',\n content_group: 'calendar',\n gtm_tag: 'link',\n link_text: `${event.title}`,\n link_url: `${event.eventSlug}`,\n })\n \"\n >\n <h3 class=\"heading-4\" v-html=\"event.title\"></h3>\n </router-link>\n <time\n v-if=\"!event.hideStartTime\"\n class=\"subtitle-2\"\n :datetime=\"dateTime(event.start)\"\n v-html=\"`${formatTime(event.start)} ${event.timezoneAbbr}`\"\n ></time>\n <p v-if=\"event.specificText && event.hideStartTime\" v-html=\"event.specificText\"></p>\n </header>\n <p v-html=\"event.excerpt\"></p>\n <EventTypes\n v-if=\"Object.keys(event.eventTypes.nodes).length\"\n :types=\"event.eventTypes.nodes\"\n ></EventTypes>\n </section>\n </article>\n </section>\n</template>\n\n<script setup lang=\"ts\">\nimport { defineAsyncComponent } from 'vue';\nimport { EventInterface } from '@/types/event.interface';\nimport { useDateFormat, useImageProxy } from '@/composables/Common.js';\n\nconst EventTypes = defineAsyncComponent(() => import('@/components/calendar/EventTypes.vue'));\n\nconst props = defineProps<{\n events: EventInterface[];\n firstDate: Date;\n}>();\n\nconst { dateTime, formatDate, formatTime, formatToString } = useDateFormat();\nconst { proxySource } = useImageProxy();\n\nfunction isNewDate(key: number): boolean {\n return (\n key === 0 ||\n (key > 0 && props.events[key].start.isoDate !== props.events[key - 1].start.isoDate)\n );\n}\n</script>\n\n<style lang=\"scss\" module>\n.date {\n @include space-48-64-above;\n}\n\n.day {\n margin-top: 4rem;\n}\n\n.event {\n @include space-48-64-above;\n\n &:first-of-type {\n @include space-28-32-above;\n }\n}\n\n.image {\n @include aspect-container;\n margin-top: 2rem;\n}\n\n.message {\n grid-column: span 12;\n margin-top: 2rem;\n}\n\n.text {\n margin-top: 1rem;\n\n ul + .title {\n h2 {\n margin-top: 0.25rem;\n }\n }\n}\n\n.title {\n margin-top: 0.5rem;\n text-decoration: none;\n\n &:hover {\n text-decoration: underline;\n }\n\n h3 {\n margin-top: 0;\n width: fit-content;\n }\n}\n\n@media (min-width: $break-point) {\n .day {\n grid-column: span 12;\n margin-top: 2rem;\n }\n\n .event {\n @include grid;\n grid-column: span 12;\n\n h2 {\n grid-column: span 12;\n }\n }\n\n .image,\n .text {\n grid-column: span 6;\n }\n .image {\n margin-top: px-to-rem(37);\n }\n .text {\n margin-top: 2rem;\n }\n\n .title {\n margin-top: 2rem;\n }\n}\n</style>\n","import gql from 'graphql-tag';\n\nexport const calendarQuery = gql`\n query getEventOccurrences {\n eventOccurrences(first: 1000) {\n nodes {\n end {\n day\n isoDate\n meridiem\n month\n time\n timestamp\n timezone\n year\n weekday\n }\n eventSlug\n eventTypes {\n nodes {\n name\n slug\n }\n }\n excerpt\n featuredImage {\n node {\n altText\n sourceUrl\n }\n }\n imageSrcset\n hideStartTime\n multisession\n soldOutLabel\n specificText\n start {\n day\n isoDate\n meridiem\n month\n time\n timestamp\n timezone\n year\n weekday\n }\n title\n ticketLabel\n ticketLink\n timezoneAbbr\n }\n pageInfo {\n hasMoreEventOccurrences\n }\n }\n }\n`;\n","<template>\n <section v-if=\"eventOccurrences && Object.keys(eventOccurrences).length\" :class=\"$style.frame\">\n <header :class=\"$style.header\">\n <h1 class=\"no-border-above\">{{ title }}</h1>\n <div :class=\"$style.nav\">\n <div>\n <div :class=\"[$style.link, { [$style.active]: view === 'day' }]\">\n <router-link\n :to=\"{\n name: 'CalendarSection',\n params: {\n date: selectedDate && selectedDate !== today ? selectedDate : '',\n view: 'day',\n },\n query: activeFilters.length ? { q: activeFilters.join(',') } : null,\n }\"\n :aria-current=\"view === 'day'\"\n :disabled=\"view === 'day' ? true : null\"\n :ga4-event=\"\n JSON.stringify({\n click_type: 'view',\n component: 'CalendarSection',\n content_group: 'calendar',\n gtm_tag: 'interaction',\n link_text: 'Day',\n })\n \"\n >\n Day View\n </router-link>\n </div>\n <div :class=\"[$style.link, { [$style.active]: view === 'month' }]\">\n <router-link\n :to=\"{\n name: 'CalendarSection',\n params: {\n date: selectedDate && selectedDate !== today ? selectedDate : '',\n view: 'month',\n },\n query: activeFilters.length ? { q: activeFilters.join(',') } : null,\n }\"\n :aria-current=\"view === 'month'\"\n :disabled=\"view === 'month' ? true : null\"\n :ga4-event=\"\n JSON.stringify({\n click_type: 'view',\n component: 'CalendarSection',\n content_group: 'calendar',\n gtm_tag: 'interaction',\n link_text: 'Month',\n })\n \"\n >\n Month View\n </router-link>\n </div>\n </div>\n <div :class=\"$style.selection\">\n <div>\n <button\n id=\"datepicker-button\"\n aria-controls=\"datepicker\"\n :aria-expanded=\"selected === 'datepicker'\"\n type=\"button\"\n :disabled=\"datepickerDisabled\"\n :class=\"['button-filter', selected === 'datepicker' ? 'up' : 'down']\"\n @click.stop.prevent=\"toggle('datepicker')\"\n >\n Select a Date\n </button>\n <Datepicker\n v-show=\"selected === 'datepicker'\"\n id=\"datepicker\"\n ref=\"datepickerRef\"\n v-model:selectedDate=\"selectedDate\"\n :active-dates=\"activeDates\"\n aria-labelledby=\"datepicker-button\"\n :class=\"$style.datepicker\"\n :collapsible=\"true\"\n @close=\"selected = ''\"\n @pick=\"setUserPick\"\n ></Datepicker>\n </div>\n <div :class=\"['nav-subtypes', { active: selected === 'filters' }]\">\n <button\n id=\"filters-button\"\n aria-controls=\"filters\"\n :aria-expanded=\"selected === 'filters'\"\n type=\"button\"\n :class=\"['button-filter', selected === 'filters' ? 'up' : 'down']\"\n @click.stop.prevent=\"toggle('filters')\"\n >\n Filters\n </button>\n <div\n v-show=\"selected === 'filters'\"\n id=\"filters\"\n ref=\"filterDropdown\"\n aria-labelledby=\"filters-button\"\n :class=\"[$style.navFilters, 'nav-items']\"\n >\n <div v-for=\"(filter, key, index) in filters\" :key=\"key\">\n <input\n :id=\"key\"\n v-model=\"activeFilters\"\n :aria-checked=\"isActiveFilter(key)\"\n :class=\"$style.input\"\n type=\"checkbox\"\n :value=\"key\"\n :ga4-event=\"\n JSON.stringify({\n click_type: 'link',\n component: 'CalendarSection',\n content_group: 'calendar',\n gtm_tag: 'link',\n link_text: 'See exhibitions on view',\n link_url: '/exhibitions',\n })\n \"\n />\n <label class=\"button\" :for=\"key\">\n <div :class=\"$style.checkbox\">\n <IconCheck v-if=\"isActiveFilter(key)\" :key=\"key\"></IconCheck>\n <IconBox v-else></IconBox>\n </div>\n <span>{{ filter }}</span>\n </label>\n </div>\n <button class=\"apply\" type=\"button\" @click=\"selected = ''\">Close</button>\n </div>\n </div>\n </div>\n </div>\n <div v-if=\"selectedFilters.length || pickedDate\" :class=\"$style.selectedFilters\">\n <p class=\"label\">Filtered by:</p>\n <div v-if=\"pickedDate\">\n <input id=\"picked\" v-model=\"checkedDate\" type=\"checkbox\" :value=\"pickedDate\" />\n <label for=\"picked\">{{ getDay(pickedDate) }}</label>\n </div>\n <div v-for=\"(filter, key) in selectedFilters\" :key=\"key\">\n <input\n :id=\"`input-${String(key)}`\"\n v-model=\"selectedFilters\"\n :checked=\"selectedFilters.indexOf(key) >= 0\"\n type=\"checkbox\"\n :value=\"filter\"\n />\n <label :for=\"`input-${String(key)}`\">\n {{ slugToTitle(filter) }}\n </label>\n </div>\n <button class=\"button-secondary\" type=\"button\" @click.prevent=\"clearAll\">Clear</button>\n </div>\n </header>\n <CalendarDay\n v-if=\"view === 'day' && activeEvents.length\"\n :class=\"$style.occurrences\"\n :events=\"activeEvents\"\n :first-date=\"firstDate\"\n ></CalendarDay>\n <CalendarMonth\n v-if=\"view === 'month' && activeEvents.length\"\n :class=\"$style.occurrences\"\n :events=\"activeEvents\"\n :first-date=\"firstDate\"\n ></CalendarMonth>\n <p v-if=\"!activeEvents.length\" class=\"space-24-32-above\">\n There are no {{ noEventsFound() }} scheduled on or after\n {{ formatToString(parseISO(selectedDate)) }}.\n </p>\n <div v-if=\"activeEvents.length || !moreDisabled\" :class=\"[$style.loadMore]\">\n <p v-if=\"activeEvents.length && eventOccurrences.nodes.length\" ref=\"total\" class=\"body-2\">\n Showing {{ activeEvents.length }} of {{ totalCount }} results\n </p>\n <button v-if=\"!moreDisabled\" class=\"button-secondary\" type=\"button\" @click=\"loadData()\">\n Load More Results\n </button>\n </div>\n <BackToTop></BackToTop>\n </section>\n</template>\n\n<script setup lang=\"ts\">\nimport { AppConfig } from '@/types/global.interface.ts';\nimport BackToTop from '@/components/common/BackToTop.vue';\nimport CalendarDay from '@/components/calendar/CalendarDay.vue';\nimport CalendarMonth from '@/components/calendar/CalendarMonth.vue';\nimport { calendarQuery } from '@/queries/CalendarQuery';\nimport {\n computed,\n defineAsyncComponent,\n inject,\n nextTick,\n onMounted,\n ref,\n watch\n} from 'vue';\nimport { EventInterface } from '@/types/event.interface';\nimport { filters, monthNames } from '@/config/calendar';\nimport IconBox from '@/assets/svgs/IconBox.svg?component';\nimport IconCheck from '@/assets/svgs/IconCheck.svg?component';\nimport { slugToTitle } from '@/utils.js';\nimport {\n useA11y,\n useAnalytics,\n useDateFormat,\n useFilterInteractions,\n useHandleError,\n useMetaData,\n} from '@/composables/Common.js';\nimport { useMainStore } from '@/stores/mainStore';\nimport { useQuery } from 'villus';\nimport { useRoute } from 'vue-router';\n\nconst Datepicker = defineAsyncComponent(() => import('@/components/calendar/DatePicker.vue'));\n\nconst props = defineProps<{\n date?: string;\n view?: string;\n}>();\n\nconst { detectKeyboardUser, focusFirstChild } = useA11y();\nconst { formatToString } = useDateFormat();\nconst { ga4Event } = useAnalytics();\nconst { handleError } = useHandleError();\nconst { setMetaDescription, setMetaTitle } = useMetaData();\nconst route = useRoute();\nconst store = useMainStore();\nconst { setValue } = store;\n\nconst appConfig = inject<AppConfig>('appConfig');\n\nlet allActiveDates;\n\nconst activeDates = ref([]);\nconst activeEvents = ref([]);\nconst activeFilters = ref<string[]>([]);\nconst checkedDate = ref(false);\nconst datepickerDisabled = ref<boolean>(false);\nconst datepickerRef = ref(null);\nconst eventOccurrences = ref<{\n nodes: EventInterface[];\n pageInfo: {\n hasMoreEventOccurrences: boolean;\n };\n}>({});\nconst filterDropdown = ref(null);\nconst moreDisabled = ref(false);\nconst moreSlices = ref(false);\nconst pickedDate = ref('');\nconst selected = ref('');\nconst selectedDate = ref(props.date);\nconst selectedFilters = ref<string[]>([]);\nconst sliceEnd = ref(20);\nconst sliceSize = ref(20);\nconst sliceStart = ref(0);\nconst totalCount = ref(0);\n\nconst { selectNav } = useFilterInteractions(selected);\n\nconst { data, error } = useQuery({\n onData: data => {\n setValue({ type: 'dataLoaded', value: true });\n setMetaTitle(title);\n eventOccurrences.value.nodes = [];\n eventOccurrences.value.pageInfo = data.eventOccurrences.pageInfo;\n\n if (data.eventOccurrences.nodes.length) {\n setMetaDescription(data.eventOccurrences.nodes[0].excerpt);\n Object.keys(data.eventOccurrences.nodes).map((key) => {\n // Build array of all valid active dates.\n if (\n !activeDates.value.includes(data.eventOccurrences.nodes[key].start.isoDate) &&\n data.eventOccurrences.nodes[key].start.isoDate >= today.value\n ) {\n activeDates.value.push(data.eventOccurrences.nodes[key].start.isoDate);\n }\n\n // Build array of all current event occurrences.\n if (data.eventOccurrences.nodes[key].start.isoDate >= today.value) {\n eventOccurrences.value.nodes.push(data.eventOccurrences.nodes[key]);\n }\n });\n allActiveDates = activeDates.value;\n loadData();\n }\n\n if (!data) {\n handleError(title, error);\n }\n\n nextTick().then(() => {\n detectKeyboardUser();\n });\n },\n query: calendarQuery,\n});\n\nconst firstDate = computed(() => {\n return selectedDate.value !== activeEvents.value[0].start.isoDate\n ? parseISO(selectedDate.value)\n : parseISO(activeEvents.value[0].start.isoDate);\n});\nconst title = 'Calendar';\nconst today = computed(() => appConfig.today.isoDate);\n\nwatch(activeFilters, () => updateFilters());\n\nwatch(checkedDate, () => {\n handleDate();\n});\n\n/**\n * Watch for date changes, trigger navigation and send GA4 event.\n */\nwatch(selectedDate, () => {\n setUrl();\n resetSlice();\n loadData();\n ga4Event({\n filter_location: 'calendar',\n filter_type: 'date',\n filter_value: selectedDate.value.toString(),\n gtm_tag: 'filter',\n });\n});\n\nwatch(selectedFilters, () => {\n activeFilters.value = selectedFilters.value;\n updateFilters();\n});\n\nonMounted(() => {\n /*\n ?filterSets=%7B\"calendar\"%3A%5B\"Lectures%20%26amp%3B%20Symposia\", \"Concerts%20%26amp%3B%20Performances\", \"Special%20Events\"%5D%7D\n */\n if (route.query.filterSets) {\n const legacyFilters = JSON.parse(route.query.filterSets as string).calendar;\n\n legacyFilters.map((filter) => {\n const current = filter.replace('&', '');\n\n activeFilters.value.push(slugify(current));\n selectedFilters.value.push(slugify(current));\n });\n }\n\n /*\n ?q=lectures-symposia,concerts-performances,special-events\n */\n if (route.query.q) {\n route.query.q.split(',').map((filter) => {\n activeFilters.value.push(filter);\n selectedFilters.value.push(filter);\n });\n }\n\n pickedDate.value = route.params.date || '';\n});\n\nfunction isActiveFilter(key: string): boolean {\n return activeFilters.value.indexOf(key) >= 0;\n}\n\nfunction clearAll() {\n activeFilters.value = [];\n selectedFilters.value = [];\n handleDate();\n}\n\nfunction getDay(date: string): string {\n const selected = date.split('-');\n\n return `${monthNames[Number(selected[1]) - 1]} ${parseInt(selected[2])}`;\n}\n\nfunction handleDate() {\n if (selectedDate.value === pickedDate.value) {\n pickedDate.value = '';\n }\n\n selectedDate.value = today.value;\n setUrl(true);\n resetSlice();\n loadData();\n}\n\n/**\n * Loads the next slice of events.\n */\nfunction loadData(): void {\n const temp = [];\n\n // Purge active events when there is a new slice.\n if (sliceStart.value === 0) {\n activeDates.value = [];\n activeEvents.value = [];\n }\n\n Object.keys(eventOccurrences.value.nodes).map((key) => {\n const event = eventOccurrences.value.nodes[key];\n\n if (activeFilters.value.length) {\n for (let i = 0; i < event.eventTypes.nodes.length; i++) {\n if (activeFilters.value.indexOf(event.eventTypes.nodes[i].slug) > -1) {\n // Filter active dates.\n if (\n !activeDates.value.includes(event.start.isoDate) &&\n event.start.isoDate >= today.value\n ) {\n activeDates.value.push(event.start.isoDate);\n }\n\n // Filter event occurrences.\n if (event.start.isoDate >= selectedDate.value) {\n temp.push(event);\n break;\n }\n }\n }\n }\n\n if (!activeFilters.value.length) {\n activeDates.value = allActiveDates;\n\n if (event.start.isoDate >= selectedDate.value) {\n temp.push(event);\n }\n }\n });\n\n // Conditionally disable datepicker.\n datepickerDisabled.value = activeDates.value.length === 0;\n\n if (moreSlices.value || (sliceStart.value === 0 && temp.length)) {\n // Display the current slice of event occurrences.\n activeEvents.value.push(...temp.slice(sliceStart.value, sliceEnd.value));\n moreSlices.value = sliceEnd.value < temp.length;\n }\n\n // Increment next slice bounds.\n if (moreSlices.value) {\n sliceStart.value = sliceEnd.value;\n sliceEnd.value =\n sliceEnd.value + sliceSize.value < temp.length\n ? sliceEnd.value + sliceSize.value\n : temp.length;\n\n ga4Event({\n click_type: 'load_more',\n component: 'events',\n content_group: 'calendar',\n gtm_tag: 'interaction',\n link_text: 'Load More Results',\n });\n }\n\n // Set load more button state.\n moreDisabled.value = !moreSlices.value;\n totalCount.value = temp.length;\n}\n\n/**\n * Generates the no events found message.\n */\nfunction noEventsFound(): string {\n let str = '';\n\n for (let i = 0; i < activeFilters.value.length; i++) {\n str += filters[activeFilters.value[i]];\n\n if (activeFilters.value.length > 1 && i < activeFilters.value.length - 1) {\n str += ' or ';\n }\n }\n\n return str.slice(-6).toLowerCase() === 'events' ? str : `${str} events`;\n}\n\nfunction parseISO(date) {\n return new Date(`${date}T00:00:00`);\n}\n\n/**\n * Resets the slice start and end values.\n */\nfunction resetSlice(): void {\n sliceStart.value = 0;\n sliceEnd.value = sliceSize.value;\n}\n\n/**\n * Sets, and navigates the user to, the target URL when filters or datepicker date is changed.\n */\nfunction setUrl(isDeselected: boolean = false): void {\n const base = route.path.indexOf('calendar/month') > -1 ? '/calendar/month' : '/calendar/day';\n const date = isDeselected ? '' : selectedDate.value;\n\n let url =\n selectedDate.value && today.value !== selectedDate.value\n ? `${base}/${date}`\n : base;\n\n url = activeFilters.value.length ? url + '?q=' + activeFilters.value.join(',') : url;\n window.history.pushState({}, '', url);\n}\n\nfunction setUserPick(date: string): void {\n pickedDate.value = date;\n}\n\nfunction toggle(type: string): void {\n selectNav(type, [datepickerRef.value._.refs.datepicker, filterDropdown.value]);\n ga4Event({\n filter_location: 'calendar',\n filter_type: 'datepicker',\n filter_value: selected.value ? 'close' : 'open',\n gtm_tag: 'filter',\n });\n}\n\nfunction updateFilters(): void {\n if (JSON.stringify(selectedFilters.value) !== JSON.stringify(activeFilters.value)) {\n selectedFilters.value = activeFilters.value;\n }\n\n setUrl();\n resetSlice();\n loadData();\n ga4Event({\n filter_location: 'calendar',\n filter_type: 'filter',\n filter_value: activeFilters.value.join(','),\n gtm_tag: 'filter',\n });\n}\n</script>\n\n<script lang=\"ts\">\nexport default {\n beforeRoute(params, villusClient) {\n return new Promise<void>((resolve, reject) => {\n villusClient\n .executeQuery({\n query: calendarQuery,\n variables: {},\n })\n .then(() => resolve())\n .catch((err) => reject(err));\n });\n },\n};\n</script>\n\n<style lang=\"scss\">\n@use '@/styles/links.module.scss' as *;\n@use '@/styles/navigation.module.scss' as *;\n</style>\n\n<style lang=\"scss\" module>\n.checkbox {\n height: 24px;\n width: 24px;\n}\n.datepicker {\n position: absolute;\n left: -0.25rem;\n margin-top: px-to-rem(4);\n width: 100vw;\n}\n.header {\n &::after {\n @include line;\n\n & {\n margin-top: 1rem;\n }\n }\n}\n\n.load-more {\n @include space-48-64-above;\n\n button {\n margin: 1rem auto 0 auto;\n width: fit-content;\n display: block;\n }\n\n p {\n text-align: center;\n }\n}\n\n.link {\n margin-left: 1rem;\n\n &:first-of-type {\n margin-left: 0;\n }\n\n &.active {\n a {\n border-bottom: 2px solid #171717;\n cursor: text;\n\n &:focus,\n &:hover {\n text-decoration: none;\n }\n }\n }\n\n a {\n text-decoration: none;\n\n &:focus,\n &:hover {\n text-decoration: underline;\n }\n }\n}\n\n.nav {\n font-family: $guggensans;\n line-height: px-to-rem(20);\n margin: 2rem 0 1rem;\n padding: 0;\n width: fit-content;\n\n button {\n color: $black;\n cursor: pointer;\n\n &:hover {\n text-decoration: none;\n }\n }\n\n > div {\n cursor: pointer;\n list-style: none;\n margin-right: 1rem;\n\n > div {\n display: inline-block;\n width: fit-content;\n }\n\n &:first-of-type {\n margin-right: 0;\n text-align: center;\n }\n\n &:last-of-type {\n margin-right: 0;\n margin-top: 0.5rem;\n }\n }\n\n :global(.nav-subtypes) {\n &:global(.active) {\n :global(.nav-items) {\n border: 1px solid $black;\n left: 0;\n padding-bottom: 0;\n position: absolute;\n white-space: nowrap;\n width: calc(100vw - 2rem);\n\n :global(.apply) {\n position: sticky;\n }\n }\n }\n }\n}\n\n.selected-filters {\n margin-top: 4rem;\n padding-bottom: 1rem;\n\n &::before {\n @include line;\n\n & {\n margin-top: -2rem;\n }\n }\n\n div {\n display: inline-block;\n margin: 1rem 0.5rem 0 0;\n\n &:last-of-type{\n margin-right: 1rem;\n }\n\n input[type='checkbox'] {\n height: 0;\n opacity: 0;\n position: absolute;\n width: 0;\n\n &::after {\n display: none;\n }\n }\n\n label {\n text-decoration: underline;\n }\n }\n}\n\n.selected {\n background-color: $black;\n}\n\n.selection {\n position: relative;\n\n button {\n &:hover {\n text-decoration: underline;\n }\n }\n}\n\n@media (min-width: $break-point) {\n .datepicker {\n transform: none;\n width: px-to-rem(300);\n }\n\n .frame {\n @include grid-content;\n }\n\n .header {\n h1 {\n margin-top: 0;\n }\n }\n\n .header,\n .occurrences {\n grid-column: 1 / span 8;\n }\n\n .nav {\n align-items: center;\n display: grid;\n grid-auto-columns: max-content;\n grid-auto-flow: column;\n\n > div {\n &:first-of-type {\n margin-right: 1rem;\n }\n\n &:last-of-type {\n margin-top: 0;\n }\n\n > div {\n &.nav-filters {\n left: px-to-rem(115);\n top: px-to-rem(28);\n z-index: get-zindex(submenu);\n }\n }\n }\n\n :global(.nav-subtypes) {\n &:global(.active) {\n :global(.nav-items) {\n left: auto;\n width: fit-content;\n }\n }\n }\n }\n}\n</style>\n"],"file":"assets/CalendarSection-CcH0-c7Q.js"}