/* Reimplementation of the handful of Wix components this site actually uses.
 *
 * The Wix client runtime is removed at build time (scripts/strip-runtime),
 * because it cannot work without Wix and a half-booted runtime destroys the
 * server-rendered content. This file replaces the small number of components
 * that genuinely needed JS. See DECISIONS.md.
 *
 * Everything else on the site is plain markup and Wix's own CSS, which is
 * kept as-is.
 */

/* ------------------------------------------------------------------
 * <fluid-columns-repeater>  -- 26 pages, incl. the programs grid
 *
 * A custom element. Wix's JS defines it, and on upgrade it absolutely
 * positions its children into columns and clears the inline
 * visibility:hidden it ships with. Undefined, it never upgrades, so the
 * whole subtree stays hidden -- 452 of 842 elements on /programs.
 *
 * Observed on the live site: children are a fixed 649px wide (from Wix's
 * own CSS, which we still have), two per row, 40px gaps, centred. Flex
 * wrap reproduces that without needing to compute positions.
 * ------------------------------------------------------------------ */

fluid-columns-repeater {
  /* Beats the inline style="visibility:hidden" the element ships with. */
  visibility: visible !important;

  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: 40px;
  position: relative;
  box-sizing: border-box;

  /* `safe` degrades to flex-start instead of centring when a row overflows.
   * Plain `center` splits the overflow both ways, and the left half is
   * unreachable -- it cannot be scrolled to and gets clipped.
   */
  justify-content: safe center;

  /* Wix ships this element with a negative margin on all four sides: gutter
   * compensation for the 20px inset it gives each child, so that the outer
   * children still sit flush with the container edge. The real component
   * positions children absolutely at `top: 20px`; we lay them out with flex
   * and never apply that inset, so every negative margin is left uncancelled.
   *
   * Horizontally that dragged the row 20px left and clipped the leftmost card
   * at every column count. Vertically it pulled the cards 20px up into the
   * text above them -- measured against the live site, which leaves 23px
   * between the paragraph and the first card where we had 3px.
   *
   * Both axes are the same bug, so both are zeroed.
   */
  margin: 0 !important;
  width: auto !important;
}

/* The real component takes children out of flow and places them. Without it
 * they must flow normally or they stack on top of each other.
 *
 * `flex: 0 1 auto` with Wix's fixed 649px width gives the behaviour we want
 * for free: cards keep their width and wrap when a row is full, and shrink
 * only once a single card no longer fits. No breakpoints needed.
 */
fluid-columns-repeater > * {
  position: relative !important;
  inset: auto !important;
  flex: 0 1 auto;
  max-width: 100%;
  min-width: 0;
}

/* ------------------------------------------------------------------
 * <wix-video> background video
 *
 * Wix's runtime set the video's width, height and object-fit as inline
 * styles; no stylesheet carries them. Without the runtime the <video> falls
 * back to its intrinsic size -- an 854x480 box letterboxed inside a 993x622
 * container -- which reads as "the video is not playing" even while it is.
 *
 * data-video-info gives fittingType "fill" and alignType "center" for both
 * of these, which is cover/centre.
 * ------------------------------------------------------------------ */

wix-video {
  overflow: hidden;
}

wix-video > video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;

  /* Wix ships the video at opacity 0 and fades it in from the runtime once
   * playback starts. Without the runtime it plays correctly and stays
   * invisible -- which looks exactly like "the video is not autoplaying".
   */
  opacity: 1 !important;
}

/* The poster sits AFTER the video in DOM order, so it paints on top of it.
 * Wix's runtime fades the poster out once playback begins; without that the
 * video advances perfectly underneath a static image -- which is
 * indistinguishable from a video that never started.
 *
 * The poster is kept until the shim reports playback, so a still frame is
 * shown rather than a blank box while the video loads, and it stays put
 * entirely if the video never plays (autoplay refused, JS disabled, decode
 * failure).
 */
wix-video [class*="bgVideoposter"] {
  transition: opacity 400ms ease;
}

wix-video.as-video-playing [class*="bgVideoposter"] {
  opacity: 0;
  pointer-events: none;
}

