/* Bioperio Sticky Bar — every class is prefixed with bsb- so nothing can
   collide with a class the theme or another plugin already defines globally.

   DESIGN NOTE — why so many custom properties.
   Every responsive control Elementor renders wins on specificity: it emits
   `.elementor-{doc} .elementor-element.elementor-element-{id} .bsb-inner {…}`,
   which no rule in this file can outrank. A plain `@media (max-width: 767px)`
   block here therefore loses to the desktop value of any control it tries to
   override — and it also hardcodes 767px, which is wrong on a site that moved
   Elementor's breakpoints.

   So every switch that has to differ per device (phrase on/off, which CTA
   label, how the buttons share the row) is expressed as a custom property with
   a fallback below, and the controls write those properties per breakpoint.
   Elementor generates the media queries from its own breakpoint config, and
   the cascade stops being a fight.

   Two levels are used deliberately:
     - controls write to `.bsb-bar`      → per-device, user-chosen;
     - render-time state writes to `.bsb-inner` → beats the inherited value
       from `.bsb-bar` for a state PHP knows about (e.g. no phrase at all),
       without having to out-specify Elementor. */

.bsb-bar {
	--bsb-z-index: 999;
	--bsb-edge-offset: 0px;
	--bsb-side-inset: 0px;
	--bsb-anim-duration: 400ms;

	/* Layout switches — overwritten per breakpoint by the widget controls. */
	--bsb-inner-justify: space-between;
	--bsb-text-display: block;
	--bsb-actions-margin: 0px;
	--bsb-actions-flex: 0 1 auto;
	--bsb-actions-width: auto;
	--bsb-actions-wrap: wrap;
	--bsb-actions-direction: row;
	--bsb-actions-align: center;
	--bsb-btn-flex: 0 1 auto;
	--bsb-btn-wrap: normal;

	/* Long/short CTA copy: which of the two labels is the visible one. */
	--bsb-label-base: inline;
	--bsb-label-alt: none;

	--bsb-btn-transition: 200ms;
	--bsb-btn-lift: 1px;
	--bsb-btn-icon-order: 0;
	--bsb-btn-icon-size: 1.2em;
	--bsb-btn-icon-gap: 8px;

	position: fixed;
	left: var(--bsb-side-inset);
	right: var(--bsb-side-inset);
	z-index: var(--bsb-z-index);
	display: flex;
	align-items: center;
	gap: 12px;
	box-sizing: border-box;
	margin: 0;

	/* The footer shift rides on `translate` — the individual property, not the
	   `transform` shorthand — for two reasons that both matter:

	     - `transform` is transitioned below for the entrance animation, and
	       `transition-property: transform` does NOT cover `translate`. Putting
	       the shift on `transform` would inherit that 400ms ease-out, and the
	       bar would glide onto the footer edge a third of a second late on
	       every scroll: it visibly peels off the footer and drifts back on.
	     - it is a transform-family property, so the shift is composited rather
	       than triggering a layout pass, which keeps it in the same frame as
	       the scroll that caused it.

	   `translate` is applied before `transform` in the property order, so the
	   two compose cleanly: the bar can slide out of view from wherever it is
	   currently parked. */
	translate: 0 var(--bsb-stop-translate, 0px);

	transition:
		transform var(--bsb-anim-duration) cubic-bezier(0.22, 1, 0.36, 1),
		opacity var(--bsb-anim-duration) ease,
		visibility 0s linear 0s;
}

.bsb-bar--bottom {
	bottom: var(--bsb-edge-offset);
}

.bsb-bar--top {
	top: var(--bsb-edge-offset);
}

.bsb-inner {
	display: flex;
	flex: 1 1 auto;
	min-width: 0;
	box-sizing: border-box;
	margin-inline: auto;
	width: 100%;
	flex-direction: row;
	align-items: center;
	justify-content: var(--bsb-inner-justify, space-between);
	flex-wrap: wrap;
	gap: 24px;
}

/* Content coming from an Elementor template: let the template's own container
   drive the layout, this only gives it room. */
.bsb-content {
	flex: 1 1 auto;
	min-width: 0;
}

.bsb-content > .elementor {
	width: 100%;
}

/* ---------------------------------------------------------------------------
   Elementor entrance animations
   Elementor stamps `elementor-invisible` (visibility: hidden) on any widget
   that has an Advanced → Motion Effects entrance animation, and only removes
   it from JS once the widget scrolls into view. That never happens here: the
   bar is position: fixed, so its wrapper collapses to 0px height and may never
   satisfy the observer — the bar then stays invisible forever.

   An Elementor entrance animation on a fixed bar is meaningless anyway (the
   widget has its own Entrance control under Behaviour), so it is neutralised.
   Scoped to this widget type by class, so no other widget on the site is
   affected. The script strips the class too, for the case where a stale cached
   stylesheet is served.
   ------------------------------------------------------------------------ */

