{"version":3,"file":"index.js","sources":["../../../../../fe-src/node_modules/react-helmet-async/lib/index.esm.js","../../../../../fe-src/src/components/furniture/Logo.jsx","../../../../../fe-src/src/components/helpers/Context.jsx","../../../../../fe-src/theme.config.js","../../../../../fe-src/src/helpers/style.js","../../../../../fe-src/src/components/helpers/ctas/Button.jsx","../../../../../fe-src/src/components/furniture/MainNav.jsx","../../../../../fe-src/src/components/furniture/MobileNav.jsx","../../../../../fe-src/src/components/furniture/Search.jsx","../../../../../fe-src/src/components/furniture/CTA.jsx","../../../../../fe-src/src/components/furniture/Header.jsx","../../../../../fe-src/src/components/furniture/Breadcrumbs.jsx","../../../../../fe-src/src/helpers/markup.jsx","../../../../../fe-src/src/components/furniture/StickyFooter.jsx","../../../../../fe-src/src/components/furniture/BackToTop.jsx","../../../../../fe-src/src/components/furniture/Footer.jsx","../../../../../fe-src/src/components/helpers/Loader.jsx","../../../../../fe-src/src/components/furniture/Alert.jsx","../../../../../fe-src/src/components/furniture/Skip.jsx","../../../../../fe-src/src/components/helpers/TitleBlock.jsx","../../../../../fe-src/src/components/sections/_Section.jsx","../../../../../fe-src/src/components/sections/Accordion.jsx","../../../../../fe-src/src/components/sections/BasicContent.jsx","../../../../../fe-src/src/components/sections/CalloutCard.jsx","../../../../../fe-src/src/components/helpers/Image.jsx","../../../../../fe-src/src/components/helpers/CardListingHeroTitle.jsx","../../../../../fe-src/src/components/helpers/Picture.jsx","../../../../../fe-src/src/components/sections/CardListCurated.jsx","../../../../../fe-src/src/components/sections/CardListDynamic.jsx","../../../../../fe-src/src/components/sections/ContentFiftybyFifty.jsx","../../../../../fe-src/src/components/sections/HeroBanner.jsx","../../../../../fe-src/src/components/sections/InformationBanner.jsx","../../../../../fe-src/src/components/sections/RatesCalculator.jsx","../../../../../fe-src/src/components/sections/RatesCalloutCard.jsx","../../../../../fe-src/src/components/sections/RatesCardList.jsx","../../../../../fe-src/src/components/sections/SearchResult.jsx","../../../../../fe-src/src/components/sections/SubPageBanner.jsx","../../../../../fe-src/src/helpers/thirdparty.js","../../../../../fe-src/src/components/sections/ThirdParty.jsx","../../../../../fe-src/src/components/Page.jsx","../../../../../fe-src/src/App.jsx","../../../../../fe-src/src/entry-server.jsx"],"sourcesContent":["// src/index.tsx\nimport React3, { Component as Component3 } from \"react\";\nimport fastCompare from \"react-fast-compare\";\nimport invariant from \"invariant\";\n\n// src/Provider.tsx\nimport React2, { Component } from \"react\";\n\n// src/server.ts\nimport React from \"react\";\n\n// src/constants.ts\nvar TAG_NAMES = /* @__PURE__ */ ((TAG_NAMES2) => {\n TAG_NAMES2[\"BASE\"] = \"base\";\n TAG_NAMES2[\"BODY\"] = \"body\";\n TAG_NAMES2[\"HEAD\"] = \"head\";\n TAG_NAMES2[\"HTML\"] = \"html\";\n TAG_NAMES2[\"LINK\"] = \"link\";\n TAG_NAMES2[\"META\"] = \"meta\";\n TAG_NAMES2[\"NOSCRIPT\"] = \"noscript\";\n TAG_NAMES2[\"SCRIPT\"] = \"script\";\n TAG_NAMES2[\"STYLE\"] = \"style\";\n TAG_NAMES2[\"TITLE\"] = \"title\";\n TAG_NAMES2[\"FRAGMENT\"] = \"Symbol(react.fragment)\";\n return TAG_NAMES2;\n})(TAG_NAMES || {});\nvar SEO_PRIORITY_TAGS = {\n link: { rel: [\"amphtml\", \"canonical\", \"alternate\"] },\n script: { type: [\"application/ld+json\"] },\n meta: {\n charset: \"\",\n name: [\"generator\", \"robots\", \"description\"],\n property: [\n \"og:type\",\n \"og:title\",\n \"og:url\",\n \"og:image\",\n \"og:image:alt\",\n \"og:description\",\n \"twitter:url\",\n \"twitter:title\",\n \"twitter:description\",\n \"twitter:image\",\n \"twitter:image:alt\",\n \"twitter:card\",\n \"twitter:site\"\n ]\n }\n};\nvar VALID_TAG_NAMES = Object.values(TAG_NAMES);\nvar REACT_TAG_MAP = {\n accesskey: \"accessKey\",\n charset: \"charSet\",\n class: \"className\",\n contenteditable: \"contentEditable\",\n contextmenu: \"contextMenu\",\n \"http-equiv\": \"httpEquiv\",\n itemprop: \"itemProp\",\n tabindex: \"tabIndex\"\n};\nvar HTML_TAG_MAP = Object.entries(REACT_TAG_MAP).reduce(\n (carry, [key, value]) => {\n carry[value] = key;\n return carry;\n },\n {}\n);\nvar HELMET_ATTRIBUTE = \"data-rh\";\n\n// src/utils.ts\nvar HELMET_PROPS = {\n DEFAULT_TITLE: \"defaultTitle\",\n DEFER: \"defer\",\n ENCODE_SPECIAL_CHARACTERS: \"encodeSpecialCharacters\",\n ON_CHANGE_CLIENT_STATE: \"onChangeClientState\",\n TITLE_TEMPLATE: \"titleTemplate\",\n PRIORITIZE_SEO_TAGS: \"prioritizeSeoTags\"\n};\nvar getInnermostProperty = (propsList, property) => {\n for (let i = propsList.length - 1; i >= 0; i -= 1) {\n const props = propsList[i];\n if (Object.prototype.hasOwnProperty.call(props, property)) {\n return props[property];\n }\n }\n return null;\n};\nvar getTitleFromPropsList = (propsList) => {\n let innermostTitle = getInnermostProperty(propsList, \"title\" /* TITLE */);\n const innermostTemplate = getInnermostProperty(propsList, HELMET_PROPS.TITLE_TEMPLATE);\n if (Array.isArray(innermostTitle)) {\n innermostTitle = innermostTitle.join(\"\");\n }\n if (innermostTemplate && innermostTitle) {\n return innermostTemplate.replace(/%s/g, () => innermostTitle);\n }\n const innermostDefaultTitle = getInnermostProperty(propsList, HELMET_PROPS.DEFAULT_TITLE);\n return innermostTitle || innermostDefaultTitle || void 0;\n};\nvar getOnChangeClientState = (propsList) => getInnermostProperty(propsList, HELMET_PROPS.ON_CHANGE_CLIENT_STATE) || (() => {\n});\nvar getAttributesFromPropsList = (tagType, propsList) => propsList.filter((props) => typeof props[tagType] !== \"undefined\").map((props) => props[tagType]).reduce((tagAttrs, current) => ({ ...tagAttrs, ...current }), {});\nvar getBaseTagFromPropsList = (primaryAttributes, propsList) => propsList.filter((props) => typeof props[\"base\" /* BASE */] !== \"undefined\").map((props) => props[\"base\" /* BASE */]).reverse().reduce((innermostBaseTag, tag) => {\n if (!innermostBaseTag.length) {\n const keys = Object.keys(tag);\n for (let i = 0; i < keys.length; i += 1) {\n const attributeKey = keys[i];\n const lowerCaseAttributeKey = attributeKey.toLowerCase();\n if (primaryAttributes.indexOf(lowerCaseAttributeKey) !== -1 && tag[lowerCaseAttributeKey]) {\n return innermostBaseTag.concat(tag);\n }\n }\n }\n return innermostBaseTag;\n}, []);\nvar warn = (msg) => console && typeof console.warn === \"function\" && console.warn(msg);\nvar getTagsFromPropsList = (tagName, primaryAttributes, propsList) => {\n const approvedSeenTags = {};\n return propsList.filter((props) => {\n if (Array.isArray(props[tagName])) {\n return true;\n }\n if (typeof props[tagName] !== \"undefined\") {\n warn(\n `Helmet: ${tagName} should be of type \"Array\". Instead found type \"${typeof props[tagName]}\"`\n );\n }\n return false;\n }).map((props) => props[tagName]).reverse().reduce((approvedTags, instanceTags) => {\n const instanceSeenTags = {};\n instanceTags.filter((tag) => {\n let primaryAttributeKey;\n const keys2 = Object.keys(tag);\n for (let i = 0; i < keys2.length; i += 1) {\n const attributeKey = keys2[i];\n const lowerCaseAttributeKey = attributeKey.toLowerCase();\n if (primaryAttributes.indexOf(lowerCaseAttributeKey) !== -1 && !(primaryAttributeKey === \"rel\" /* REL */ && tag[primaryAttributeKey].toLowerCase() === \"canonical\") && !(lowerCaseAttributeKey === \"rel\" /* REL */ && tag[lowerCaseAttributeKey].toLowerCase() === \"stylesheet\")) {\n primaryAttributeKey = lowerCaseAttributeKey;\n }\n if (primaryAttributes.indexOf(attributeKey) !== -1 && (attributeKey === \"innerHTML\" /* INNER_HTML */ || attributeKey === \"cssText\" /* CSS_TEXT */ || attributeKey === \"itemprop\" /* ITEM_PROP */)) {\n primaryAttributeKey = attributeKey;\n }\n }\n if (!primaryAttributeKey || !tag[primaryAttributeKey]) {\n return false;\n }\n const value = tag[primaryAttributeKey].toLowerCase();\n if (!approvedSeenTags[primaryAttributeKey]) {\n approvedSeenTags[primaryAttributeKey] = {};\n }\n if (!instanceSeenTags[primaryAttributeKey]) {\n instanceSeenTags[primaryAttributeKey] = {};\n }\n if (!approvedSeenTags[primaryAttributeKey][value]) {\n instanceSeenTags[primaryAttributeKey][value] = true;\n return true;\n }\n return false;\n }).reverse().forEach((tag) => approvedTags.push(tag));\n const keys = Object.keys(instanceSeenTags);\n for (let i = 0; i < keys.length; i += 1) {\n const attributeKey = keys[i];\n const tagUnion = {\n ...approvedSeenTags[attributeKey],\n ...instanceSeenTags[attributeKey]\n };\n approvedSeenTags[attributeKey] = tagUnion;\n }\n return approvedTags;\n }, []).reverse();\n};\nvar getAnyTrueFromPropsList = (propsList, checkedTag) => {\n if (Array.isArray(propsList) && propsList.length) {\n for (let index = 0; index < propsList.length; index += 1) {\n const prop = propsList[index];\n if (prop[checkedTag]) {\n return true;\n }\n }\n }\n return false;\n};\nvar reducePropsToState = (propsList) => ({\n baseTag: getBaseTagFromPropsList([\"href\" /* HREF */], propsList),\n bodyAttributes: getAttributesFromPropsList(\"bodyAttributes\" /* BODY */, propsList),\n defer: getInnermostProperty(propsList, HELMET_PROPS.DEFER),\n encode: getInnermostProperty(propsList, HELMET_PROPS.ENCODE_SPECIAL_CHARACTERS),\n htmlAttributes: getAttributesFromPropsList(\"htmlAttributes\" /* HTML */, propsList),\n linkTags: getTagsFromPropsList(\n \"link\" /* LINK */,\n [\"rel\" /* REL */, \"href\" /* HREF */],\n propsList\n ),\n metaTags: getTagsFromPropsList(\n \"meta\" /* META */,\n [\n \"name\" /* NAME */,\n \"charset\" /* CHARSET */,\n \"http-equiv\" /* HTTPEQUIV */,\n \"property\" /* PROPERTY */,\n \"itemprop\" /* ITEM_PROP */\n ],\n propsList\n ),\n noscriptTags: getTagsFromPropsList(\"noscript\" /* NOSCRIPT */, [\"innerHTML\" /* INNER_HTML */], propsList),\n onChangeClientState: getOnChangeClientState(propsList),\n scriptTags: getTagsFromPropsList(\n \"script\" /* SCRIPT */,\n [\"src\" /* SRC */, \"innerHTML\" /* INNER_HTML */],\n propsList\n ),\n styleTags: getTagsFromPropsList(\"style\" /* STYLE */, [\"cssText\" /* CSS_TEXT */], propsList),\n title: getTitleFromPropsList(propsList),\n titleAttributes: getAttributesFromPropsList(\"titleAttributes\" /* TITLE */, propsList),\n prioritizeSeoTags: getAnyTrueFromPropsList(propsList, HELMET_PROPS.PRIORITIZE_SEO_TAGS)\n});\nvar flattenArray = (possibleArray) => Array.isArray(possibleArray) ? possibleArray.join(\"\") : possibleArray;\nvar checkIfPropsMatch = (props, toMatch) => {\n const keys = Object.keys(props);\n for (let i = 0; i < keys.length; i += 1) {\n if (toMatch[keys[i]] && toMatch[keys[i]].includes(props[keys[i]])) {\n return true;\n }\n }\n return false;\n};\nvar prioritizer = (elementsList, propsToMatch) => {\n if (Array.isArray(elementsList)) {\n return elementsList.reduce(\n (acc, elementAttrs) => {\n if (checkIfPropsMatch(elementAttrs, propsToMatch)) {\n acc.priority.push(elementAttrs);\n } else {\n acc.default.push(elementAttrs);\n }\n return acc;\n },\n { priority: [], default: [] }\n );\n }\n return { default: elementsList, priority: [] };\n};\nvar without = (obj, key) => {\n return {\n ...obj,\n [key]: void 0\n };\n};\n\n// src/server.ts\nvar SELF_CLOSING_TAGS = [\"noscript\" /* NOSCRIPT */, \"script\" /* SCRIPT */, \"style\" /* STYLE */];\nvar encodeSpecialCharacters = (str, encode = true) => {\n if (encode === false) {\n return String(str);\n }\n return String(str).replace(/&/g, \"&\").replace(//g, \">\").replace(/\"/g, \""\").replace(/'/g, \"'\");\n};\nvar generateElementAttributesAsString = (attributes) => Object.keys(attributes).reduce((str, key) => {\n const attr = typeof attributes[key] !== \"undefined\" ? `${key}=\"${attributes[key]}\"` : `${key}`;\n return str ? `${str} ${attr}` : attr;\n}, \"\");\nvar generateTitleAsString = (type, title, attributes, encode) => {\n const attributeString = generateElementAttributesAsString(attributes);\n const flattenedTitle = flattenArray(title);\n return attributeString ? `<${type} ${HELMET_ATTRIBUTE}=\"true\" ${attributeString}>${encodeSpecialCharacters(\n flattenedTitle,\n encode\n )}` : `<${type} ${HELMET_ATTRIBUTE}=\"true\">${encodeSpecialCharacters(\n flattenedTitle,\n encode\n )}`;\n};\nvar generateTagsAsString = (type, tags, encode = true) => tags.reduce((str, t) => {\n const tag = t;\n const attributeHtml = Object.keys(tag).filter(\n (attribute) => !(attribute === \"innerHTML\" /* INNER_HTML */ || attribute === \"cssText\" /* CSS_TEXT */)\n ).reduce((string, attribute) => {\n const attr = typeof tag[attribute] === \"undefined\" ? attribute : `${attribute}=\"${encodeSpecialCharacters(tag[attribute], encode)}\"`;\n return string ? `${string} ${attr}` : attr;\n }, \"\");\n const tagContent = tag.innerHTML || tag.cssText || \"\";\n const isSelfClosing = SELF_CLOSING_TAGS.indexOf(type) === -1;\n return `${str}<${type} ${HELMET_ATTRIBUTE}=\"true\" ${attributeHtml}${isSelfClosing ? `/>` : `>${tagContent}`}`;\n}, \"\");\nvar convertElementAttributesToReactProps = (attributes, initProps = {}) => Object.keys(attributes).reduce((obj, key) => {\n const mapped = REACT_TAG_MAP[key];\n obj[mapped || key] = attributes[key];\n return obj;\n}, initProps);\nvar generateTitleAsReactComponent = (_type, title, attributes) => {\n const initProps = {\n key: title,\n [HELMET_ATTRIBUTE]: true\n };\n const props = convertElementAttributesToReactProps(attributes, initProps);\n return [React.createElement(\"title\" /* TITLE */, props, title)];\n};\nvar generateTagsAsReactComponent = (type, tags) => tags.map((tag, i) => {\n const mappedTag = {\n key: i,\n [HELMET_ATTRIBUTE]: true\n };\n Object.keys(tag).forEach((attribute) => {\n const mapped = REACT_TAG_MAP[attribute];\n const mappedAttribute = mapped || attribute;\n if (mappedAttribute === \"innerHTML\" /* INNER_HTML */ || mappedAttribute === \"cssText\" /* CSS_TEXT */) {\n const content = tag.innerHTML || tag.cssText;\n mappedTag.dangerouslySetInnerHTML = { __html: content };\n } else {\n mappedTag[mappedAttribute] = tag[attribute];\n }\n });\n return React.createElement(type, mappedTag);\n});\nvar getMethodsForTag = (type, tags, encode = true) => {\n switch (type) {\n case \"title\" /* TITLE */:\n return {\n toComponent: () => generateTitleAsReactComponent(type, tags.title, tags.titleAttributes),\n toString: () => generateTitleAsString(type, tags.title, tags.titleAttributes, encode)\n };\n case \"bodyAttributes\" /* BODY */:\n case \"htmlAttributes\" /* HTML */:\n return {\n toComponent: () => convertElementAttributesToReactProps(tags),\n toString: () => generateElementAttributesAsString(tags)\n };\n default:\n return {\n toComponent: () => generateTagsAsReactComponent(type, tags),\n toString: () => generateTagsAsString(type, tags, encode)\n };\n }\n};\nvar getPriorityMethods = ({ metaTags, linkTags, scriptTags, encode }) => {\n const meta = prioritizer(metaTags, SEO_PRIORITY_TAGS.meta);\n const link = prioritizer(linkTags, SEO_PRIORITY_TAGS.link);\n const script = prioritizer(scriptTags, SEO_PRIORITY_TAGS.script);\n const priorityMethods = {\n toComponent: () => [\n ...generateTagsAsReactComponent(\"meta\" /* META */, meta.priority),\n ...generateTagsAsReactComponent(\"link\" /* LINK */, link.priority),\n ...generateTagsAsReactComponent(\"script\" /* SCRIPT */, script.priority)\n ],\n toString: () => (\n // generate all the tags as strings and concatenate them\n `${getMethodsForTag(\"meta\" /* META */, meta.priority, encode)} ${getMethodsForTag(\n \"link\" /* LINK */,\n link.priority,\n encode\n )} ${getMethodsForTag(\"script\" /* SCRIPT */, script.priority, encode)}`\n )\n };\n return {\n priorityMethods,\n metaTags: meta.default,\n linkTags: link.default,\n scriptTags: script.default\n };\n};\nvar mapStateOnServer = (props) => {\n const {\n baseTag,\n bodyAttributes,\n encode = true,\n htmlAttributes,\n noscriptTags,\n styleTags,\n title = \"\",\n titleAttributes,\n prioritizeSeoTags\n } = props;\n let { linkTags, metaTags, scriptTags } = props;\n let priorityMethods = {\n toComponent: () => {\n },\n toString: () => \"\"\n };\n if (prioritizeSeoTags) {\n ({ priorityMethods, linkTags, metaTags, scriptTags } = getPriorityMethods(props));\n }\n return {\n priority: priorityMethods,\n base: getMethodsForTag(\"base\" /* BASE */, baseTag, encode),\n bodyAttributes: getMethodsForTag(\"bodyAttributes\" /* BODY */, bodyAttributes, encode),\n htmlAttributes: getMethodsForTag(\"htmlAttributes\" /* HTML */, htmlAttributes, encode),\n link: getMethodsForTag(\"link\" /* LINK */, linkTags, encode),\n meta: getMethodsForTag(\"meta\" /* META */, metaTags, encode),\n noscript: getMethodsForTag(\"noscript\" /* NOSCRIPT */, noscriptTags, encode),\n script: getMethodsForTag(\"script\" /* SCRIPT */, scriptTags, encode),\n style: getMethodsForTag(\"style\" /* STYLE */, styleTags, encode),\n title: getMethodsForTag(\"title\" /* TITLE */, { title, titleAttributes }, encode)\n };\n};\nvar server_default = mapStateOnServer;\n\n// src/HelmetData.ts\nvar instances = [];\nvar isDocument = !!(typeof window !== \"undefined\" && window.document && window.document.createElement);\nvar HelmetData = class {\n instances = [];\n canUseDOM = isDocument;\n context;\n value = {\n setHelmet: (serverState) => {\n this.context.helmet = serverState;\n },\n helmetInstances: {\n get: () => this.canUseDOM ? instances : this.instances,\n add: (instance) => {\n (this.canUseDOM ? instances : this.instances).push(instance);\n },\n remove: (instance) => {\n const index = (this.canUseDOM ? instances : this.instances).indexOf(instance);\n (this.canUseDOM ? instances : this.instances).splice(index, 1);\n }\n }\n };\n constructor(context, canUseDOM) {\n this.context = context;\n this.canUseDOM = canUseDOM || false;\n if (!canUseDOM) {\n context.helmet = server_default({\n baseTag: [],\n bodyAttributes: {},\n encodeSpecialCharacters: true,\n htmlAttributes: {},\n linkTags: [],\n metaTags: [],\n noscriptTags: [],\n scriptTags: [],\n styleTags: [],\n title: \"\",\n titleAttributes: {}\n });\n }\n }\n};\n\n// src/Provider.tsx\nvar defaultValue = {};\nvar Context = React2.createContext(defaultValue);\nvar HelmetProvider = class _HelmetProvider extends Component {\n static canUseDOM = isDocument;\n helmetData;\n constructor(props) {\n super(props);\n this.helmetData = new HelmetData(this.props.context || {}, _HelmetProvider.canUseDOM);\n }\n render() {\n return /* @__PURE__ */ React2.createElement(Context.Provider, { value: this.helmetData.value }, this.props.children);\n }\n};\n\n// src/Dispatcher.tsx\nimport { Component as Component2 } from \"react\";\nimport shallowEqual from \"shallowequal\";\n\n// src/client.ts\nvar updateTags = (type, tags) => {\n const headElement = document.head || document.querySelector(\"head\" /* HEAD */);\n const tagNodes = headElement.querySelectorAll(`${type}[${HELMET_ATTRIBUTE}]`);\n const oldTags = [].slice.call(tagNodes);\n const newTags = [];\n let indexToDelete;\n if (tags && tags.length) {\n tags.forEach((tag) => {\n const newElement = document.createElement(type);\n for (const attribute in tag) {\n if (Object.prototype.hasOwnProperty.call(tag, attribute)) {\n if (attribute === \"innerHTML\" /* INNER_HTML */) {\n newElement.innerHTML = tag.innerHTML;\n } else if (attribute === \"cssText\" /* CSS_TEXT */) {\n if (newElement.styleSheet) {\n newElement.styleSheet.cssText = tag.cssText;\n } else {\n newElement.appendChild(document.createTextNode(tag.cssText));\n }\n } else {\n const attr = attribute;\n const value = typeof tag[attr] === \"undefined\" ? \"\" : tag[attr];\n newElement.setAttribute(attribute, value);\n }\n }\n }\n newElement.setAttribute(HELMET_ATTRIBUTE, \"true\");\n if (oldTags.some((existingTag, index) => {\n indexToDelete = index;\n return newElement.isEqualNode(existingTag);\n })) {\n oldTags.splice(indexToDelete, 1);\n } else {\n newTags.push(newElement);\n }\n });\n }\n oldTags.forEach((tag) => tag.parentNode?.removeChild(tag));\n newTags.forEach((tag) => headElement.appendChild(tag));\n return {\n oldTags,\n newTags\n };\n};\nvar updateAttributes = (tagName, attributes) => {\n const elementTag = document.getElementsByTagName(tagName)[0];\n if (!elementTag) {\n return;\n }\n const helmetAttributeString = elementTag.getAttribute(HELMET_ATTRIBUTE);\n const helmetAttributes = helmetAttributeString ? helmetAttributeString.split(\",\") : [];\n const attributesToRemove = [...helmetAttributes];\n const attributeKeys = Object.keys(attributes);\n for (const attribute of attributeKeys) {\n const value = attributes[attribute] || \"\";\n if (elementTag.getAttribute(attribute) !== value) {\n elementTag.setAttribute(attribute, value);\n }\n if (helmetAttributes.indexOf(attribute) === -1) {\n helmetAttributes.push(attribute);\n }\n const indexToSave = attributesToRemove.indexOf(attribute);\n if (indexToSave !== -1) {\n attributesToRemove.splice(indexToSave, 1);\n }\n }\n for (let i = attributesToRemove.length - 1; i >= 0; i -= 1) {\n elementTag.removeAttribute(attributesToRemove[i]);\n }\n if (helmetAttributes.length === attributesToRemove.length) {\n elementTag.removeAttribute(HELMET_ATTRIBUTE);\n } else if (elementTag.getAttribute(HELMET_ATTRIBUTE) !== attributeKeys.join(\",\")) {\n elementTag.setAttribute(HELMET_ATTRIBUTE, attributeKeys.join(\",\"));\n }\n};\nvar updateTitle = (title, attributes) => {\n if (typeof title !== \"undefined\" && document.title !== title) {\n document.title = flattenArray(title);\n }\n updateAttributes(\"title\" /* TITLE */, attributes);\n};\nvar commitTagChanges = (newState, cb) => {\n const {\n baseTag,\n bodyAttributes,\n htmlAttributes,\n linkTags,\n metaTags,\n noscriptTags,\n onChangeClientState,\n scriptTags,\n styleTags,\n title,\n titleAttributes\n } = newState;\n updateAttributes(\"body\" /* BODY */, bodyAttributes);\n updateAttributes(\"html\" /* HTML */, htmlAttributes);\n updateTitle(title, titleAttributes);\n const tagUpdates = {\n baseTag: updateTags(\"base\" /* BASE */, baseTag),\n linkTags: updateTags(\"link\" /* LINK */, linkTags),\n metaTags: updateTags(\"meta\" /* META */, metaTags),\n noscriptTags: updateTags(\"noscript\" /* NOSCRIPT */, noscriptTags),\n scriptTags: updateTags(\"script\" /* SCRIPT */, scriptTags),\n styleTags: updateTags(\"style\" /* STYLE */, styleTags)\n };\n const addedTags = {};\n const removedTags = {};\n Object.keys(tagUpdates).forEach((tagType) => {\n const { newTags, oldTags } = tagUpdates[tagType];\n if (newTags.length) {\n addedTags[tagType] = newTags;\n }\n if (oldTags.length) {\n removedTags[tagType] = tagUpdates[tagType].oldTags;\n }\n });\n if (cb) {\n cb();\n }\n onChangeClientState(newState, addedTags, removedTags);\n};\nvar _helmetCallback = null;\nvar handleStateChangeOnClient = (newState) => {\n if (_helmetCallback) {\n cancelAnimationFrame(_helmetCallback);\n }\n if (newState.defer) {\n _helmetCallback = requestAnimationFrame(() => {\n commitTagChanges(newState, () => {\n _helmetCallback = null;\n });\n });\n } else {\n commitTagChanges(newState);\n _helmetCallback = null;\n }\n};\nvar client_default = handleStateChangeOnClient;\n\n// src/Dispatcher.tsx\nvar HelmetDispatcher = class extends Component2 {\n rendered = false;\n shouldComponentUpdate(nextProps) {\n return !shallowEqual(nextProps, this.props);\n }\n componentDidUpdate() {\n this.emitChange();\n }\n componentWillUnmount() {\n const { helmetInstances } = this.props.context;\n helmetInstances.remove(this);\n this.emitChange();\n }\n emitChange() {\n const { helmetInstances, setHelmet } = this.props.context;\n let serverState = null;\n const state = reducePropsToState(\n helmetInstances.get().map((instance) => {\n const props = { ...instance.props };\n delete props.context;\n return props;\n })\n );\n if (HelmetProvider.canUseDOM) {\n client_default(state);\n } else if (server_default) {\n serverState = server_default(state);\n }\n setHelmet(serverState);\n }\n // componentWillMount will be deprecated\n // for SSR, initialize on first render\n // constructor is also unsafe in StrictMode\n init() {\n if (this.rendered) {\n return;\n }\n this.rendered = true;\n const { helmetInstances } = this.props.context;\n helmetInstances.add(this);\n this.emitChange();\n }\n render() {\n this.init();\n return null;\n }\n};\n\n// src/index.tsx\nvar Helmet = class extends Component3 {\n static defaultProps = {\n defer: true,\n encodeSpecialCharacters: true,\n prioritizeSeoTags: false\n };\n shouldComponentUpdate(nextProps) {\n return !fastCompare(without(this.props, \"helmetData\"), without(nextProps, \"helmetData\"));\n }\n mapNestedChildrenToProps(child, nestedChildren) {\n if (!nestedChildren) {\n return null;\n }\n switch (child.type) {\n case \"script\" /* SCRIPT */:\n case \"noscript\" /* NOSCRIPT */:\n return {\n innerHTML: nestedChildren\n };\n case \"style\" /* STYLE */:\n return {\n cssText: nestedChildren\n };\n default:\n throw new Error(\n `<${child.type} /> elements are self-closing and can not contain children. Refer to our API for more information.`\n );\n }\n }\n flattenArrayTypeChildren(child, arrayTypeChildren, newChildProps, nestedChildren) {\n return {\n ...arrayTypeChildren,\n [child.type]: [\n ...arrayTypeChildren[child.type] || [],\n {\n ...newChildProps,\n ...this.mapNestedChildrenToProps(child, nestedChildren)\n }\n ]\n };\n }\n mapObjectTypeChildren(child, newProps, newChildProps, nestedChildren) {\n switch (child.type) {\n case \"title\" /* TITLE */:\n return {\n ...newProps,\n [child.type]: nestedChildren,\n titleAttributes: { ...newChildProps }\n };\n case \"body\" /* BODY */:\n return {\n ...newProps,\n bodyAttributes: { ...newChildProps }\n };\n case \"html\" /* HTML */:\n return {\n ...newProps,\n htmlAttributes: { ...newChildProps }\n };\n default:\n return {\n ...newProps,\n [child.type]: { ...newChildProps }\n };\n }\n }\n mapArrayTypeChildrenToProps(arrayTypeChildren, newProps) {\n let newFlattenedProps = { ...newProps };\n Object.keys(arrayTypeChildren).forEach((arrayChildName) => {\n newFlattenedProps = {\n ...newFlattenedProps,\n [arrayChildName]: arrayTypeChildren[arrayChildName]\n };\n });\n return newFlattenedProps;\n }\n warnOnInvalidChildren(child, nestedChildren) {\n invariant(\n VALID_TAG_NAMES.some((name) => child.type === name),\n typeof child.type === \"function\" ? `You may be attempting to nest components within each other, which is not allowed. Refer to our API for more information.` : `Only elements types ${VALID_TAG_NAMES.join(\n \", \"\n )} are allowed. Helmet does not support rendering <${child.type}> elements. Refer to our API for more information.`\n );\n invariant(\n !nestedChildren || typeof nestedChildren === \"string\" || Array.isArray(nestedChildren) && !nestedChildren.some((nestedChild) => typeof nestedChild !== \"string\"),\n `Helmet expects a string as a child of <${child.type}>. Did you forget to wrap your children in braces? ( <${child.type}>{\\`\\`} ) Refer to our API for more information.`\n );\n return true;\n }\n mapChildrenToProps(children, newProps) {\n let arrayTypeChildren = {};\n React3.Children.forEach(children, (child) => {\n if (!child || !child.props) {\n return;\n }\n const { children: nestedChildren, ...childProps } = child.props;\n const newChildProps = Object.keys(childProps).reduce((obj, key) => {\n obj[HTML_TAG_MAP[key] || key] = childProps[key];\n return obj;\n }, {});\n let { type } = child;\n if (typeof type === \"symbol\") {\n type = type.toString();\n } else {\n this.warnOnInvalidChildren(child, nestedChildren);\n }\n switch (type) {\n case \"Symbol(react.fragment)\" /* FRAGMENT */:\n newProps = this.mapChildrenToProps(nestedChildren, newProps);\n break;\n case \"link\" /* LINK */:\n case \"meta\" /* META */:\n case \"noscript\" /* NOSCRIPT */:\n case \"script\" /* SCRIPT */:\n case \"style\" /* STYLE */:\n arrayTypeChildren = this.flattenArrayTypeChildren(\n child,\n arrayTypeChildren,\n newChildProps,\n nestedChildren\n );\n break;\n default:\n newProps = this.mapObjectTypeChildren(child, newProps, newChildProps, nestedChildren);\n break;\n }\n });\n return this.mapArrayTypeChildrenToProps(arrayTypeChildren, newProps);\n }\n render() {\n const { children, ...props } = this.props;\n let newProps = { ...props };\n let { helmetData } = props;\n if (children) {\n newProps = this.mapChildrenToProps(children, newProps);\n }\n if (helmetData && !(helmetData instanceof HelmetData)) {\n const data = helmetData;\n helmetData = new HelmetData(data.context, true);\n delete newProps.helmetData;\n }\n return helmetData ? /* @__PURE__ */ React3.createElement(HelmetDispatcher, { ...newProps, context: helmetData.value }) : /* @__PURE__ */ React3.createElement(Context.Consumer, null, (context) => /* @__PURE__ */ React3.createElement(HelmetDispatcher, { ...newProps, context }));\n }\n};\nexport {\n Helmet,\n HelmetData,\n HelmetProvider\n};\n","function Logo(props) {\r\n return (\r\n \r\n \r\n {(props.mobLogo || props.deskLogo) && (\r\n \r\n {props.mobLogo && }\r\n {props.deskLogo && }\r\n {props.deskLogo && (\r\n \r\n )}\r\n {!props.deskLogo && props.mobLogo && (\r\n {props.deskLogo?.altText || props.mobLogo?.altText || 'Site Logo'}\r\n )}\r\n \r\n )}\r\n {!props.mobLogo && !props.deskLogo && Home}\r\n \r\n \r\n )\r\n}\r\n\r\nexport default Logo\r\n","import { createContext } from 'react'\r\n\r\nconst SectionContext = createContext({ state: {}, actions: {} })\r\n\r\nexport default SectionContext\r\n","/*\r\n This file is the base theming configuration file for the MCU cua instance. \r\n This file is part of the theming config and should only be updated inside the /theme/ branches in the repository.\r\n When you make changes to this file, please update the below string so we can always stay +1 to the base repo version of the file.\r\n\r\n Iteration: 1\r\n\r\n*/\r\nconst palette = {\r\n theme: {\r\n brightgrey: {\r\n DEFAULT: '#58585A',\r\n 50: '#B4B4B6',\r\n 100: '#AAAAAC',\r\n 200: '#959597',\r\n 300: '#808083',\r\n 400: '#6C6C6F',\r\n 500: '#58585A',\r\n 600: '#444445',\r\n 700: '#303031',\r\n 800: '#1B1B1C',\r\n 900: '#070707',\r\n 950: '#000000',\r\n },\r\n cinnabar: {\r\n DEFAULT: '#F1592A',\r\n 50: '#FCDFD6',\r\n 100: '#FBD0C3',\r\n 200: '#F9B39D',\r\n 300: '#F69577',\r\n 400: '#F47750',\r\n 500: '#F1592A',\r\n 600: '#E3410F',\r\n 700: '#BD360C',\r\n 800: '#972B0A',\r\n 900: '#702007',\r\n 950: '#5D1B06',\r\n },\r\n lightningyellow: {\r\n DEFAULT: '#F7941E',\r\n 50: '#FDE8CF',\r\n 100: '#FDDFBC',\r\n 200: '#FBCC94',\r\n 300: '#FAB96D',\r\n 400: '#F8A745',\r\n 500: '#F7941E',\r\n 600: '#E48008',\r\n 700: '#BD6A07',\r\n 800: '#955405',\r\n 900: '#6E3E04',\r\n 950: '#5A3303',\r\n },\r\n broom: {\r\n DEFAULT: '#ECDC15',\r\n 50: '#FAF5BF',\r\n 100: '#F8F3AC',\r\n 200: '#F5ED86',\r\n 300: '#F2E760',\r\n 400: '#EFE23B',\r\n 500: '#ECDC15',\r\n 600: '#C8BA10',\r\n 700: '#A2970D',\r\n 800: '#7C740A',\r\n 900: '#575107',\r\n 950: '#443F06',\r\n },\r\n yellowgreen: {\r\n DEFAULT: '#8DC63F',\r\n 50: '#E1F0CD',\r\n 100: '#D8EBBD',\r\n 200: '#C5E29D',\r\n 300: '#B2D97E',\r\n 400: '#A0CF5E',\r\n 500: '#8DC63F',\r\n 600: '#77AA32',\r\n 700: '#618A29',\r\n 800: '#4B6B20',\r\n 900: '#354B16',\r\n 950: '#2A3C12',\r\n },\r\n irisblue: {\r\n DEFAULT: '#01ABC5',\r\n 50: '#7FEDFE',\r\n 100: '#6BEBFE',\r\n 200: '#42E5FE',\r\n 300: '#1AE0FE',\r\n 400: '#01CEEE',\r\n 500: '#01ABC5',\r\n 600: '#01889C',\r\n 700: '#016574',\r\n 800: '#00414B',\r\n 900: '#001E23',\r\n 950: '#000C0E',\r\n },\r\n },\r\n base: {\r\n dark: {\r\n DEFAULT: '#000000',\r\n 50: '#5C5C5C',\r\n 100: '#525252',\r\n 200: '#3D3D3D',\r\n 300: '#292929',\r\n 400: '#141414',\r\n 500: '#000000',\r\n 600: '#000000',\r\n 700: '#000000',\r\n 800: '#000000',\r\n 900: '#000000',\r\n 950: '#000000',\r\n },\r\n light: {\r\n DEFAULT: '#FFFFFF',\r\n 50: '#FFFFFF',\r\n 100: '#FFFFFF',\r\n 200: '#FFFFFF',\r\n 300: '#FFFFFF',\r\n 400: '#FFFFFF',\r\n 500: '#FFFFFF',\r\n 600: '#E3E3E3',\r\n 700: '#C7C7C7',\r\n 800: '#ABABAB',\r\n 900: '#8F8F8F',\r\n 950: '#818181',\r\n },\r\n },\r\n}\r\n\r\nconst hexBasedPalette = {\r\n // defining this palette of the base colours will allow us better interaction with the colours pickers from the CMS that only return the colour value.\r\n // one limitation of this is that only the '500' level colours will be supported in the picker, although the colour variable can be manipulated via the shade selectors in the templates.\r\n '000000': palette.base.dark,\r\n ffffff: palette.base.light,\r\n '01abc5': palette.theme.irisblue,\r\n '8dc63f': palette.theme.yellowgreen,\r\n ecdc15: palette.theme.broom,\r\n f7941e: palette.theme.lightningyellow,\r\n f1592a: palette.theme.cinnabar,\r\n '58585a': palette.theme.brightgrey,\r\n}\r\n\r\nconst paletteNames = [...Object.keys(palette.theme), ...Object.keys(palette.base), ...Object.keys(hexBasedPalette)]\r\n\r\nconst thirdParty = {\r\n calculators: {\r\n test: {\r\n // we test against this selector to see if we need to load the third party script.\r\n // selector: 'iframe[src*=\"gbst.com\"]',\r\n selector: 'iframe',\r\n // list the attributes we need to get from the selector to make it work.\r\n attributes: ['id'],\r\n // list any subelements that we need to get from the selected element.\r\n // note that in this instance because we are loading from an iframe we cannot access any DOM elements within, so anything here will return and empty NodeList.\r\n elements: [],\r\n },\r\n script: {\r\n // if we do need to run the script, here's the src and an ID so that we only load it once.\r\n src: 'https://calculators.gbst.com/clients/standard_suite/lib/iframeResizer.min.js',\r\n id: 'iframeResizerScript',\r\n // we add a callback function to be run once that loaded script's onload event fires.\r\n callback: null,\r\n },\r\n callback: {\r\n attributes: function ({ id }) {\r\n if (typeof iFrameResize === 'function') {\r\n iFrameResize({}, `#${id}`)\r\n }\r\n },\r\n elements: function (elements) {\r\n // any function that requires subelements of the selected parents elements goes in here.\r\n },\r\n },\r\n },\r\n}\r\n\r\n/* if you are adding a local font for a client, you will also need to edit fe-src\\src\\scss\\base\\_localFonts.scss to add the font-family details */\r\nconst viteFontSetup = {\r\n // google: {\r\n // families: [\r\n // {\r\n // name: 'Playfair Display',\r\n // styles: 'ital,wght@0,400;0,700;0,900;1,400;1,700;1,900',\r\n // defer: true,\r\n // },\r\n // ],\r\n // },\r\n // custom: {\r\n // families: [\r\n // {\r\n // name: 'PPEditorialNew',\r\n // local: 'PPEditorialNew',\r\n // src: './public/fonts/PPEditorialNew-Regular.woff',\r\n // transform(font) {\r\n // if (font.basename === 'PPEditorialNew') {\r\n // // update the font weight\r\n // font.weight = 400\r\n // }\r\n // // we can also return null to skip the font\r\n // return font\r\n // },\r\n // },\r\n // ],\r\n // },\r\n}\r\n\r\nconst themeConfig = {\r\n thirdParty: thirdParty,\r\n paletteNames: paletteNames,\r\n hexBasedPalette: hexBasedPalette,\r\n settings: {\r\n // this will close all other accordions in the same component when a new one is open\r\n onlyOneAccordionOpen: true,\r\n // this setting will resetting any/all breakpoints for your site.\r\n // this is mostly useful for locking the max-content width to a certain size.\r\n // the default tailwind setting for this is 1536px.\r\n // values: false, or an object something like:\r\n // {\r\n // '2xl': '1440px',\r\n // },\r\n breakPoints: {},\r\n // this setting will set a more 'readable' width constraint to various components.\r\n // it's probably a good idea to turn it on, but the default will be off, so as not to break existing cient designs.\r\n useReadableContentWidth: false,\r\n // there are two types of button available, rounded rectangles and pill-shaped.\r\n // set this to true to lock all buttons to pill-shaped, or false to default to rounded-rectangles\r\n useOnlyPillButtons: true,\r\n // if a button colour selection matches the colour of a button in the component\r\n // true: switch to a white button\r\n // false: switch to a lighter shadew of the same theme colour.\r\n useWhiteButtonsOnCollision: false,\r\n rates: {\r\n // for use in rates cards etc, where possible stack the %pa text.\r\n // this will not work for strings entered via RTE fields\r\n stackPercent: false,\r\n // if the rates values should use the 'hero' font, if provided\r\n // this will apply to all values across the site, except those entered by RTE fields\r\n useHeroFont: false,\r\n // if the rates values should be larger than the standard height\r\n // this will apply to all values across the site, except those entered by RTE fields\r\n // this should be a set of tailwind classes that will set the font-size correctly.\r\n // useAlternateSize: 'max-lg:text-4xl text-6xl leading-none',\r\n useAlternateSize: false,\r\n },\r\n showExternalLinkIcons: false,\r\n ratesCard: {\r\n highlightDescription: true,\r\n highlightRate: true,\r\n showVariantNames: false,\r\n },\r\n buttonShades: {\r\n standard: {\r\n base: '400',\r\n hover: '300',\r\n },\r\n muted: {\r\n base: '300',\r\n hover: '100',\r\n },\r\n },\r\n backToTop: 'irisblue-500',\r\n searchPageStub: 'search',\r\n useCMSMenuAccents: true,\r\n hero: {\r\n card: {\r\n shadow: {\r\n base: 'inherit',\r\n // it is unlikely that you wil want this to be the full colour, as it will be quite stark, so it's recommended that you specifically add the class `shadow-[color-value]/50` to the safelist below to ensure that the colour choice is loaded (unless you use 'inherit' of course).\r\n hover: 'inherit',\r\n },\r\n },\r\n },\r\n nav: {\r\n desktop: {\r\n base: 'brightgrey-500',\r\n active: 'brightgrey-700',\r\n highlight: 'lightning-500',\r\n },\r\n mobile: {\r\n base: 'brightgrey-500',\r\n active: 'brightgrey-700',\r\n },\r\n footer: {\r\n base: palette.theme.brightgrey['500'],\r\n disclaimers: 'primary-300',\r\n inheritLinkStyle: false,\r\n },\r\n sticky: {\r\n base: 'irisblue-500',\r\n },\r\n breadcrumbs: {\r\n base: palette.theme.light,\r\n },\r\n search: {\r\n base: 'brightgrey-700',\r\n },\r\n },\r\n alerts: {\r\n success: {\r\n bg: 'yellowgreen-50',\r\n text: 'yellowgreen-900',\r\n },\r\n primary: {\r\n bg: 'primary-200',\r\n text: 'primary-200-text',\r\n },\r\n secondary: {\r\n bg: 'secondary-200',\r\n text: 'secondary-200-text',\r\n },\r\n danger: {\r\n bg: 'red-50',\r\n text: 'red-800',\r\n },\r\n warning: {\r\n bg: 'yellow-50',\r\n text: 'yellow-700',\r\n },\r\n light: {\r\n bg: 'slate-50',\r\n text: 'brightgrey-500',\r\n },\r\n dark: {\r\n bg: 'brightgrey-500',\r\n text: 'slate-50',\r\n },\r\n },\r\n },\r\n // this flag will tell the system to generate text-colors for each base colour that is present.\r\n detectInverseText: true,\r\n // these colours can be presented in either HEX or RBG notation, either will work for the inverse text detection\r\n colors: {\r\n // if the client just has a set of base colours they can be defined here, and it will generate a tailwind-compatible set of shades based on these as the central (-500 value) colour.\r\n base: {\r\n // base: palette.base.light,\r\n // primary: palette.base.light,\r\n // secondary: palette.theme.irisblue[500],\r\n // tertiary: palette.base.light,\r\n // dark: palette.base.dark,\r\n // light: palette.base.light,\r\n // ...palette.theme\r\n },\r\n // if there are explicitly defined shades for a given client, they can be added here.\r\n // if there is a name collision between a shade and a built-in tailwind colour these will become the truth\r\n\r\n /*\r\n IMPORTANT: using shades will require editing of the tailwind.config.js file to include all the shades and variants inside the safelist to ensure they are always loaded and available to dynamically created content\r\n */\r\n\r\n shades: {\r\n // we map the palette onto the various \"themes\" in use\r\n base: palette.base.light,\r\n primary: palette.base.light,\r\n secondary: palette.theme.irisblue,\r\n tertiary: palette.base.light,\r\n dark: palette.base.dark,\r\n light: palette.base.light,\r\n // then we add the entire palette even though it should not be required\r\n ...palette.theme,\r\n // and then a palette with the hex codes of the colours as the key\r\n ...hexBasedPalette,\r\n },\r\n text: {\r\n // the color for dark text on a light background, not the color that goes over dark\r\n light: '#002B54',\r\n // the color for light text on a dark background, not the color that goes over light\r\n dark: '#fff',\r\n },\r\n link: {\r\n default: {\r\n // the color for dark text on a light background, not the color that goes over dark\r\n light: palette.theme.yellowgreen[500],\r\n // the color for light text on a dark background, not the color that goes over light\r\n dark: palette.theme.cinnabar[700],\r\n },\r\n hover: {\r\n // the color for dark text on a light background, not the color that goes over dark\r\n light: palette.theme.broom[500],\r\n // the color for light text on a dark background, not the color that goes over light\r\n dark: palette.theme.irisblue[700],\r\n },\r\n },\r\n },\r\n font: {\r\n family: {\r\n // not limited to just 'sans' and 'serif', can be any arbitrary name\r\n\r\n // Instructions for adding a font from Google.\r\n /*\r\n - near the top of this file is a const viteFontSetup. \r\n - this is an object that will load a series of one or more google fonts, with selectable weights.\r\n - once this is filled in using the options that can be found at https://github.com/cssninjaStudio/unplugin-fonts you need to:\r\n - run the build script\r\n - open the resulting index.html file\r\n - look for lines that look like \r\n \r\n \r\n - they will be different depending on the fonts you are installing, so be careful. DO NOT COPY AND PASTE FROM HERE\r\n - Copy those lines and paste them into the Header Scripts area of the site in the CMS\r\n - the plugin adds them to the index.html, but we are not using that as our launchpad for the site, so need to work around it.\r\n - Save, and test locally.\r\n - The same piece of code will need to be added to each environment, per client.\r\n - add the font details as below, using the display name of the font you are trying to load, per Google's naming in the related font page.\r\n - profit!\r\n */\r\n\r\n // Font names with spaces can be surrounded with \"\" inside the string.\r\n sans: ['\"Helvetica Neue\"', 'sans-serif'],\r\n },\r\n },\r\n // these settings will change the colour related classes that are added to the tailwind safelist.\r\n // because many of our classes are dynamically added they do not get picked up as being in use when tailwind does its internal tree-shaking.\r\n // adding classes to the safelist forces them to be included, at the cost of potentially unneccessary rules being added.\r\n // tailwind colour classes can get pretty special, from simple items like \"bg-red-500\" or \"text-black-500\" to \"max-lg:hover:text-jazzberry-300-text\".\r\n tailwind: {\r\n // this is the list of shades that will be included in the final build.\r\n // Once theming is complete this should be reduced to what we know is in use to reduce CSS file size.\r\n shades: [50, 100, 200, 300, 400, 500, 700, 800, 900],\r\n // this is the list of prefix stubs that are required for use in the site.\r\n types: ['bg', 'outline', 'text', 'border', 'decoration'],\r\n // these are the variants of the classes used to cover the \"state\" or \"breakpoint\" options of the classes\r\n variants: ['', 'group-hover:', 'hover:', 'focus-visible:', 'md:', 'max-md:', 'max-lg:', 'lg:', 'hover:lg:'],\r\n // these are the suffix stubs that modify the action variants of the colours.\r\n modifiers: ['', '-text', '-link', '-hover'],\r\n // this is the current list of safelist tailwind classes required for the theme to function.\r\n // this can be a string, or an object that matches a pattern. This object may include a variants key that is similar to the above variants key, but customised for that pattern.\r\n // there are currently other patterns described in the base tailwind.config.js, the one here is a small example of usage (that we also need, so please don't remove it)\r\n safelist: [\r\n 'text-light',\r\n 'text-dark',\r\n 'rounded-l-full',\r\n 'rounded-r-full',\r\n 'divide-y',\r\n 'font-normal',\r\n 'bg-dark',\r\n 'text-dark-text',\r\n 'bg-light',\r\n 'text-light-text',\r\n 'banner',\r\n {\r\n pattern: /bg-gradient-(t|r|l)/,\r\n },\r\n {\r\n pattern: /^text-(2xl|3xl|4xl|5xl|6xl)$/,\r\n },\r\n ],\r\n // this is a list of specific classes that we do not want to include in the build.\r\n // this cannot be a pattern, like the safelist, and must be a discrete array of strings.\r\n // this is probably not going to be necessary due to configuration optimisations that have already taken place.\r\n blocklist: [],\r\n },\r\n}\r\n\r\nthemeConfig.tailwind.safelist.push(`shadow-${themeConfig.settings.hero.card.shadow.base}/50`)\r\nthemeConfig.tailwind.safelist.push(`hover:shadow-${themeConfig.settings.hero.card.shadow.hover}/50`)\r\n\r\nexport default themeConfig\r\n","import themeConfig from '../../theme.config'\r\n\r\nconst getRGB = (color) => {\r\n color = color ?? '#ffffff'\r\n\r\n let r, g, b\r\n\r\n if (color.match(/^rgb/)) {\r\n // If RGB --> store the red, green, blue values in separate variables\r\n color = color.match(/^rgba?\\((\\d+),\\s*(\\d+),\\s*(\\d+)(?:,\\s*(\\d+(?:\\.\\d+)?))?\\)$/)\r\n\r\n r = color[1]\r\n g = color[2]\r\n b = color[3]\r\n } else {\r\n // If hex --> Convert it to RGB: http://gist.github.com/983661\r\n color = +('0x' + color.slice(1).replace(color.length < 5 && /./g, '$&$&'))\r\n\r\n r = color >> 16\r\n g = (color >> 8) & 255\r\n b = color & 255\r\n }\r\n return { r, g, b }\r\n}\r\n\r\nconst lightOrDark = (color) => {\r\n // Variables for red, green, blue values\r\n let hsp,\r\n type = 'dark'\r\n\r\n const { r, g, b } = getRGB(color)\r\n // HSP (Highly Sensitive Poo) equation from http://alienryderflex.com/hsp.html\r\n hsp = Math.sqrt(0.299 * (r * r) + 0.587 * (g * g) + 0.114 * (b * b))\r\n\r\n // Using the HSP value, determine whether the color is light or dark\r\n hsp > 127.5 && (type = 'light')\r\n return type\r\n}\r\n\r\nconst addBgImageClass = (desktop = undefined, mobile = undefined) => {\r\n let bgClass = ``\r\n\r\n // set the mobile background if it's available\r\n mobile && (bgClass += `bg-[image:var(--mobile-bg-url)] `)\r\n\r\n // if only a desktop background is set use the desktop for all breakpoints\r\n desktop && !mobile && (bgClass += `bg-[image:var(--desktop-bg-url)] `)\r\n\r\n // if both desktop and mobile are set only use the desktop image for mobile up\r\n desktop && mobile && (bgClass += `sm:bg-[image:var(--desktop-bg-url)] `)\r\n\r\n bgClass.length && (bgClass += `bg-center bg-cover bg-no-repeat`)\r\n\r\n return bgClass\r\n}\r\n\r\nconst addGradient = (direction = 'left', fullMobile = false) => {\r\n let dir = 'to-r'\r\n const toStr = `to-[color:var(--gradient-from)]`\r\n let to = '' //this is used for non-gradient gradients (full-screen wash)\r\n\r\n // if we are sending the gradient to the full panel on mobile we just add the colour here\r\n // this will turn to transparent above tablet breakpoint.\r\n fullMobile && (to = `${toStr} md:to-transparent`)\r\n\r\n switch (direction.toLowerCase()) {\r\n case 'right':\r\n dir = `to-l`\r\n break\r\n case 'bottom':\r\n dir = 'to-t'\r\n break\r\n case 'full':\r\n case 'text area':\r\n dir = 'to-l'\r\n to = toStr\r\n break\r\n }\r\n\r\n return `bg-gradient-${dir} from-[color:var(--gradient-from)] ${to}`\r\n}\r\n\r\nconst detectShadeClash = (baseColour, selectedColour) => {\r\n return (\r\n `#${baseColour.replace('#', '').toLowerCase()}` ===\r\n `#${themeConfig.colors.shades[selectedColour][500].replace('#', '').toLowerCase()}`\r\n )\r\n}\r\n\r\nconst transformPaddingToTailwind = (value, hero = false) => {\r\n // we have a list of hard-coded padding values available to the user in the Component definition.\r\n // we need to map that numeric value to tailwind classes so it can be acted on correctly\r\n const type = hero ? 'hero' : 'standard'\r\n const padding = {\r\n hero: {\r\n 0: {\r\n top: 'pt-0',\r\n bottom: 'pb-0',\r\n mid: '',\r\n card: '',\r\n },\r\n 24: {\r\n top: 'pt-6',\r\n bottom: 'pb-6',\r\n mid: 'pb-12',\r\n card: '-mt-6',\r\n },\r\n 32: {\r\n top: 'pt-8',\r\n bottom: 'pb-8',\r\n mid: 'pb-16',\r\n card: '-mt-8',\r\n },\r\n 48: {\r\n top: 'pt-12',\r\n bottom: 'pb-12',\r\n mid: 'pb-24',\r\n card: '-mt-12',\r\n },\r\n 64: {\r\n top: 'pt-16',\r\n bottom: 'pb-16',\r\n mid: 'pb-32',\r\n card: '-mt-16',\r\n },\r\n 96: {\r\n top: 'pt-24',\r\n bottom: 'pb-24',\r\n mid: 'pb-48',\r\n card: '-mt-24',\r\n },\r\n 128: {\r\n top: 'pt-32',\r\n bottom: 'pb-32',\r\n mid: 'pb-64',\r\n card: '-mt-32',\r\n },\r\n },\r\n standard: {\r\n 0: 'py-0',\r\n 24: 'py-6',\r\n 32: 'py-8',\r\n 48: 'py-12',\r\n 64: 'py-16',\r\n 96: 'py-24',\r\n 128: 'py-32',\r\n },\r\n }\r\n // if value is undefined, or not set in the component definition, we use the central value of 48px, or py-12\r\n return value && padding[type][value.toString()] ? padding[type][value.toString()] : padding[type]['48']\r\n}\r\n\r\nconst showExternalLinkIcons = () => {\r\n document.body.classList.add(themeConfig.settings.showExternalLinkIcons ? 'show-external-icons' : 'no-external-icons')\r\n}\r\n\r\nexport {\r\n lightOrDark,\r\n addGradient,\r\n addBgImageClass,\r\n getRGB,\r\n detectShadeClash,\r\n transformPaddingToTailwind,\r\n showExternalLinkIcons,\r\n}\r\n","import { useContext, useEffect, useState } from 'react'\r\nimport SectionContext from '../Context'\r\nimport themeConfig from '../../../../theme.config'\r\nimport { getRGB } from '../../../helpers/style'\r\nimport * as HeroIcons from '@heroicons/react/24/solid'\r\n\r\nconst DynamicHeroIcon = (props) => {\r\n const { ...icons } = HeroIcons\r\n let TheIcon\r\n if (props.link?.linkIconClass) {\r\n TheIcon = icons[`${props.link?.linkIconClass}Icon`]\r\n } else if (props.icon) {\r\n TheIcon = icons[`${props.icon}Icon`]\r\n }\r\n\r\n return (\r\n \r\n )\r\n}\r\n\r\nconst getBorderTheme = (skip = false) => (skip ? `border border-light` : '')\r\n\r\nconst setButtonShades = (theme, shade, hoverShade) => {\r\n return `bg-${theme}-${shade} hover:bg-${theme}-${hoverShade} focus-visible:outline-${theme}-${shade} text-${theme}-${shade}-text hover:text-${theme}-${hoverShade}-text`\r\n}\r\n\r\nconst getButtonRGB = (theme, shade) => Object.values(getRGB(themeConfig.colors.shades[theme][shade])).join(',')\r\n\r\nconst overrideButton = (theme, buttonShade, themeClasses, base) => {\r\n const buttonRGB = {\r\n primary: getButtonRGB('primary', buttonShade),\r\n secondary: getButtonRGB('secondary', buttonShade),\r\n }\r\n\r\n if (Object.values(getRGB(base)).join(',') === buttonRGB[theme]) {\r\n return themeConfig.settings.useWhiteButtonsOnCollision\r\n ? `bg-dark text-light ${getBorderTheme(true)}`\r\n : `${setButtonShades(theme, themeConfig.settings.buttonShades.muted.base, themeConfig.settings.buttonShades.muted.hover)} ${getBorderTheme(buttonRGB[theme] === Object.values(getRGB('#ffffff')).join(','))}`\r\n }\r\n return themeClasses\r\n}\r\n\r\nfunction ButtonEl(props) {\r\n let buttonShade = themeConfig.settings.buttonShades.standard.base\r\n let buttonHoverShade = themeConfig.settings.buttonShades.standard.hover\r\n const type = ['default', 'rounded', 'circle'].includes(props.buttonType) ? props.buttonType : 'default'\r\n let theme = ['primary', 'secondary', 'tertiary', 'text', 'none'].includes(props.theme) ? props.theme : 'secondary'\r\n // we do it this long-ass way because I did not want to go and add a flag to every button call across the site.\r\n const showDecorator = props.showDecorator === false ? false : true\r\n\r\n theme = theme === 'text' ? 'none' : theme\r\n\r\n const { base } = useContext(SectionContext)\r\n const [baseColor, setBaseColor] = useState('#fff')\r\n const [themeClasses, setThemeClasses] = useState(setButtonShades(theme, buttonShade, buttonHoverShade))\r\n const [hoverThemeClasses, setHoverThemeClasses] = useState(`group-hover:bg-${theme}-${buttonHoverShade}-text`)\r\n const [aria, setAria] = useState({})\r\n\r\n let typeClasses = type === 'default' ? 'rounded' : 'rounded-full'\r\n // if the config is set to not use square buttons, override the class\r\n themeConfig.settings.useOnlyPillButtons && (typeClasses = 'rounded-full')\r\n\r\n useEffect(() => {\r\n let theBase = base\r\n if (props.overrideBase) {\r\n const str = props.overrideBase.split('-')\r\n theBase = themeConfig.colors.shades[str[0]][str[1]]\r\n }\r\n setBaseColor(theBase)\r\n }, [base])\r\n\r\n useEffect(() => {\r\n setAria((prevState) => {\r\n let newState = { ...prevState }\r\n if (!props.ariaHidden || props.ariaHidden === 'false') {\r\n delete newState['aria-hidden']\r\n delete newState.tabIndex\r\n } else {\r\n newState['aria-hidden'] = 'true'\r\n newState.tabIndex = -1\r\n }\r\n if (props.ariaHasPopup) {\r\n newState['aria-haspopup'] = props.ariaHasPopup\r\n }\r\n if (props.ariaControls) {\r\n newState['aria-controls'] = props.ariaControls\r\n } else {\r\n delete newState['aria-controls']\r\n }\r\n if (props.ariaExpanded) {\r\n newState['aria-expanded'] = props.ariaExpanded\r\n } else {\r\n delete newState['aria-expanded']\r\n }\r\n return newState\r\n })\r\n }, [props.ariaHidden, props.ariaControls, props.ariaExpanded])\r\n\r\n useEffect(() => {\r\n setThemeClasses(overrideButton(theme, buttonShade, themeClasses, baseColor))\r\n setHoverThemeClasses(`group-hover:bg-${theme}-${buttonHoverShade}-text`)\r\n }, [baseColor])\r\n\r\n const className = `cta group font-semibold ${theme !== 'none' ? 'shadow-sm px-5 ' : ''} py-3 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 flex transition-all duration-300 ${themeClasses} ${typeClasses} ${props.className ? props.className : ''}`\r\n\r\n const inner = (\r\n
\r\n {/* {theme !== 'none' && ( */}\r\n <>\r\n
\r\n {props.icon && }\r\n {props.label || props.children || props.link?.name || props.link?.label}\r\n
\r\n \r\n \r\n
\r\n )\r\n\r\n return props.link ? (\r\n \r\n {inner}\r\n \r\n ) : (\r\n \r\n {inner}\r\n \r\n )\r\n}\r\n\r\nexport default ButtonEl\r\n","import { useState, useEffect } from 'react'\r\nimport ButtonEl from '../helpers/ctas/Button'\r\nimport { ChevronDownIcon, ChevronRightIcon } from '@heroicons/react/24/solid'\r\nimport themeConfig from '../../../theme.config'\r\n\r\nconst NavLevel2 = (props) => {\r\n return (\r\n \r\n {props.child.children.map((subchild, idx) => {\r\n return !subchild?.disablePageLinkInMegaMenu ? (\r\n
  • \r\n \r\n {subchild.label}\r\n \r\n
  • \r\n ) : (\r\n <>\r\n )\r\n })}\r\n \r\n )\r\n}\r\n\r\nconst NavLevel1 = (props) => {\r\n const [active, setActive] = useState(false)\r\n const [subActive, setSubActive] = useState(-1)\r\n const [menuImage, setMenuImage] = useState('')\r\n const [menuImageAlt, setMenuImageAlt] = useState('')\r\n const [hasChildActive, setHasChildActive] = useState(false)\r\n const mmHeightDefault = 224\r\n const [megamenuHeight, setMegamenuHeight] = useState(null)\r\n\r\n const handleNavClick = ({ target }) => {\r\n let clickTarget = target.nodeName === 'BUTTON' ? target : target.closest('button')\r\n setActive((prevState) => {\r\n const newState = !prevState\r\n props.handleNavClick(clickTarget.dataset?.idx)\r\n handleMenuImageSwap(clickTarget)\r\n return newState\r\n })\r\n }\r\n\r\n const handleMegaMenuClick = ({ target }) => {\r\n let clickTarget = target.nodeName === 'BUTTON' ? target : target.closest('button')\r\n const idx = clickTarget.dataset.idx\r\n handleMenuImageSwap(clickTarget)\r\n let x\r\n setSubActive((prevState) => {\r\n x = idx !== prevState ? idx : -1\r\n setHasChildActive(x === idx)\r\n return x\r\n })\r\n const relatedMegaMenu = clickTarget.getAttribute('aria-controls')\r\n const targetedMenu = document.getElementById(relatedMegaMenu)\r\n setTimeout(() => {\r\n // we need to wait a tick for the height to be revealed to us.\r\n setMegamenuHeight(x > -1 ? { minHeight: `${targetedMenu.offsetHeight}px` } : {})\r\n }, 10)\r\n }\r\n\r\n useEffect(() => {\r\n if (!props.active) {\r\n // if we close the parent, close the active second level nav too.\r\n setSubActive(-1)\r\n setMegamenuHeight({})\r\n }\r\n }, [props.active])\r\n\r\n const handleMenuImageSwap = (target) => {\r\n const imgTargetParent = target.closest('div')\r\n const imgTarget = imgTargetParent.querySelector('[data-img]')\r\n if (!imgTarget) return\r\n\r\n if (imgTarget.dataset?.img !== menuImage) {\r\n setMenuImage(imgTarget.dataset?.img)\r\n setMenuImageAlt(imgTarget.dataset?.imgAlt)\r\n }\r\n }\r\n\r\n return (\r\n \r\n \r\n {!props.navItem?.disablePageLinkInMegaMenu ? (\r\n <>\r\n \r\n {props.navItem?.label}\r\n \r\n \r\n \r\n
    {`Expand menu for item ${props.navItem?.label}`}
    \r\n \r\n \r\n ) : (\r\n \r\n \r\n {props.navItem?.label}\r\n \r\n \r\n
    {`Expand menu for item ${props.navItem?.label}`}
    \r\n \r\n )}\r\n \r\n \r\n
      \r\n {props.navItem?.children.map((child, idx) => {\r\n return (\r\n \r\n {(!child.children || !child.children?.length > 0) && !child?.disablePageLinkInMegaMenu && (\r\n <>\r\n \r\n {child.label}\r\n \r\n \r\n )}\r\n {child.children && child.children?.length > 0 && (\r\n <>\r\n \r\n {!child?.disablePageLinkInMegaMenu ? (\r\n <>\r\n \r\n {child.label}\r\n \r\n \r\n \r\n
      {`Expand submenu for item ${child?.label}`}
      \r\n \r\n \r\n ) : (\r\n \r\n \r\n {child.label}\r\n \r\n \r\n
      {`Expand menu for item ${child.label}`}
      \r\n \r\n )}\r\n \r\n \r\n \r\n )}\r\n \r\n )\r\n })}\r\n
    \r\n {props.type && props.type === 'desktop' && (\r\n \r\n {menuImage && (\r\n
    \r\n {menuImageAlt}\r\n
    \r\n )}\r\n \r\n )}\r\n \r\n \r\n )\r\n}\r\n\r\nconst MainNav = (props) => {\r\n const [activeIndex, setActiveIndex] = useState(null)\r\n const useMenuAccents = themeConfig.settings.useCMSMenuAccents ?? false\r\n const themeHighlight = themeConfig.settings.nav.desktop.highlight\r\n\r\n // test the settings to see if we want to use CMS-based link highlights.\r\n // if we do not, use the colour in the settings\r\n // if we do, test to see if it is set\r\n // if it is, use that colour, or fall back to the settings colour.\r\n const baseHighlightColour = useMenuAccents\r\n ? props.res?.navigationAccentColour?.length > 1\r\n ? `${props.res?.navigationAccentColour.toLowerCase()}-500`\r\n : `${themeHighlight}-500`\r\n : `${themeHighlight}-500`\r\n\r\n const setActive = (isActive) => {\r\n // global menu active should be the same as local menu active\r\n props.setMenuActive(isActive)\r\n props.setSearchActive((prevState) => {\r\n let newState = prevState\r\n if (isActive === true) {\r\n // is menu has become active turn the search off\r\n return false\r\n }\r\n // otherwise do nothing.\r\n props.setCtasActive(newState)\r\n\r\n return newState\r\n })\r\n }\r\n\r\n const handleNavClick = (idx = null) => {\r\n if (!idx) {\r\n return false\r\n }\r\n setActiveIndex((prevState) => {\r\n let isActive = true\r\n\r\n if (idx === prevState) {\r\n isActive = false\r\n }\r\n setActive(isActive)\r\n return isActive ? idx : null\r\n })\r\n }\r\n\r\n const generateHighlight = (colour) =>\r\n colour && colour?.length ? `${colour.toLowerCase()}-500` : `${baseHighlightColour}`\r\n\r\n document.addEventListener('keydown', (evt) => {\r\n if (evt.key !== 'Escape') return\r\n props.setMenuActive(false)\r\n setActiveIndex(null)\r\n })\r\n\r\n useEffect(() => {\r\n if (props.type === 'desktop') {\r\n document.addEventListener('click', (evt) => {\r\n if (\r\n !evt.target.closest('[data-type=\"desktop-navigation\"]') &&\r\n !evt.target.closest('[data-type=\"mobile-navigation\"]')\r\n ) {\r\n props.setMenuActive(false)\r\n setActiveIndex(null)\r\n }\r\n })\r\n }\r\n }, [])\r\n\r\n return (\r\n \r\n )\r\n}\r\n\r\nexport default MainNav\r\n","import { useEffect, useState } from 'react'\r\nimport { Bars4Icon, XMarkIcon } from '@heroicons/react/24/solid'\r\nimport ButtonEl from '../helpers/ctas/Button'\r\nimport themeConfig from '../../../theme.config'\r\nimport MainNav from './MainNav'\r\n\r\nfunction MobileNav(props) {\r\n const [menuActive, setMenuActive] = useState(false)\r\n\r\n const content = (\r\n <>\r\n \r\n
    \r\n \r\n
    \r\n
    \r\n \r\n
    \r\n Toggle mobile menu\r\n \r\n \r\n )\r\n\r\n useEffect(() => {\r\n setMenuActive((prevState) => (props.searchActive === true || props.ctasActive === true ? false : prevState))\r\n }, [props.searchActive, props.ctasActive, props.menuActive])\r\n\r\n useEffect(() => {\r\n if (props.type === 'mobile') {\r\n document.addEventListener('click', (evt) => {\r\n if (\r\n !evt.target.closest('[data-type=\"mobileNavTrigger\"]') &&\r\n !evt.target.closest('[data-type=\"mobile-navigation\"]')\r\n ) {\r\n setMenuActive(false)\r\n }\r\n })\r\n }\r\n }, [])\r\n\r\n const handleClick = () => {\r\n // let isActive = false\r\n setMenuActive((prevState) => {\r\n const isActive = !prevState\r\n props.setMenuActive(isActive)\r\n props.setSearchActive((prevState) => {\r\n let newState = prevState\r\n if (isActive === true) {\r\n // is search has become active turn the menu off\r\n newState = false\r\n }\r\n // otherwise do nothing.\r\n props.setCtasActive(newState)\r\n return newState\r\n })\r\n return isActive\r\n })\r\n }\r\n\r\n return (\r\n <>\r\n \r\n \r\n {content}\r\n \r\n \r\n \r\n
    \r\n \r\n
    \r\n \r\n \r\n )\r\n}\r\n\r\nexport default MobileNav\r\n","import { useEffect, useState } from 'react'\r\nimport ButtonEl from '../helpers/ctas/Button'\r\nimport themeConfig from '../../../theme.config'\r\nimport { MagnifyingGlassIcon, XMarkIcon } from '@heroicons/react/24/solid'\r\n\r\nfunction Search(props) {\r\n const triggerTheme = 'none'\r\n const searchTheme = 'secondary'\r\n const [searchActive, setSearchActive] = useState()\r\n const [searchTerm, setSearchTerm] = useState()\r\n\r\n useState(() => {\r\n document.addEventListener('click', (evt) => {\r\n if (!evt.target.closest('[data-type=\"search\"]') && !evt.target.closest('[data-type=\"searchForm\"]')) {\r\n setSearchActive(false)\r\n }\r\n })\r\n }, [])\r\n\r\n const triggerContent = (\r\n <>\r\n \r\n \r\n Toggle search field\r\n \r\n )\r\n const searchContent = Search\r\n\r\n useEffect(() => {\r\n setSearchActive((prevState) => (props.menuActive === true || props.ctasActive === true ? false : prevState))\r\n }, [props.menuActive, props.ctasActive])\r\n\r\n const submitForm = (evt) => {\r\n evt.preventDefault()\r\n const loc = window.location\r\n const searchUrl = new URL(`${loc.origin}/${themeConfig.settings.searchPageStub}`)\r\n searchUrl.searchParams.append('q', searchTerm)\r\n window.location = searchUrl\r\n }\r\n\r\n const handleSearchClick = (evt) => {\r\n setSearchActive((prevState) => {\r\n const isActive = !prevState\r\n props.setSearchActive(isActive)\r\n props.setMenuActive((prevState) => {\r\n let newState = prevState\r\n if (isActive === true) {\r\n // is search has become active turn the menu off\r\n newState = false\r\n }\r\n // otherwise do nothing.\r\n props.setCtasActive(newState)\r\n return newState\r\n })\r\n return isActive\r\n })\r\n }\r\n\r\n return (\r\n <>\r\n \r\n \r\n {triggerContent}\r\n \r\n \r\n \r\n \r\n
    \r\n setSearchTerm(encodeURIComponent(e.target.value))}\r\n placeholder=\"Enter search terms\"\r\n autoComplete=\"off\"\r\n tabIndex={searchActive ? 0 : -1}\r\n aria-hidden={searchActive ? 'false' : 'true'}\r\n aria-label=\"Site Search\"\r\n className=\"rounded-full py-3 px-5 basis-auto grow\"\r\n />\r\n \r\n {searchContent}\r\n \r\n
    \r\n \r\n \r\n \r\n )\r\n}\r\n\r\nexport default Search\r\n","import { useState, useEffect } from 'react'\r\nimport ButtonEl from '../helpers/ctas/Button'\r\nimport { ChevronDownIcon, EllipsisVerticalIcon, ArrowLongUpIcon, ArrowRightIcon } from '@heroicons/react/24/solid'\r\n\r\nfunction CtaDropdownTriggerButton(props) {\r\n return (\r\n \r\n
    {props.ctas[0].link?.name}
    \r\n \r\n \r\n )\r\n}\r\n\r\nfunction CtaDropdownTriggerMinimal(props) {\r\n return (\r\n \r\n {props.ctas[0].name}\r\n
    \r\n \r\n \r\n
    \r\n \r\n )\r\n}\r\n\r\nfunction CtaDropDownTrigger(props) {\r\n if (props.triggerStyle === 'minimal') {\r\n // returns the minimal trigger button.\r\n return \r\n } else if (props.triggerStyle === 'button') {\r\n // inherits the button style from the first CTA as defined in the CMS\r\n return \r\n }\r\n // this overrides any theme set on the first button to show the \"standard\" version of the dropdown.\r\n return \r\n}\r\n\r\nfunction CtaDropdown(props) {\r\n const [ctaActive, setCtaActive] = useState(false)\r\n let variant = ['simple', 'icon', 'divider'].includes(props.variant) ? props.variant : 'simple'\r\n const [variantClasses, setVariantClasses] = useState('')\r\n const wrapperClasses = props.position === 'mobile' ? 'ml-3 block md:hidden' : 'basis-1/10 ml-auto hidden md:block'\r\n const menuClasses = props.position === 'mobile' ? 'origin-bottom translate-y-[-110%] top-0' : 'origin-top'\r\n useEffect(() => {\r\n setCtaActive((prevState) => (props.menuActive === true || props.searchActive === true ? false : prevState))\r\n }, [props.menuActive, props.searchActive])\r\n\r\n document.addEventListener('click', (evt) => {\r\n if (!evt.target.closest('[data-type=\"cta-dropdown\"]')) {\r\n setCtaActive(false)\r\n }\r\n })\r\n\r\n useEffect(() => {\r\n setVariantClasses((dd) => {\r\n if (props.variant === 'divider') {\r\n return 'divide-y'\r\n }\r\n return ''\r\n })\r\n }, [props.variant])\r\n\r\n const handleCtaExpandClick = () => {\r\n setCtaActive((prevState) => {\r\n const isActive = !prevState\r\n if (props.position !== 'mobile') {\r\n props.setCtasActive(isActive)\r\n props.setSearchActive((prevState) => {\r\n let newState = prevState\r\n if (isActive === true) {\r\n // is search has become active turn the menu off\r\n newState = false\r\n }\r\n // otherwise do nothing.\r\n props.setMenuActive(newState)\r\n return newState\r\n })\r\n }\r\n return isActive\r\n })\r\n }\r\n\r\n return (\r\n
    \r\n {props.ctas?.length > 1 && (\r\n //

    Multiple Buttons

    \r\n // we need to build a drop-down from this, using the first button as a label only\r\n // any links added to this CTA will be ignored.\r\n \r\n
      \r\n
    • \r\n \r\n \r\n {props.ctas.map((cta, idx) => {\r\n if (idx == 0) {\r\n return\r\n }\r\n return (\r\n <>\r\n {idx > 0 && (\r\n
    • \r\n \r\n {props.variant !== 'icon' && {cta.link.name}}\r\n {props.variant === 'icon' && (\r\n <>\r\n
      {cta.link.name}
      \r\n \r\n \r\n )}\r\n \r\n
    • \r\n )}\r\n \r\n )\r\n })}\r\n
    \r\n \r\n \r\n \r\n )}\r\n\r\n {props.ctas?.length === 1 &&\r\n props.ctas.map((cta, i) => {\r\n // return

    Button

    \r\n return (\r\n \r\n )\r\n })}\r\n
    \r\n )\r\n}\r\n\r\nexport default CtaDropdown\r\n","import Logo from './Logo'\r\nimport MobileNav from './MobileNav'\r\nimport Search from './Search'\r\nimport CtaDropDown from './CTA'\r\nimport MainNav from './MainNav'\r\n\r\nfunction Header(props) {\r\n return (\r\n
    \r\n {props.children}\r\n
    \r\n \r\n {!props.res.hideMegamenu && }\r\n {props.ctas && }\r\n \r\n {!props.res.hideMegamenu && }\r\n
    \r\n
    \r\n )\r\n}\r\n\r\nexport default Header\r\n","import themeConfig from '../../../theme.config'\r\nimport { HomeIcon } from '@heroicons/react/24/solid'\r\n\r\nfunction Breadcrumbs(props) {\r\n if (!props.items?.length) {\r\n return\r\n }\r\n return (\r\n \r\n )\r\n}\r\n\r\nexport default Breadcrumbs\r\n","import { addGradient } from './style'\r\n\r\nconst addExternalAria = (el) => {\r\n const links = el.querySelectorAll('a')\r\n Array.from(links).forEach((link) => {\r\n if (link.target === '_blank') {\r\n link.setAttribute('aria-label', 'link opens in new tab or window')\r\n }\r\n })\r\n return el[el.classList.contains('has-table') ? 'outerHTML' : 'innerHTML'].toString()\r\n}\r\n\r\nconst addTableClasses = (el) => {\r\n el.classList.add(el.querySelectorAll('table').length > 0 ? 'has-table' : 'no-table')\r\n return el\r\n}\r\n\r\nconst createMarkup = (markup) => {\r\n let el = document.createElement('div')\r\n el.innerHTML = markup\r\n el = addTableClasses(el)\r\n return { __html: addExternalAria(el) }\r\n}\r\n\r\nconst createGradientElement = ({ type, fromColor, fullMobile = false, classes = '' }) => {\r\n if (!type || !fromColor) {\r\n return\r\n }\r\n return (\r\n \r\n )\r\n}\r\n\r\nexport { createMarkup, createGradientElement }\r\n","import ButtonEl from '../helpers/ctas/Button'\r\nimport CtaDropdown from './CTA'\r\nimport themeConfig from '../../../theme.config'\r\n\r\nfunction StickyFooter(props) {\r\n if (\r\n (props.stickyNavPrimary && props.stickyNavPrimary.length) ||\r\n (props.stickyNavSecondary && props.stickyNavSecondary.length)\r\n ) {\r\n return (\r\n
    \r\n \r\n
    \r\n {props.stickyNavPrimary && props.stickyNavPrimary[0] && props.stickyNavPrimary[0].link.url && (\r\n \r\n )}\r\n {props.stickyNavSecondary && (\r\n \r\n )}\r\n
    \r\n \r\n
    \r\n )\r\n } else {\r\n return <>\r\n }\r\n}\r\n\r\nexport default StickyFooter\r\n","import { ArrowUpCircleIcon } from '@heroicons/react/24/solid'\r\nimport ButtonEl from '../helpers/ctas/Button'\r\nimport themeConfig from '../../../theme.config'\r\nimport { useState, useEffect } from 'react'\r\n\r\nconst scrollToTop = () => {\r\n window.scrollTo({\r\n top: 0,\r\n behavior: 'smooth', // for smoothly scrolling\r\n })\r\n}\r\n\r\nconst BackToTop = (props) => {\r\n const [showButton, setShowButton] = useState(false)\r\n\r\n useEffect(() => {\r\n window.addEventListener('scroll', () => {\r\n if (window.scrollY > 300) {\r\n setShowButton(true)\r\n } else {\r\n setShowButton(false)\r\n }\r\n })\r\n }, [])\r\n\r\n return (\r\n \r\n
    \r\n \r\n Back to top\r\n
    \r\n \r\n )\r\n}\r\n\r\nexport default BackToTop\r\n","import { createMarkup } from '../../helpers/markup'\r\nimport StickyFooter from './StickyFooter'\r\nimport themeConfig from '../../../theme.config'\r\nimport BackToTop from './BackToTop'\r\nimport { lightOrDark } from '../../helpers/style'\r\n\r\nfunction Footer(props) {\r\n const bgSplit = themeConfig.settings.nav.footer.base.split('-')\r\n\r\n return (\r\n <>\r\n \r\n {props.footerNavigationItems?.length > 0 && (\r\n
    \r\n {props.footerNavigationItems.map((col, idx) => (\r\n \r\n ))}\r\n
    \r\n )}\r\n {props.footerDescription && (\r\n
    \r\n
    \r\n
    \r\n )}\r\n {props.socialMediaLinks?.length ? (\r\n
      \r\n {props.socialMediaLinks?.map((link, j) => (\r\n
    • \r\n \r\n \r\n {link.link?.name}\r\n \r\n
    • \r\n ))}\r\n
    \r\n ) : null}\r\n
    \r\n © Copyright {new Date().getFullYear()}{' '}\r\n
    \r\n
    \r\n {props.footerDisclaimerText && (\r\n
    \r\n
    \r\n
    \r\n )}\r\n \r\n \r\n {!props.disableSticky && (props.stickyNavPrimary || props.stickyNavSecondary) && }\r\n \r\n )\r\n}\r\n\r\nexport default Footer\r\n","const Loader = () => {\r\n return \r\n}\r\n\r\nexport default Loader","import { useState, useEffect } from 'react'\r\nimport { createMarkup } from '../../helpers/markup'\r\nimport { ExclamationTriangleIcon, XMarkIcon } from '@heroicons/react/24/solid'\r\nimport ButtonEl from '../helpers/ctas/Button'\r\nimport { read_cookie } from 'sfcookies'\r\nimport themeConfig from '../../../theme.config'\r\n\r\nconst createCookieValue = str => {\r\n let value = 'alertcookie'\r\n\r\n console.log('cookiestr: ', str, value)\r\n\r\n if (str.length) {\r\n const el = document.createElement('div')\r\n el.innerHTML = str\r\n // get the innertext and strip whitespaces which are not allowed in cookie values.\r\n // limit the string to 25 characters to not overload things. \r\n value = el.innerText.toLowerCase().replace(/\\W/g, '').substring(0, 25)\r\n }\r\n return value\r\n}\r\n\r\nconst Alert = (props) => {\r\n const [active, setActive] = useState(true)\r\n //set the cookie to something a bit static to allow for security policy checks to still work.\r\n const cookieID = `_cookie-${props.type?.toLowerCase()}`\r\n // generate a cookie value based on the title.\r\n // not using a title on the alert will result in a more generic value being set, which may cause some issues with detection.\r\n const cookieValueStr = createCookieValue(props.title)\r\n\r\n const date = new Date()\r\n const numWeeks = 1\r\n date.setDate(date.getDate() + numWeeks * 7)\r\n\r\n let type = props.type?.toLowerCase() || 'warning'\r\n let hasSetCookie = false\r\n\r\n hasSetCookie = (document.cookie.split(\";\").some((item) => (item.trim().startsWith(cookieID) && item.includes(cookieValueStr)))) \r\n\r\n const bgClass = `bg-${themeConfig.settings.alerts[type].bg}`\r\n const fgClass = `text-${themeConfig.settings.alerts[type].text}`\r\n const classes = 'top-0 left-0 w-full ' + bgClass + ' ' + fgClass\r\n\r\n const handleClick = () => {\r\n console.log('cookie: ', cookieID, cookieValueStr)\r\n setActive((prevState) => {\r\n const newState = !prevState\r\n if (newState === false) {\r\n document.cookie = cookieID + '=' + cookieValueStr + '; expires=' + date.toUTCString() + '; path=/;'\r\n }\r\n return newState\r\n })\r\n }\r\n\r\n return (\r\n <>\r\n {hasSetCookie !== true && active && (\r\n
    \r\n
    \r\n \r\n
    \r\n {props.title && (\r\n

    \r\n )}\r\n {props.description && (\r\n

    \r\n )}\r\n

    \r\n \r\n \r\n Close this alert\r\n \r\n
    \r\n
    \r\n )}\r\n \r\n )\r\n}\r\n\r\nexport default Alert\r\n","const Skip = (props) => {\r\n return (\r\n <>\r\n \r\n Skip to main content\r\n \r\n \r\n )\r\n}\r\n\r\nexport default Skip\r\n","import { createMarkup } from '../../helpers/markup'\r\n\r\nconst TitleBlock = (props) => {\r\n return (\r\n <>\r\n {(props.title || props.description) && (\r\n
    \r\n {props.title && (\r\n
    \r\n )}\r\n {props.description && (\r\n
    \r\n )}\r\n
    \r\n )}\r\n \r\n )\r\n}\r\n\r\nexport default TitleBlock\r\n","import { useEffect, useState } from 'react'\r\nimport SectionContext from '../helpers/Context'\r\nimport TitleBlock from '../helpers/TitleBlock'\r\nimport { createGradientElement } from '../../helpers/markup'\r\nimport { lightOrDark, addBgImageClass } from '../../helpers/style'\r\n\r\nconst Section = (props) => {\r\n // the api is sending out un-hashed hex colour strings, so we either make it the hashed version, or default to the base colour setting from the theme config.\r\n const [contained, setContained] = useState(false)\r\n const [backgroundColor, setBackgroundColor] = useState('#fff')\r\n const [gradientColor, setgradientColor] = useState('#fff')\r\n\r\n const sectionGradient = ![null, 'None', 'Text area'].includes(props.gradientType)\r\n const contentGradient = ['Text area'].includes(props.gradientType)\r\n useEffect(() => {\r\n setContained(() => props.backgroundConfiguration === 'Contained')\r\n }, [props.backgroundConfiguration])\r\n\r\n useEffect(() => {\r\n // we strip the '#' from the front by default because some sources of the data have it included, and some do not.\r\n // this sets everything to the same format, even though we add it back immediately after.\r\n const bgColor = props.backgroundColor.replace('#', '')\r\n const fgColor = props.foregroundColor.replace('#', '')\r\n setBackgroundColor((prevState) => (bgColor ? `#${bgColor}` : prevState))\r\n setgradientColor((prevState) => (fgColor ? `#${fgColor}` : prevState))\r\n }, [])\r\n\r\n return (\r\n \r\n \r\n {sectionGradient &&\r\n createGradientElement({\r\n type: props.gradientType,\r\n fromColor: gradientColor,\r\n fullMobile: true,\r\n })}\r\n \r\n {contentGradient &&\r\n createGradientElement({\r\n type: props.gradientType,\r\n fromColor: gradientColor,\r\n fullMobile: false,\r\n })}\r\n {props.sectionTitle !== false && (props.title || props.description) && }\r\n {props.children}\r\n
    \r\n \r\n \r\n )\r\n}\r\n\r\nexport default Section\r\n","import { useState } from 'react'\r\nimport Section from './_Section'\r\nimport { createMarkup } from '../../helpers/markup'\r\nimport ButtonEl from '../helpers/ctas/Button'\r\nimport { PlusIcon, MinusIcon } from '@heroicons/react/24/solid'\r\nimport { transformPaddingToTailwind } from '../../helpers/style'\r\nimport themeConfig from '../../../theme.config'\r\n\r\nfunction Accordion(props) {\r\n const [open, setOpen] = useState({})\r\n const componentPadding = transformPaddingToTailwind(props.componentPadding)\r\n\r\n return (\r\n
    \r\n {props.accordionPanelItems.length != 0 && (\r\n \r\n {props.accordionPanelItems.map((item, i) => (\r\n
  • \r\n {\r\n setOpen((previousOpen) => {\r\n if (themeConfig.settings.onlyOneAccordionOpen) {\r\n const newState = { ...previousOpen }\r\n newState[i] = !newState[i]\r\n for (let x in newState) {\r\n if (Number(x) !== Number(i)) {\r\n newState[x] = false\r\n }\r\n }\r\n return newState\r\n } else {\r\n return {\r\n ...previousOpen,\r\n [i]: !previousOpen[i],\r\n }\r\n }\r\n })\r\n }}\r\n >\r\n {item.title}\r\n {open[i] ? (\r\n <>\r\n \r\n Close Accordion\r\n \r\n ) : (\r\n <>\r\n \r\n Open Accordion\r\n \r\n )}\r\n \r\n {open[i] &&
    }\r\n
  • \r\n ))}\r\n \r\n )}\r\n
    \r\n )\r\n}\r\n\r\nexport default Accordion\r\n","import Section from './_Section'\r\nimport { createMarkup } from '../../helpers/markup'\r\nimport ButtonEl from '../helpers/ctas/Button'\r\nimport { transformPaddingToTailwind } from '../../helpers/style'\r\n\r\nfunction BasicContent(props) {\r\n const componentPadding = transformPaddingToTailwind(props.componentPadding)\r\n\r\n return (\r\n
    \r\n {props.ctaLink?.length != 0 && (\r\n
    \r\n {props.ctaLink.map((ctaLinkItem, i) => (\r\n \r\n ))}\r\n
    \r\n )}\r\n
    \r\n )\r\n}\r\n\r\nexport default BasicContent\r\n","import Section from './_Section'\r\nimport { createMarkup } from '../../helpers/markup'\r\nimport ButtonEl from '../helpers/ctas/Button'\r\nimport { ArrowRightIcon, PhoneIcon } from '@heroicons/react/24/solid'\r\nimport TitleBlock from '../helpers/TitleBlock'\r\nimport { transformPaddingToTailwind } from '../../helpers/style'\r\n\r\nfunction CalloutCard(props) {\r\n const sectionGradient = !['None', 'ContentArea'].includes(props.backgroundGradientType)\r\n const contentGradient = ['ContentArea'].includes(props.backgroundGradientType)\r\n const componentPadding = transformPaddingToTailwind(props.componentPadding)\r\n\r\n return (\r\n \r\n
    \r\n {(props.title || props.description) && (\r\n \r\n )}\r\n {props.ctaLink.length != 0 && (\r\n
    \r\n {props.ctaLink.map((ctaLinkItem, i) => {\r\n let content = ctaLinkItem.link?.name\r\n const url = ctaLinkItem.link?.url\r\n if (content) {\r\n if (url?.startsWith('tel:')) {\r\n content = (\r\n <>\r\n \r\n {content}\r\n \r\n )\r\n } else {\r\n content = (\r\n <>\r\n {content}\r\n \r\n \r\n )\r\n }\r\n }\r\n return (\r\n
    \r\n \r\n {content}\r\n \r\n
    \r\n )\r\n })}\r\n
    \r\n )}\r\n
    \r\n \r\n )\r\n}\r\n\r\nexport default CalloutCard\r\n","const Image = (props) => {\r\n if (!props?.src) return\r\n\r\n return {props.altText\r\n}\r\n\r\nexport default Image\r\n","const HeroTitle = ({ type, cardItem, idx }) => {\r\n const mapped = {\r\n title: 'title',\r\n }\r\n\r\n if (type === 'dynamic') {\r\n mapped.title = 'listingTitle'\r\n }\r\n\r\n if (cardItem.ctaLinkItem && cardItem.ctaLinkItem?.length !== 0) {\r\n // if the editor added a cta in hero mode that link becomes the link in the title.\r\n return (\r\n \r\n \r\n {cardItem[mapped.title]}\r\n \r\n \r\n )\r\n } else if (cardItem.listingLink && cardItem.listingLink?.length !== 0) {\r\n return (\r\n \r\n \r\n {cardItem[mapped.title]}\r\n \r\n \r\n )\r\n } else {\r\n return (\r\n \r\n {cardItem[mapped.title]}\r\n \r\n )\r\n }\r\n}\r\n\r\nexport default HeroTitle\r\n","const Picture = (props) => {\r\n if (!props.desktopImage && !props.mobileImage) return\r\n // if either image is provided we still proceed, using what we have.\r\n\r\n // use the mobile as the default image if it's present, otherwise use desktopImage as the default.\r\n // we know that if mobileImage does not exist desktopImage must, because of the previous check\r\n const baseImage = props.mobileImage ? props.mobileImage : props.desktopImage\r\n return (\r\n \r\n {props.desktopImage && (\r\n \r\n )}\r\n {props.mobileImage && (\r\n \r\n )}\r\n \r\n \r\n )\r\n}\r\n\r\nexport default Picture\r\n","import { Suspense, useState, useEffect } from 'react'\r\nimport Section from './_Section'\r\nimport { createMarkup, createGradientElement } from '../../helpers/markup'\r\nimport { addBgImageClass, lightOrDark, transformPaddingToTailwind } from '../../helpers/style'\r\nimport ButtonEl from '../helpers/ctas/Button'\r\nimport { ArrowRightIcon, PlayIcon, XMarkIcon } from '@heroicons/react/24/solid'\r\nimport Image from '../helpers/Image'\r\nimport HeroTitle from '../helpers/CardListingHeroTitle'\r\nimport Modal from 'react-modal'\r\nimport Loader from '../helpers/Loader'\r\nimport Picture from '../helpers/Picture'\r\nModal.setAppElement('#root')\r\n\r\nconst customModalStyle = {\r\n content: {\r\n top: '50%',\r\n left: '50%',\r\n width: '75vw',\r\n right: 'auto',\r\n bottom: 'auto',\r\n marginRight: '-50%',\r\n translate: '-50% -50%',\r\n aspectRatio: '16/10',\r\n maxHeight: '95vh',\r\n },\r\n}\r\n\r\nasync function getYTEmbed(url) {\r\n try {\r\n const response = await fetch(`https://www.youtube.com/oembed?url=${url}&format=json`)\r\n const responseJson = await response.json()\r\n return responseJson\r\n } catch (error) {\r\n console.error(error)\r\n }\r\n}\r\n\r\nconst CardListBGImage = (props) => {\r\n const { cardItem, i } = props\r\n const [modalIsOpen, setIsOpen] = useState(false)\r\n const [videoEmbed, setVideoEmbed] = useState(null)\r\n const [backgroundColor, setBackgroundColor] = useState('transparent')\r\n const [gradientColor, setgradientColor] = useState('#fff')\r\n\r\n useEffect(() => {\r\n const bgColor = props.cardBackgroundColour.replace('#', '')\r\n const fgColor = props.imageGradientColour.replace('#', '')\r\n setBackgroundColor((prevState) => (bgColor ? `#${bgColor}` : prevState))\r\n setgradientColor((prevState) => (fgColor ? `#${fgColor}` : prevState))\r\n }, [])\r\n\r\n function openModal() {\r\n setIsOpen(true)\r\n }\r\n\r\n async function afterOpenModal() {\r\n // references are now sync'd and can be accessed.\r\n // subtitle.style.color = '#f00';\r\n const embedCode = getYTEmbed(cardItem.videoUrl)\r\n embedCode.then((res) => {\r\n if (!res.error) {\r\n setVideoEmbed(res)\r\n }\r\n })\r\n }\r\n\r\n function closeModal() {\r\n setIsOpen(false)\r\n }\r\n\r\n return (\r\n \r\n {props.imageGradientColour &&\r\n createGradientElement({\r\n type: props.imageGradientType,\r\n fromColor: gradientColor,\r\n })}\r\n \r\n {cardItem.videoUrl ? (\r\n \r\n \r\n Play video\r\n \r\n ) : null}\r\n
    \r\n {cardItem.title && !cardItem.useSmallTitle && (\r\n \r\n {cardItem.title}\r\n \r\n )}\r\n {cardItem.title && cardItem.useSmallTitle && (\r\n \r\n {cardItem.title}\r\n \r\n )}\r\n {cardItem.description && (\r\n
    \r\n )}\r\n {cardItem.ctaLinkItem.length != 0 && (\r\n \r\n {cardItem.ctaLinkItem.map((ctaLinkItem, i) => (\r\n \r\n ))}\r\n
    \r\n )}\r\n {/* */}\r\n
    \r\n \r\n {cardItem.videoUrl ? (\r\n \r\n \r\n \r\n Close this alert\r\n \r\n
    \r\n {videoEmbed && (\r\n
    \r\n {videoEmbed.title}\r\n
    \r\n )}\r\n }>\r\n {videoEmbed && (\r\n \r\n )}\r\n \r\n
    \r\n \r\n ) : null}\r\n \r\n )\r\n}\r\n\r\nconst CardListIcon = ({ cardItem, i }) => {\r\n return (\r\n \r\n
    \r\n
    \r\n \r\n
    \r\n
    \r\n {cardItem.title && }\r\n {cardItem.description && (\r\n
    \r\n )}\r\n
    \r\n
    \r\n
    \r\n )\r\n}\r\n\r\nconst CardListHeroImage = ({ cardItem, i }) => {\r\n return (\r\n \r\n
    \r\n \r\n
    \r\n {/* {cardItem.dateTimeFormatted} */}\r\n {cardItem.title && }\r\n {cardItem.description && (\r\n
    \r\n )}\r\n
    \r\n
    \r\n
    \r\n )\r\n}\r\n\r\nfunction CardListCurated(props) {\r\n let cardItems = props.cardItems || []\r\n const initialNumber = props.initialNoOfCards || 3\r\n const [viewMore, setViewMore] = useState(cardItems.length <= initialNumber)\r\n const [variant, setVariant] = useState('background')\r\n const [textAlignment, setTextAlignment] = useState({\r\n flex: 'center',\r\n align: 'center',\r\n })\r\n const componentPadding = transformPaddingToTailwind(props.componentPadding)\r\n\r\n if (!viewMore) {\r\n cardItems = cardItems.slice(0, initialNumber)\r\n }\r\n\r\n useEffect(() => {\r\n setTextAlignment((prevState) => {\r\n const newState = { ...prevState }\r\n const alignment = props.contentAlignment?.toLowerCase() ?? 'center'\r\n if (newState.align !== props.contentAlignment?.toLowerCase()) {\r\n newState.flex = alignment === 'center' ? 'center' : 'around'\r\n newState.align = alignment === 'center' ? 'center' : 'left'\r\n }\r\n return newState\r\n })\r\n setVariant((prevState) => {\r\n // Background Image => background\r\n // Hero Image => hero\r\n // Icon => icon\r\n if (!props.cardVariant) return 'background'\r\n\r\n return props.cardVariant?.split(' ')[0].toLowerCase()\r\n })\r\n }, [])\r\n\r\n return (\r\n \r\n <>\r\n {cardItems.length != 0 && (\r\n \r\n {/* ${Math.min(cardItems.length, Math.max(cardItems.length, 3))} */}\r\n {cardItems.map((cardItem, i) => {\r\n if (variant === 'background') {\r\n return \r\n } else if (variant === 'hero') {\r\n return \r\n }\r\n return \r\n })}\r\n \r\n )}\r\n {!viewMore && (\r\n
    \r\n {\r\n setViewMore(true)\r\n }}\r\n >\r\n {props.viewMoreText || 'View more'}\r\n \r\n \r\n
    \r\n )}\r\n \r\n \r\n )\r\n}\r\n\r\nexport default CardListCurated\r\n","import { useState, useEffect } from 'react'\r\nimport Section from './_Section'\r\nimport { createMarkup, createGradientElement } from '../../helpers/markup'\r\nimport { addBgImageClass, lightOrDark, transformPaddingToTailwind } from '../../helpers/style'\r\nimport ButtonEl from '../helpers/ctas/Button'\r\nimport { ArrowRightIcon } from '@heroicons/react/24/solid'\r\nimport HeroTitle from '../helpers/CardListingHeroTitle'\r\nimport TitleBlock from '../helpers/TitleBlock'\r\nimport Picture from '../helpers/Picture'\r\n\r\nfunction CardListDynamic(props) {\r\n let cardItems = (props.listingContents || []).filter((cardItem) => !cardItem.hideInListing)\r\n const componentPadding = transformPaddingToTailwind(props.componentPadding)\r\n\r\n const initialNumber = props.initialNoOfCards || 3\r\n const [viewMore, setViewMore] = useState(cardItems.length <= initialNumber)\r\n const [alignment, setAlignment] = useState('center')\r\n const [textAlignment, setTextAlignment] = useState({\r\n flex: 'center',\r\n align: 'center',\r\n })\r\n const variant = props.cardVariant\r\n const [backgroundColor, setBackgroundColor] = useState('transparent')\r\n const [gradientColor, setgradientColor] = useState('#fff')\r\n\r\n useEffect(() => {\r\n setTextAlignment((prevState) => {\r\n const newState = { ...prevState }\r\n const alignment = props.contentAlignment?.toLowerCase() ?? 'center'\r\n if (newState.align !== props.contentAlignment?.toLowerCase()) {\r\n newState.flex = alignment === 'center' ? 'center' : 'center'\r\n newState.align = alignment === 'center' ? 'center' : 'left'\r\n }\r\n setAlignment(alignment)\r\n return newState\r\n })\r\n const bgColor = props.cardBackgroundColour.replace('#', '')\r\n const fgColor = props.imageGradientColour.replace('#', '')\r\n setBackgroundColor((prevState) => (bgColor ? `#${bgColor}` : prevState))\r\n setgradientColor((prevState) => (fgColor ? `#${fgColor}` : prevState))\r\n }, [])\r\n\r\n if (!viewMore) {\r\n cardItems = cardItems.slice(0, initialNumber)\r\n }\r\n\r\n return (\r\n \r\n
    \r\n {(props.title || props.description) && }\r\n\r\n {cardItems.length != 0 && (\r\n \r\n {cardItems.map((cardItem, i) => {\r\n const tags = (cardItem.tagsConfig && JSON.parse(cardItem.tagsConfig).tags) || []\r\n\r\n const innerHero = (\r\n <>\r\n
    \r\n
    \r\n \r\n {cardItem.dateTimeFormatted}\r\n {cardItem.listingTitle && }\r\n {cardItem.listingDescription && (\r\n \r\n )}\r\n
    \r\n
    \r\n \r\n )\r\n\r\n const innerBG = (\r\n <>\r\n {props.imageGradientColour &&\r\n createGradientElement({\r\n type: props.imageGradientType,\r\n fromColor: gradientColor,\r\n })}\r\n
    \r\n {cardItem.dateTimeFormatted}\r\n {cardItem.listingTitle && {cardItem.listingTitle}}\r\n {tags.length != 0 && {tags.join(', ')}}\r\n {cardItem.listingDescription &&
    {cardItem.listingDescription}
    }\r\n {cardItem.dynamicCardLinkText && (\r\n
    \r\n {cardItem.dynamicCardLinkText}\r\n
    \r\n )}\r\n
    \r\n \r\n )\r\n const bgProps = {\r\n style: {\r\n '--mobile-bg-url': cardItem.listingMobileImage ? `url(${cardItem.listingMobileImage.src})` : null,\r\n '--desktop-bg-url': cardItem.listingDesktopImage ? `url(${cardItem.listingDesktopImage.src})` : null,\r\n '--bg-color': backgroundColor,\r\n '--light-or-dark': lightOrDark(backgroundColor),\r\n },\r\n className: `md:[&:nth-child(3n+3)]:col-start-5 \r\n md:[&:nth-child(3n+2)]:col-start-3 \r\n md:[&:nth-child(3n+1)]:col-start-1 \r\n md:[&:last-child:first-child]:col-start-3 \r\n md:[&:last-child:nth-child(3n+1)]:col-start-3 \r\n md:[&:nth-last-child(2):first-child]:col-start-2 \r\n md:[&:nth-last-child(2):nth-child(3n+1)]:col-start-2 \r\n md:[&:nth-child(2):last-child]:col-start-4 \r\n md:[&:last-child:nth-child(3n+2)]:col-start-4 col-span-2 relative w-full h-full bg-[color:var(--bg-color)] pt-4 px-8 pb-8 rounded-2xl overflow-hidden text-${lightOrDark(backgroundColor)} ${addBgImageClass(cardItem.listingDesktopImage?.src, cardItem.listingMobileImage?.src)}`,\r\n }\r\n\r\n const heroProps = {\r\n className: 'relative w-full pt-4 pb-8 rounded-2xl overflow-hidden',\r\n }\r\n\r\n const inner = variant !== 'Hero image' ? innerBG : innerHero\r\n if (variant !== 'Hero image') {\r\n return cardItem.listingLink ? (\r\n \r\n {inner}\r\n \r\n ) : (\r\n
    \r\n {inner}\r\n
    \r\n )\r\n } else {\r\n return (\r\n \r\n {inner}\r\n
    \r\n )\r\n }\r\n })}\r\n \r\n )}\r\n {!viewMore && (\r\n
    \r\n {\r\n setViewMore(true)\r\n }}\r\n >\r\n {props.viewMoreText || 'View more'}\r\n \r\n \r\n
    \r\n )}\r\n \r\n \r\n )\r\n}\r\n\r\nexport default CardListDynamic\r\n","import Section from './_Section'\r\nimport { createMarkup, createGradientElement } from '../../helpers/markup'\r\nimport { addBgImageClass, lightOrDark, transformPaddingToTailwind } from '../../helpers/style'\r\nimport ButtonEl from '../helpers/ctas/Button'\r\nimport { useState, useEffect } from 'react'\r\n\r\nfunction ContentFiftybyFifty(props) {\r\n const [backgroundColor, setBackgroundColor] = useState('transparent')\r\n const [gradientColor, setgradientColor] = useState('#fff')\r\n const componentPadding = transformPaddingToTailwind(props.componentPadding)\r\n\r\n useEffect(() => {\r\n const bgColor = props.cardBackgroundColour.replace('#', '')\r\n const fgColor = props.imageGradientColour.replace('#', '')\r\n setBackgroundColor((prevState) => (bgColor ? `#${bgColor}` : prevState))\r\n setgradientColor((prevState) => (fgColor ? `#${fgColor}` : prevState))\r\n }, [])\r\n\r\n return (\r\n
    \r\n
    \r\n
    \r\n {props.cardItems.map((cardItem, idx) => (\r\n \r\n {props.imageGradientColour &&\r\n createGradientElement({\r\n type: props.imageGradientType,\r\n fromColor: gradientColor,\r\n classes: 'rounded-2xl',\r\n })}\r\n
    \r\n {cardItem.title && !cardItem.useSmallTitle && (\r\n \r\n {cardItem.title}\r\n \r\n )}\r\n {cardItem.title && cardItem.useSmallTitle && (\r\n \r\n {cardItem.title}\r\n \r\n )}\r\n {cardItem.description && (\r\n
    \r\n )}\r\n\r\n {/* {cardItem.videoUrl ? : null} */}\r\n\r\n {cardItem.ctaLinkItem.length != 0 && (\r\n
    \r\n {cardItem.ctaLinkItem.map((ctaLinkItem, i) => (\r\n \r\n ))}\r\n
    \r\n )}\r\n
    \r\n
    \r\n ))}\r\n
    \r\n
    \r\n
    \r\n )\r\n}\r\n\r\nexport default ContentFiftybyFifty\r\n","import { useState, useEffect } from 'react'\r\nimport Section from './_Section'\r\nimport { createMarkup } from '../../helpers/markup'\r\nimport ButtonEl from '../helpers/ctas/Button'\r\nimport Picture from '../helpers/Picture'\r\nimport Image from '../helpers/Image'\r\nimport TitleBlock from '../helpers/TitleBlock'\r\nimport { transformPaddingToTailwind } from '../../helpers/style'\r\nimport themeConfig from '../../../theme.config'\r\n\r\nfunction HeroBanner(props) {\r\n // const hasCardItems = props.cardItems.length != 0\r\n const maxCards = 6\r\n const [hasCardItems, setHasCardItems] = useState(0)\r\n const [cardColumns, setCardColumns] = useState(6)\r\n const [textAlignment, setTextAlignment] = useState({\r\n flex: 'center',\r\n align: 'center',\r\n })\r\n const [cardStartCols, setCardStartCols] = useState('col-start-1')\r\n const [cardSpanCols, setCardSpanCols] = useState('col-span-4')\r\n const componentPadding = transformPaddingToTailwind(props.componentPadding, true)\r\n\r\n useEffect(() => {\r\n setHasCardItems(() => props.cardItems.length != 0)\r\n setCardColumns(() => {\r\n let cols = 'full'\r\n switch (props.cardItems.length) {\r\n case 6:\r\n case 5:\r\n cols = 'justify-between'\r\n break\r\n case 4:\r\n case 3:\r\n case 2:\r\n cols = 'justify-evenly'\r\n break\r\n case 1:\r\n cols = 'justify-center'\r\n break\r\n }\r\n return cols\r\n })\r\n let start = 'col-start-1'\r\n let span = 'col-span-4'\r\n switch (props.cardItems.length) {\r\n case 6:\r\n start = 'col-start-1 md-col-start-1'\r\n span = 'col-span-2 md:col-span-4'\r\n break\r\n case 5:\r\n start = 'col-start-1 md:col-start-1 2xl:col-start-3'\r\n span =\r\n 'col-span-2 md:col-span-4 2xl:col-span-4 max-md:[&:last-child]:col-start-2 md:max-2xl:[&:nth-last-child(2)]:col-start-3 '\r\n break\r\n case 4:\r\n start = 'col-start-1 md:col-start-1 2xl:col-start-5'\r\n span = 'col-span-2 md:col-span-4 2xl:col-span-4 md:max-2xl:[&:last-child]:col-start-5 '\r\n break\r\n case 3:\r\n start = 'col-start-1 md-col-start-1 2xl:col-start-7'\r\n span = 'col-span-2 md:col-span-4 2xl:col-span-4 max-md:[&:last-child]:col-start-2 '\r\n break\r\n case 2:\r\n start = 'col-start-1 md:col-start-3 2xl:col-start-9'\r\n span = 'col-span-2 md:col-span-4 2xl:col-span-4'\r\n break\r\n case 1:\r\n start = 'col-start-2 md:col-start-5 2xl:col-start-11 '\r\n span = 'col-span-2 md:col-span-4 2xl:col-span-4'\r\n break\r\n }\r\n setCardStartCols(start)\r\n setCardSpanCols(span)\r\n }, [props.cardItems])\r\n\r\n useEffect(() => {\r\n setTextAlignment((prevState) => {\r\n const newState = { ...prevState }\r\n const alignment = props.contentAlignment?.toLowerCase() ?? 'center'\r\n if (newState.align !== props.contentAlignment?.toLowerCase()) {\r\n newState.flex = alignment === 'center' ? 'center' : 'start'\r\n newState.align = alignment === 'center' ? 'center' : 'left'\r\n }\r\n return newState\r\n })\r\n }, [])\r\n\r\n return (\r\n <>\r\n \r\n
    \r\n {(props.title || props.description) && }\r\n {props.ctaLinkItem.length != 0 && (\r\n \r\n {props.ctaLinkItem.map((ctaLinkItem, i) => (\r\n \r\n ))}\r\n
    \r\n )}\r\n \r\n \r\n {(hasCardItems || props.footnoteText) && (\r\n \r\n
    \r\n {hasCardItems && (\r\n //
    \r\n \r\n {props.cardItems.map((cardItem, i) => {\r\n const inner = (\r\n <>\r\n \r\n
    \r\n \r\n
    \r\n {cardItem.title}\r\n
    \r\n \r\n )\r\n // const className = ` w-full px-2 max-sm:py-1 py-2 cardItem basis-1/2 md:max-2xl:basis-1/3 2xl:basis-1/6`\r\n const className = `${i === 0 ? cardStartCols : ''} w-full max-sm:py-1 py-2 cardItem basis-1/2 md:max-2xl:basis-1/3 2xl:basis-1/6 rounded-lg ${cardSpanCols} `\r\n return cardItem.ctaLinkItem[0]?.link?.url ? (\r\n \r\n {inner}\r\n \r\n ) : (\r\n \r\n {inner}\r\n
    \r\n )\r\n })}\r\n \r\n )}\r\n\r\n {props.footnoteText && (\r\n \r\n )}\r\n \r\n \r\n )}\r\n \r\n )\r\n}\r\n\r\nexport default HeroBanner\r\n","import { useState, useEffect } from 'react'\r\nimport Section from './_Section'\r\nimport { createMarkup } from '../../helpers/markup'\r\nimport ButtonEl from '../helpers/ctas/Button'\r\nimport Image from '../helpers/Image'\r\nimport TitleBlock from '../helpers/TitleBlock'\r\nimport { transformPaddingToTailwind } from '../../helpers/style'\r\n\r\nfunction InformationBanner(props) {\r\n const [textAlignment, setTextAlignment] = useState({\r\n flex: 'center',\r\n align: 'center',\r\n })\r\n const componentPadding = transformPaddingToTailwind(props.componentPadding)\r\n\r\n useEffect(() => {\r\n setTextAlignment((prevState) => {\r\n const newState = { ...prevState }\r\n const alignment = props.contentAlignment?.toLowerCase() ?? 'center'\r\n if (newState.align !== props.contentAlignment?.toLowerCase()) {\r\n newState.flex = alignment === 'center' ? 'center' : 'start'\r\n newState.align = alignment === 'center' ? 'center' : 'left'\r\n }\r\n return newState\r\n })\r\n }, [])\r\n\r\n return (\r\n \r\n \r\n {(props.title || props.description) && }\r\n\r\n {props.ctaLink.length != 0 && (\r\n
    \r\n {props.ctaLink.map((ctaLinkItem, i) => (\r\n \r\n ))}\r\n
    \r\n )}\r\n \r\n )\r\n}\r\n\r\nexport default InformationBanner\r\n","import Section from './_Section'\r\nimport { createMarkup } from '../../helpers/markup'\r\nimport Image from '../helpers/Image'\r\nimport TitleBlock from '../helpers/TitleBlock'\r\nimport { transformPaddingToTailwind } from '../../helpers/style'\r\n\r\nfunction RatesCalculator(props) {\r\n // not adding the boolean to the end output the length field 0 if there was no data.\r\n const right = props.rightTitle || props.linkItems?.length || false\r\n const stacked = props.layout === 'Single column'\r\n const componentPadding = transformPaddingToTailwind(props.componentPadding)\r\n\r\n return (\r\n
    \r\n
    \r\n \r\n {(props.title || props.description) && }\r\n\r\n {props.url &&