/* Anchor buttons scroll rather than jump, as they do on the live site, where
 * the runtime animated it. Declared as a preference query so that a visitor
 * who has asked for reduced motion keeps the instant jump.
 */
@media (prefers-reduced-motion: no-preference) {
  html { scroll-behavior: smooth; }
}

/* ------------------------------------------------------------------
 * In-page anchors  -- scripts/fix-anchors
 *
 * Wix's anchor buttons are JS-driven: the href is a no-JS fallback pointing
 * at the current page, and the runtime reads data-anchor and scrolls. With
 * the runtime gone, clicking them just reloaded the page.
 *
 * They are rewritten to real fragment links at build time. Wix only renders
 * an anchor element for anchors that were named in the editor, so the rest
 * are generated with this class -- zero height, no layout impact, matching
 * how Wix's own anchor divs behave.
 * ------------------------------------------------------------------ */

/* The sticky header, faded -- see initHeaderFade() in the shim. Same values
 * the live site's own class carries: it stays in the layout and keeps its
 * place at the top, it simply stops being visible or clickable.
 */
.as-header-faded {
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.2s ease-in;
}

/* Where the scroll lands.
 *
 * An earlier version of this offset the target by the height of the site
 * header, on the reasoning that `#SITE_HEADER` is `position: sticky` and
 * would otherwise cover the top of the section. It does say sticky -- and it
 * never sticks: it is a grid item of #masterPage with `grid-area: 1/1/2/2`,
 * and a sticky box can only travel inside its containing block, which for a
 * grid item is its grid area. That row is exactly as tall as the header, so
 * there is nowhere to travel and it scrolls away like any other element.
 * The live site behaves the same way, being the same CSS: click an anchor
 * there and the header is gone, with the section's divider at the very top.
 * The 104px this used to add therefore landed every section a header's
 * height lower than Wix landed it.
 *
 * Wix's own anchor div, where the editor had one, sits exactly where its
 * runtime scrolled to, so that lands at the top with no adjustment at all.
 */
.as-anchor-target {
  scroll-margin-top: 0;
}

/* Where there was no anchor div, the id went on the section heading instead
 * -- which is below the point Wix scrolled to, by whatever gap the editor
 * left there. That gap was measured per page by driving the live site (see
 * "_offsets" in inventory/anchors.json) and each target carries its own
 * figure in a style attribute; this is only the fallback for a target with
 * no measurement, and the measured ones run from 30px to 72px.
 */
.as-anchor-heading {
  scroll-margin-top: 40px;
}

/* ------------------------------------------------------------------
 * horizontal-menu dropdowns  -- 69 pages (Services, Company)
 *
 * The submenu is fully present in the DOM with real links; Wix hides it with
 * `display: none` on the positionBox and `opacity: 0` on the animationBox,
 * and its JS toggles both on hover/focus.
 *
 * The positionBox is `position: fixed` with no offsets, which sounds like it
 * would need JS to place. It does not: a fixed element with auto offsets
 * resolves to its static position, which is already directly beneath its menu
 * item. Measured -- revealing it with no other change puts the flyout at
 * top:60 left:400 against an item whose bottom is 60 and left is 400.
 *
 * Class names are Wix-generated (itemDepth02233374943__positionBox), so these
 * match on the stable part of the name rather than the whole thing.
 * ------------------------------------------------------------------ */

.wixui-horizontal-menu__item:hover [class*="positionBox"],
.wixui-horizontal-menu__item:focus-within [class*="positionBox"] {
  display: block !important;
}

.wixui-horizontal-menu__item:hover [class*="animationBox"],
.wixui-horizontal-menu__item:focus-within [class*="animationBox"] {
  opacity: 1 !important;
}

/* The flyout is a descendant of the item and sits flush against its bottom
 * edge, so moving the pointer into it keeps :hover alive and there is no
 * gap to fall through.
 *
 * Known limitation: aria-expanded stays "false" because CSS cannot change an
 * attribute. Screen readers will announce the trigger as collapsed even when
 * it is open. Fixing that needs a few lines of JS; noted in BUGS.md rather
 * than shipping script for it now.
 */