.elementor-widget-bioperio_sticky_bar.elementor-invisible,
.elementor-widget-bioperio_sticky_bar.elementor-invisible > .elementor-widget-container {
	visibility: visible;
}

/* ---------------------------------------------------------------------------
   Portal
   Host the script creates as a direct child of <body> when an ancestor of the
   widget has a transform / filter / perspective / contain, any of which turns
   that ancestor into the containing block for a position: fixed descendant —
   the bar would then be anchored to the bottom of a page-tall box rather than
   to the viewport, i.e. parked far below the fold. Very common with themes
   that animate a #wrap element (GSAP ScrollTrigger, smooth-scroll libraries).

   Two things the host must NOT do, both of which have to be stated rather than
   assumed:

     - create a containing block. No transform, no filter, no perspective, no
       contain, no will-change naming any of them — otherwise the host would
       reintroduce the exact problem it exists to solve.

     - create a STACKING CONTEXT. This is why it is `absolute` and not `fixed`:
       `position: fixed` always opens a stacking context, which would trap the
       bar's z-index inside a host that is itself only at `z-index: auto`. The
       bar would then be painted under ordinary page content — still at the
       right coordinates, still `visibility: visible`, and completely invisible.
       `position: absolute` with `z-index: auto` opens no stacking context, so
       the bar's own z-index competes at the root exactly as it does when the
       widget has not been moved at all. Relocating the bar has to be invisible
       to the cascade, and that includes paint order.

   0x0 and out of flow, so it takes no space and cannot be stretched by a body
   that happens to be a flex or grid container. No pointer-events juggling
   either: a 0x0 box intercepts nothing, and .bsb-bar--out keeps managing its
   own hit-testing.
   ------------------------------------------------------------------------ */

.bsb-portal {
	position: absolute;
	top: 0;
	left: 0;
	z-index: auto;
	width: 0;
	height: 0;
	margin: 0;
	padding: 0;
	border: 0;
	overflow: visible;
	transform: none;
	filter: none;
	perspective: none;
	contain: none;
	will-change: auto;
}

/* ---------------------------------------------------------------------------
   Out of view
   One single state for both reasons the bar can be away: it has not been
   revealed yet (reveal-after-scroll), or it has reached the footer and the
   "disappear" mode is on. Both animate identically, so they can also overlap
   without fighting each other.

   A bar set to "after scrolling" is rendered with this class already on, so it
   stays hidden when JavaScript is unavailable — deliberate, since the
   alternative is flashing into view on load and then jumping away.
   ------------------------------------------------------------------------ */

.bsb-bar--out {
	visibility: hidden;
	pointer-events: none;
	/* Delay only the visibility flip, so the slide/fade out is actually seen
	   before the bar becomes unhittable. */
	transition:
		transform var(--bsb-anim-duration) cubic-bezier(0.22, 1, 0.36, 1),
		opacity var(--bsb-anim-duration) ease,
		visibility 0s linear var(--bsb-anim-duration);
}

.bsb-bar--out.bsb-bar--anim-slide.bsb-bar--bottom {
	transform: translateY(100%);
}

.bsb-bar--out.bsb-bar--anim-slide.bsb-bar--top {
	transform: translateY(-100%);
}

.bsb-bar--out.bsb-bar--anim-fade {
	opacity: 0;
}

/* Closed by the user (or remembered as closed): out, without animating back. */
.bsb-bar--closed {
	display: none;
}

/* ---------------------------------------------------------------------------
   Quick-fields content
   ------------------------------------------------------------------------ */

.bsb-text {
	display: var(--bsb-text-display, block);
	margin: 0;
	color: #ffffff;
}

/* No phrase was written at all: the buttons are the only child left, so centre
   them instead of leaving them start-aligned by a space-between that now has
   nothing to space. Declared on .bsb-inner rather than on .bsb-bar so it beats
   the value the controls inherit down from .bsb-bar — see the note at the top. */
.bsb-bar--no-text .bsb-inner {
	--bsb-inner-justify: center;
	--bsb-actions-margin: auto;
}

.bsb-actions {
	display: flex;
	flex: var(--bsb-actions-flex, 0 1 auto);
	width: var(--bsb-actions-width, auto);
	flex-wrap: var(--bsb-actions-wrap, wrap);
	flex-direction: var(--bsb-actions-direction, row);
	/* stretch when stacked, so a full-width column really is full width */
	align-items: var(--bsb-actions-align, center);
	justify-content: center;
	margin-inline: var(--bsb-actions-margin, 0px);
	gap: 12px;
	min-width: 0;
}