/* ------------------------------------------------------------------
 * Captcha  -- /contact and /professional-development
 *
 * Wix renders a placeholder that its runtime swaps for the real widget:
 *
 *   <div class="... wixui-captcha">
 *     <div class="Captcha...__captchaLoader"></div>
 *     <div class="Captcha...__captcha"></div>
 *
 * Without the runtime the loader spins forever next to the submit button.
 *
 * The container is reused rather than hidden: scripts/add-turnstile swaps its
 * contents for a Cloudflare Turnstile widget, so the real captcha lands
 * exactly where Wix's was, already positioned and spaced by Wix's own CSS.
 *
 * Matched on wixui-captcha, not the hashed Captcha3940957316 class, which is
 * regenerated by Wix builds.
 * ------------------------------------------------------------------ */

/* Anything left of Wix's placeholder if a page was not rewritten. */
[class*="captchaLoader"],
[class*="Captcha"][class*="__checkbox"] {
  display: none !important;
}

/* Wix's captcha slot is 234x60 and its position is load-bearing: on
 * /professional-development the Submit button sits in the SAME row, starting
 * 10px to the right of the slot. Widening the slot to centre the widget -- an
 * earlier attempt here -- made it overlap the button on that page.
 *
 * So the slot keeps exactly the geometry Wix gave it, matching the live site,
 * where the captcha is left-aligned with the Submit button's left edge rather
 * than centred on the form.
 *
 * Turnstile's widget is ~300px, wider than the 234px slot. Two things follow:
 *
 *  - `flex: none` stops flexbox shrinking the widget to 234px, which squashed
 *    it and was what actually looked wrong.
 *  - it is scaled down to fit instead, by a factor the shim measures per slot.
 *    Scaling rather than overflowing, because overflow would run straight into
 *    the Submit button on /professional-development.
 */
.as-turnstile {
  display: flex;
  justify-content: flex-start;   /* left-aligned, as on the live site */
  align-items: center;
  min-height: 60px;              /* the slot's own height, so nothing jumps */
}

.as-turnstile > * {
  flex: none;
  transform: scale(var(--as-ts-scale, 1));
  transform-origin: left center;
}

/* Honeypot: out of sight and out of the accessibility tree, without
 * display:none or visibility:hidden -- some bots specifically skip fields
 * hidden that way, which would defeat the point.
 */
.as-honeypot {
  position: absolute !important;
  left: -9999px !important;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* ------------------------------------------------------------------
 * Members / login
 *
 * Dropped entirely: 31 accounts, exactly one of which ever logged in
 * twice, and that is the owner. Booking never required an account. The
 * control is inert without the Wix runtime, so hide it rather than leave
 * a dead button in the header.
 * ------------------------------------------------------------------ */

.wixui-login-social-bar,
[class*="wixui-login-social-bar"] {
  display: none !important;
}

/* ------------------------------------------------------------------
 * Cart
 *
 * Wix Stores is installed but has never taken a payment, and with Bookings
 * and Members both dropped there is nothing to buy and no one to buy it.
 * The icon links to /cart-page, which is not even in the mirror.
 *
 * Identifying it takes a component id because the semantic markers
 * (aria-label="Cart with 0 items", data-hook="cart-icon-button") are added
 * by the Wix runtime and so are absent from the stripped build -- verified
 * by inspecting the same component on the live site. The data-hook rules
 * are kept as a defensive second selector in case a future mirror captures
 * a page where the runtime had already run.
 * ------------------------------------------------------------------ */

#comp-m6fobjwt,
[data-hook="cart-icon-button"],
[data-hook="cart-icon"] {
  display: none !important;
}

/* ------------------------------------------------------------------
 * Contact form status
 *
 * The form posts with fetch and reports in place, so there is no thank-you
 * page and the API returns JSON rather than HTML. role="status" announces
 * the result to screen readers without moving focus mid-task.
 * ------------------------------------------------------------------ */

.as-form-status {
  margin: 1em 0 0;
  min-height: 1.5em;      /* reserve the line so nothing jumps on first message */

  /* Absolute, not relative. This element is appended to the <form>, which
   * inherits a very small font-size from Wix's own form styles -- 0.95em of
   * that rendered at roughly 8px and was genuinely unreadable. The one message
   * telling a visitor their enquiry failed is the last thing that should be
   * hard to read.
   */
  font-size: 16px;
  line-height: 1.5;
  font-weight: 500;

  /* Every other control in the form is centred; the status was left-aligned
   * against the form's left edge and read as unrelated to it.
   */
  text-align: center;
}

/* The address has to stay legible against whatever the form sits on, so it
 * inherits the status colour rather than picking up a link colour that may be
 * invisible on this background.
 */
.as-form-status a {
  color: inherit;
  text-decoration: underline;
}

.as-form-status[data-kind="success"] { color: #7ee787; }
.as-form-status[data-kind="error"]   { color: #ff9492; }
.as-form-status:empty                { min-height: 0; margin: 0; }

/* ------------------------------------------------------------------
 * Contact form dialog
 *
 * The status line above is still written and still announced, but on /contact
 * it sits below the fold on a laptop: pressing Send emptied the form and
 * appeared to do nothing else. This dialog is what the visitor actually sees
 * -- a spinner while the request is in flight, then the outcome -- and the
 * form keeps what was typed until it is dismissed.
 *
 * Same z-index as the lightbox, for the same reason: #SITE_HEADER is sticky
 * with a z-index of its own and Wix's sections create stacking contexts, so
 * anything appended to <body> has to be above all of it. The two are never
 * open at once (one is on /contact, the other on the gallery pages).
 * ------------------------------------------------------------------ */

.as-modal {
  position: fixed;
  inset: 0;
  z-index: 2147483000;
  background: rgba(20, 28, 46, 0.72);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  box-sizing: border-box;
}

/* The same trap the lightbox hits below, and for the same reason: `display:
 * flex` above is an author rule, so it beats the browser's own
 * [hidden] { display: none }. Without this, `root.hidden = true` sets the
 * attribute and changes nothing on screen -- the dialog stays up while every
 * dismissal path fires correctly, so Close, the backdrop and Escape all look
 * broken at once. It shipped that way; the local check asserted the property
 * rather than that the thing had actually gone.
 */
.as-modal[hidden] { display: none !important; }

/* Same again for the Close button, which is hidden while the request is in
 * flight. Its own rules below do not set `display`, so the browser's [hidden]
 * would normally be enough -- but only until one of Wix's stylesheets sets a
 * display on buttons, and then the dialog would offer a Close button during
 * the spinner that deliberately does nothing.
 */
.as-modal-close[hidden] { display: none !important; }

.as-modal-box {
  background: #fff;
  color: #2e3f66;
  border-radius: 8px;
  box-shadow: 0 18px 48px rgba(0, 0, 0, 0.35);
  padding: 32px 28px 28px;
  width: 100%;
  max-width: 420px;
  box-sizing: border-box;
  text-align: center;

  /* Absolute, like the status line and for the same reason: the dialog is a
   * child of <body>, but Wix's font-size cascade is unpredictable enough that
   * a relative size here has already produced 8px text once.
   */
  font-size: 16px;
  line-height: 1.5;
  font-weight: 500;
}

/* It is focused on open so the focus trap has somewhere to hold, which is a
 * programmatic focus the visitor did not ask for -- and a ring around the
 * whole dialog reads as an error state.
 */
.as-modal-box:focus { outline: none; }

.as-modal-spinner {
  width: 40px;
  height: 40px;
  margin: 0 auto 18px;
  border: 3px solid rgba(46, 63, 102, 0.18);
  border-top-color: #2e3f66;
  border-radius: 50%;
  animation: as-modal-spin 0.8s linear infinite;
}

/* Only while the request is in flight. Once there is an outcome the spinner
 * would be saying the opposite of the message beside it.
 */
.as-modal:not([data-kind="pending"]) .as-modal-spinner { display: none; }

@keyframes as-modal-spin { to { transform: rotate(360deg); } }

/* A spinner is exactly the kind of thing this preference is about. The dot
 * still marks the place, and the message says what is happening.
 */
@media (prefers-reduced-motion: reduce) {
  .as-modal-spinner {
    animation: none;
    border-color: rgba(46, 63, 102, 0.18);
    border-top-color: #2e3f66;
  }
}

.as-modal-message {
  margin: 0;
}

.as-modal-message a {
  color: inherit;
  text-decoration: underline;
}

/* Darker than the status line's colours, which were chosen for white text on
 * the form's dark panel; #7ee787 on white is barely there.
 */
.as-modal[data-kind="success"] .as-modal-message { color: #1a7f37; }
.as-modal[data-kind="error"]   .as-modal-message { color: #b42318; }

.as-modal-close {
  margin: 22px 0 0;
  padding: 10px 28px;
  border: 0;
  border-radius: 4px;
  background: #2e3f66;
  color: #fff;
  font: inherit;
  cursor: pointer;
}

.as-modal-close:hover  { background: #26355a; }
.as-modal-close:focus-visible { outline: 2px solid #2e3f66; outline-offset: 2px; }

/* The page behind must not scroll: it is a form the visitor should not be
 * editing until they have read the outcome. The compensating padding for the
 * vanished scrollbar is set in JS, where its width can be measured.
 */
body.as-modal-open { overflow: hidden; }

/* ------------------------------------------------------------------
 * Pro Gallery lightbox  -- 16 pages, 202 images
 *
 * Clicking a gallery image opens Wix's fullscreen viewer on the live site.
 * That viewer is built entirely by the runtime, so in the mirror the images
 * were inert. scripts/fix-gallery tags each expandable item with the URL of
 * an uncropped rendition and the shim builds the viewer.
 *
 * Colours are taken from the live viewer rather than guessed: the backdrop
 * computes to rgb(46,63,102), which is Wix's --wix-color-1. Hardcoded because
 * that variable is defined per-component, not on :root, so it is not reliably
 * in scope for an element appended to <body>.
 * ------------------------------------------------------------------ */

.as-lightbox {
  position: fixed;
  inset: 0;
  /* Above the sticky header and Wix's own stacking contexts. */
  z-index: 2147483000;
  background: #2e3f66;
  display: flex;
  align-items: center;
  justify-content: center;
  /* Room for the edge controls so the image never sits under them. */
  padding: 72px 88px;
  box-sizing: border-box;
}

/* Wix's mobile pages declare a fixed 320px viewport, so the desktop padding
 * above eats 176 of 320 and leaves a 144px image -- smaller than the thumbnail
 * that opened it. Measured, not guessed: the viewer rendered at exactly 144px
 * wide on a Pixel 8 before this rule existed.
 *
 * The arrows tighten to the edge and overlap the image slightly, which is the
 * right trade on a phone: swiping is the primary gesture there, and the
 * alternative is a postage stamp.
 */
@media (max-width: 600px) {
  .as-lightbox { padding: 56px 6px; }

  /* The desktop hit areas are 100px squares, which on a 320px viewport would
   * leave 120px of image between them. The marks inside stay the same size. */
  .as-lb-prev, .as-lb-next { width: 56px; height: 80px; top: calc(50% - 40px); }
  .as-lb-prev { left: 0; }
  .as-lb-next { right: 0; }

  .as-lb-close  { top: 10px; right: 10px; }
  .as-lb-expand { top: 10px; left: 10px; }
}

/* The reset in the page head already carries [hidden]{display:none!important},
 * but this element is toggled by a stylesheet we do not control the order of,
 * and `display:flex` above would otherwise win against a plain [hidden].
 */
.as-lightbox[hidden] { display: none !important; }

/* The viewer is a horizontal scroll-snap track rather than one <img> whose src
 * is swapped. Swapping made navigation a hard cut; the live viewer slides, and
 * it builds the same thing -- inspecting it mid-swipe shows every image in the
 * gallery present side by side.
 *
 * Native scrolling also means a finger drags the image with it, which no
 * amount of transform animation reproduces faithfully.
 */
.as-lb-track {
  display: flex;
  width: 100%;
  height: 100%;
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
  /* Keeps a drag from turning into browser back-navigation on the edges. */
  overscroll-behavior-x: contain;
}

.as-lb-track::-webkit-scrollbar { display: none; }

.as-lb-slide {
  flex: 0 0 100%;
  scroll-snap-align: center;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100%;
}

.as-lightbox img {
  max-width: 100%;
  max-height: 100%;
  width: auto;
  height: auto;
  object-fit: contain;
}

.as-lightbox button {
  position: absolute;
  display: flex;
  align-items: center;
  justify-content: center;
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
  /* Full strength, the way the live viewer draws them: it dims its controls
   * only once the browser itself is in full screen, and never on hover. */
  color: #fff;
  line-height: 1;
  font-family: inherit;
}

/* A visible focus ring matters more here than usual: the viewer traps focus,
 * so a keyboard user who cannot see where focus is has no way out but Esc.
 * This is the live viewer's own ring -- a white hairline inside blue, tucked
 * within the button rather than drawn around it.
 */
.as-lightbox button:focus-visible {
  outline: none;
  border-radius: 7px;
  box-shadow: inset 0 0 0 1px #fff, inset 0 0 1px 4px #116dff;
}

/* box-shadow is not painted in forced-colours mode, which would drop the ring
 * for exactly the people least able to do without it.
 */
@media (forced-colors: active) {
  .as-lightbox button:focus-visible { outline: 2px solid CanvasText; }
}

/* Geometry from the stylesheet the icons came out of (Wix's pro-fullscreen
 * renderer): the corner controls are a 38x44 button 30px down from the top
 * holding a 26px glyph; the arrows sit in a 100px square hit area centred
 * vertically against the viewport edge, with a 15x27 chevron in the middle.
 * The hit area is far larger than the mark it shows, which is the point.
 */
.as-lb-close  { top: 30px; right: 30px; width: 38px; height: 44px; }
.as-lb-expand { top: 30px; left: 35px;  width: 38px; height: 44px; }
.as-lb-close .as-lb-icon,
.as-lb-expand .as-lb-icon { width: 26px; height: 26px; }

.as-lb-prev, .as-lb-next { top: calc(50% - 50px); width: 100px; height: 100px; }
.as-lb-prev { left: 0; }
.as-lb-next { right: 0; }
.as-lb-prev .as-lb-icon,
.as-lb-next .as-lb-icon { width: 15px; height: 27px; }

.as-lb-icon { display: block; }

/* Hidden at the ends of the gallery -- see sync() in the shim. The rule above
 * gives these buttons `display: flex`, and an author declaration beats the
 * browser's own [hidden] rule, so without this they would stay visible.
 */
.as-lightbox button[hidden] { display: none !important; }

/* Hidden rather than removed when there is only one image, so the layout and
 * the focus order do not change between galleries of different sizes.
 */
.as-lightbox[data-single="1"] .as-lb-prev,
.as-lightbox[data-single="1"] .as-lb-next { display: none; }

/* Announced to screen readers as the image changes; the live viewer shows no
 * visible counter and adding one would be a visual difference.
 */
.as-lb-count {
  position: absolute;
  width: 1px; height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* Gallery thumbnails that open the viewer. Wix gives its items
 * tabindex="-1" and drives focus from JS; the shim makes them real buttons
 * instead, so they need to look focusable.
 */
[data-as-full] { cursor: pointer; }

.gallery-item-container:focus-visible,
[data-hook="item-link-wrapper"]:focus-visible {
  outline: 3px solid #2e3f66;
  outline-offset: 2px;
}

/* Wix locks the page behind its viewer; without this the page scrolls under
 * the backdrop when the wheel is used.
 */
body.as-lightbox-open { overflow: hidden; }

@media (prefers-reduced-motion: reduce) {
  .as-lightbox * { transition: none !important; }
}


/* ------------------------------------------------------------------
 * Mobile navigation menu
 *
 * Wix hides the panel with `[data-undisplayed=true]{display:none}` and then
 * layers opacity/visibility on a generated class (.I_VSKP at time of writing).
 * The attribute is stable and semantic; the class name is a build artifact and
 * will change the next time the site is mirrored, so the shim toggles the
 * attribute and supplies its own visible state keyed on Wix's public
 * `wixui-` class instead of the hash.
 * ------------------------------------------------------------------ */

.wixui-mobile-menu.as-menu-open {
  opacity: 1 !important;
  visibility: visible !important;
}

/* The toggle CANNOT double as the close button here, however much z-index it
 * is given. #SITE_HEADER is `position: sticky; z-index: 50`, which makes it a
 * stacking context, so the toggle inside it is confined to that context and
 * can never paint above the panel at z-index 99999. Measured:
 * document.elementFromPoint over the toggle returns the panel, and the click
 * never reaches the button.
 *
 * So the toggle is hidden while the panel is open and a real close button is
 * rendered inside the panel, where being on top is not in question.
 */
.wixui-mobile-menu__icon.as-menu-open-toggle { visibility: hidden; }

.as-menu-close {
  position: absolute;
  top: 12px;
  right: 16px;
  width: 44px;
  height: 44px;
  padding: 0;
  border: 0;
  background: none;
  color: #fff;
  cursor: pointer;
  z-index: 10;
}

.as-menu-close::before,
.as-menu-close::after {
  content: "";
  position: absolute;
  left: 10px;
  top: 21px;
  width: 24px;
  height: 2px;
  border-radius: 2px;
  background: currentColor;
}

.as-menu-close::before { transform: rotate(45deg); }
.as-menu-close::after  { transform: rotate(-45deg); }

.as-menu-close:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 4px;
}

/* The scrolling element is <html>, not <body> -- locking only the body left
 * the page scrolling underneath the open panel. Both are locked because which
 * one scrolls varies by browser and by document.
 */
html.as-menu-locked,
body.as-menu-locked {
  overflow: hidden;
}

/* A menu taller than the viewport still has to scroll within itself. */
.wixui-mobile-menu.as-menu-open {
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
}



/* Expandable Services/Company sections inside the panel. Same reasoning: Wix
 * adds a generated class to the <li>; this keys on the public one.
 */
.wixui-vertical-menu__item.as-submenu-open > * > .wixui-vertical-menu__submenu,
.wixui-vertical-menu__item.as-submenu-open > .wixui-vertical-menu__submenu {
  display: block !important;
  opacity: 1 !important;
}

/* The chevron points up while its section is open, as on the live site. */
.wixui-vertical-menu__arrow {
  transition: transform 200ms ease;
}

.wixui-vertical-menu__item.as-submenu-open > * > * > .wixui-vertical-menu__arrow,
.wixui-vertical-menu__item.as-submenu-open .wixui-vertical-menu__arrow {
  transform: rotate(180deg);
}

/* ------------------------------------------------------------------
 * Back to top
 *
 * #BACK_TO_TOP_BUTTON is already in the markup, at opacity 0 / visibility
 * hidden, waiting for a runtime that no longer exists. It only needs showing
 * while the visitor is scrolling and for a moment afterwards.
 * ------------------------------------------------------------------ */

.BACK_TO_TOP_BUTTON {
  transition: opacity 250ms ease, visibility 250ms ease;
}

.BACK_TO_TOP_BUTTON.as-btt-visible {
  opacity: 1 !important;
  visibility: visible !important;
  cursor: pointer;
}

@media (prefers-reduced-motion: reduce) {
  .as-lb-track { scroll-behavior: auto; }
}


/* ------------------------------------------------------------------
 * Blog post "more actions" menu
 *
 * The button is in the markup with aria-haspopup, but Wix built the menu
 * itself from JS, so there is nothing to style -- these rules describe the
 * menu the shim creates. Colours come from the post card rather than being
 * invented, so it sits on the page rather than on top of it.
 * ------------------------------------------------------------------ */

.as-post-menu {
  position: absolute;
  right: 0;
  top: 100%;
  z-index: 20;
  min-width: 160px;
  padding: 4px;
  border-radius: 6px;
  background: #fff;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.25);
}

.as-post-menu[hidden] { display: none !important; }

.as-post-menu-item {
  display: block;
  width: 100%;
  padding: 10px 14px;
  border: 0;
  border-radius: 4px;
  background: none;
  font: inherit;
  font-size: 15px;
  color: #2e3f66;
  text-align: left;
  cursor: pointer;
  white-space: nowrap;
}

.as-post-menu-item:hover,
.as-post-menu-item:focus-visible { background: rgba(46, 63, 102, 0.08); }