.bsb-btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	box-sizing: border-box;
	flex: var(--bsb-btn-flex, 0 1 auto);
	min-width: 0;
	/* Inert without an icon: the hidden half of a long/short label pair is
	   display: none, so it is not a flex item and produces no gap. */
	gap: var(--bsb-btn-icon-gap, 8px);
	padding: 19px 30px;
	/* Transparent rather than none, so a button with a visible border and one
	   without still come out exactly the same height. Otherwise the default pair
	   — solid CTA 1, outlined CTA 2 — sits 2px apart, which is just visible
	   enough to look like a mistake once they are side by side on a phone. */
	border: 1px solid transparent;
	border-radius: 48px;
	background-color: #ffffff;
	color: #0f3f5c;
	font: inherit;
	font-size: 15px;
	font-weight: 500;
	line-height: 1.2;
	text-align: center;
	text-decoration: none;
	white-space: var(--bsb-btn-wrap, normal);
	cursor: pointer;
	transition:
		background-color var(--bsb-btn-transition, 200ms) ease,
		color var(--bsb-btn-transition, 200ms) ease,
		border-color var(--bsb-btn-transition, 200ms) ease,
		box-shadow var(--bsb-btn-transition, 200ms) ease,
		transform var(--bsb-btn-transition, 200ms) ease;
}

.bsb-btn:hover,
.bsb-btn:focus-visible {
	text-decoration: none;
	transform: translateY(calc(-1 * var(--bsb-btn-lift, 1px)));
}

.bsb-btn--cta2 {
	background-color: rgba(3, 28, 44, 0.15);
	border: 1px solid rgba(255, 255, 255, 0.22);
	color: #ffffff;
}

/* ---------------------------------------------------------------------------
   Button icons
   `order` rather than two different markups: the icon stays first in the DOM
   whichever side it is shown on, so the label keeps coming first in the
   accessibility tree. The labels are left at the default order of 0, which is
   why 0 puts the icon before them and 2 after.

   No colour of its own — currentColor means the icon tracks the button's text
   colour through hover and focus for free. The per-button icon colour control
   sets `color` on this span when that is not wanted.
   ------------------------------------------------------------------------ */

.bsb-btn__icon {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	flex: 0 0 auto;
	order: var(--bsb-btn-icon-order, 0);
	font-size: var(--bsb-btn-icon-size, 1.2em);
	line-height: 1;
}

/* Font-icon glyph: inherit the size set above rather than the theme's. */
.bsb-btn__icon > i,
.bsb-btn__icon > span {
	font-size: inherit;
	line-height: 1;
}

/* Inline SVG (Elementor's SVG upload, or "inline SVG" for the icon library).
   Squared to the font size and filled with the text colour, which is what makes
   an uploaded icon match a font one without extra tuning. */
.bsb-btn__icon svg {
	display: block;
	width: 1em;
	height: 1em;
	fill: currentColor;
}

/* ---------------------------------------------------------------------------
   Long / short copy
   Both variants are in the DOM and CSS decides which one shows, because PHP
   cannot know the device: page caching would freeze whichever one the first
   visitor happened to get.

   The swap is opted into per element with --has-alt. Without it a single label
   is always visible, so a CTA with no short variant keeps its only text on
   every screen instead of vanishing on phones.
   ------------------------------------------------------------------------ */

.bsb-label--alt {
	display: none;
}

.bsb-btn--has-alt .bsb-label--base,
.bsb-text--has-alt .bsb-label--base {
	display: var(--bsb-label-base, inline);
}

.bsb-btn--has-alt .bsb-label--alt,
.bsb-text--has-alt .bsb-label--alt {
	display: var(--bsb-label-alt, none);
}

/* ---------------------------------------------------------------------------
   Close button
   ------------------------------------------------------------------------ */

.bsb-close {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	flex: 0 0 auto;
	width: 32px;
	height: 32px;
	padding: 0;
	border: 0;
	border-radius: 50%;
	background: transparent;
	color: #ffffff;
	cursor: pointer;
	opacity: 0.7;
	transition: opacity 0.2s ease, background-color 0.2s ease;
}

.bsb-close:hover,
.bsb-close:focus-visible {
	opacity: 1;
	background-color: rgba(255, 255, 255, 0.14);
}

/* ---------------------------------------------------------------------------
   Page spacing (only when "Reserve space at the end of the page" is on)
   ------------------------------------------------------------------------ */

body.bsb-has-space-bottom {
	padding-bottom: var(--bsb-space-bottom, 0px);
}

body.bsb-has-space-top {
	padding-top: var(--bsb-space-top, 0px);
}

/* ---------------------------------------------------------------------------
   Editor-only affordances
   ------------------------------------------------------------------------ */

.bsb-placeholder {
	width: 100%;
	padding: 14px 18px;
	border: 1px dashed rgba(255, 255, 255, 0.5);
	border-radius: 8px;
	color: #ffffff;
	font-size: 13px;
	line-height: 1.5;
	text-align: center;
}

@media (prefers-reduced-motion: reduce) {
	.bsb-bar,
	.bsb-bar--out,
	.bsb-btn {
		transition-duration: 1ms;
	}

	.bsb-btn:hover,
	.bsb-btn:focus-visible {
		transform: none;
	}
}
