/* ==========================================================================
   AI Voice Agent — Realtime Voice Widget Styles
   Floating launcher + centered glass card with a live audio-reactive
   ribbon wave, transcript, source links, and a single mic control.
   ========================================================================== */

:root {
	/* Brand tokens — matched to this site's Elementor Kit palette
	   (near-black primary, white foreground, "Now"/"Nunito Sans" fonts,
	   pill/20px radius language) rather than a generic widget theme. */
	--aiva-primary: #1e1e1e;
	--aiva-accent: #e2e2e2;
	/* Separate from --aiva-accent on purpose: the WebGL aura shader
	   (realtime-voice-widget.js _initAura) reads this at full strength as
	   its paint color, whereas --aiva-accent is only ever used diluted via
	   color-mix() elsewhere in this file. Reusing --aiva-accent there
	   washed out to a solid white circle instead of a colored glow — see
	   the comment in _initAura() for the full explanation. Set to this
	   site's actual Elementor Kit "White" system color (#FFFFFF) rather
	   than an arbitrary brand-agnostic cyan default — this site's real
	   palette is intentionally monochrome (White/Black/Gray system colors,
	   no colored accent anywhere in the Kit), so the aura now reads as a
	   soft white/silver glow consistent with that design instead of an
	   unrelated color. Override this token (not --aiva-accent) to recolor
	   the aura. */
	--aiva-aura-color: #ffffff;
	--aiva-error: #e5484d;
	--aiva-success: #22c55e;
	--aiva-radius: 20px;
	--aiva-launcher-size: 64px;
	--aiva-font-display: "Now", -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
	--aiva-font-body: "Nunito Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
}

.aiva-widget,
.aiva-widget * {
	box-sizing: border-box;
}

.aiva-widget {
	font-family: var(--aiva-font-body);
	line-height: 1.4;
	z-index: 999999;
	/* Default here (not just inside the max-width:600px query below) so
	   it's always defined — the short-viewport/landscape query further
	   down is a HEIGHT query and needs this variable regardless of width.
	   window.visualViewport (initViewportHeightVar in
	   realtime-voice-widget.js) overwrites this with the real visible
	   height wherever supported; this 100vh default is only ever the
	   value in browsers without visualViewport, exactly like before. */
	--aiva-vvh: 100vh;
}

.aiva-sr-only {
	position: absolute;
	width: 1px;
	height: 1px;
	padding: 0;
	margin: -1px;
	overflow: hidden;
	clip: rect(0, 0, 0, 0);
	white-space: nowrap;
	border: 0;
}

/* ==========================================================================
   Positioning
   ========================================================================== */

.aiva-mode-floating {
	position: fixed;
	right: 24px;
	bottom: 24px;
}

.aiva-mode-inline,
.aiva-mode-preview {
	position: relative;
	display: block;
	width: 100%;
}

.aiva-mode-inline .aiva-panel,
.aiva-mode-preview .aiva-panel {
	position: relative;
	display: flex;
	opacity: 1;
	visibility: visible;
	transform: none;
	pointer-events: auto;
	width: 100%;
	height: 560px;
	max-height: none;
	inset: auto;
}

.aiva-mode-inline .aiva-launcher,
.aiva-mode-preview .aiva-launcher {
	display: none;
}

/* ==========================================================================
   Launcher
   ========================================================================== */

.aiva-launcher {
	position: relative;
	width: var(--aiva-launcher-size);
	height: var(--aiva-launcher-size);
	border: none;
	background: transparent;
	display: flex;
	align-items: center;
	justify-content: center;
	cursor: pointer;
	transition: opacity 0.2s ease, visibility 0.2s;
	flex-shrink: 0;
	z-index: 10;
}

/* Base launcher styles when not using agent UI (fallback) */
.aiva-launcher:not(.aiva-launcher-agent) {
	border-radius: 50%;
	background: var(--aiva-primary);
	color: #fff;
	box-shadow: 0 12px 32px rgba(20, 20, 40, 0.25), 0 2px 8px rgba(20, 20, 40, 0.12);
	transition: transform 0.2s ease, box-shadow 0.2s ease, opacity 0.2s ease, visibility 0.2s;
}
.aiva-launcher:not(.aiva-launcher-agent):hover {
	transform: translateY(-2px) scale(1.03);
}

/* Agent UI specific styles — sized off the same --aiva-launcher-size token
   the fallback circular launcher uses, so the mobile breakpoint's 10%
   reduction (see Responsive section) applies here too instead of leaving
   the agent launcher fixed at desktop size on small screens. */
.aiva-launcher-agent {
	width: calc(var(--aiva-launcher-size) * 1);
	height: calc(var(--aiva-launcher-size) * 1);
}

/* Glow ring — same dark-glass + accent-glow language as .aiva-panel, so the
   closed launcher reads as the same surface as the card it opens rather
   than an unrelated chatbot-widget bubble. */
.aiva-agent-blob {
	display: none; /* Hide the black circle background */
}

.aiva-agent-avatar-wrapper {
	position: absolute;
	bottom: 0;
	left: 50%;
	transform: translateX(-50%);
	width: 100%;
	height: 100%;
	border-radius: 50%; /* Make it perfectly rounded */
	border: 1px solid #ffffff; /* Clean premium border */
	box-shadow: 0 8px 24px rgba(0, 0, 0, 0.25);
	z-index: 2;
	overflow: hidden;
	pointer-events: none;
}

.aiva-agent-avatar {
	width: 100%;
	height: 100%;
	object-fit: cover;
	object-position: center 15%; /* Keep face centered properly without translating the box */
	transform: scale(1.1); /* Slight zoom to ensure it perfectly fills the circle */
	transform-origin: center center;
	transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
	pointer-events: none;
}

/* Hover effects */
.aiva-launcher-agent:hover .aiva-agent-blob {
	transform: translateX(-50%) scale(1.05);
	box-shadow:
		0 0 0 1px rgba(255, 255, 255, 0.2) inset,
		0 12px 36px rgba(0, 0, 0, 0.4),
		0 0 44px color-mix(in srgb, var(--aiva-accent) 45%, transparent);
	animation-play-state: paused;
}

.aiva-launcher-agent:hover .aiva-agent-avatar-wrapper {
	/* Just a slight scale on hover for interactivity */
	transform: translateX(-50%) scale(1.05);
	transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
}

/* Message Bubble CTA */
.aiva-agent-message {
	position: absolute;
	right: 100%;
	bottom: 75px; /* Shifted even higher up as requested */
	margin-right: 4px; /* Shifted further right (closer to the avatar) */
	background: #ffffff;
	color: #111111;
	border: 1px solid rgba(0, 0, 0, 0.06);
	padding: 10px 18px;
	border-radius: 20px 20px 4px 20px; /* Classic chat bubble pointing bottom-right */
	box-shadow: 0 12px 32px rgba(0, 0, 0, 0.12), 0 4px 12px rgba(0, 0, 0, 0.05);
	font-family: inherit; /* Inherit website's font */
	font-size: 15px;
	font-weight: 500;
	white-space: nowrap;
	z-index: 3;
	opacity: 0;
	transform-origin: bottom right;
	transform: translateX(10px) translateY(5px) scale(0.95);
	pointer-events: auto; /* Make it clickable */
	cursor: pointer;
	transition: opacity 0.4s ease, transform 0.4s cubic-bezier(0.34, 1.56, 0.64, 1), box-shadow 0.2s ease;
}

.aiva-agent-message:hover {
	box-shadow: 0 16px 40px rgba(0, 0, 0, 0.18), 0 6px 16px rgba(0, 0, 0, 0.08);
	transform: translateX(0) translateY(0) scale(1.02);
}

.aiva-agent-message.is-visible {
	opacity: 1;
	transform: translateY(50%) translateX(0) scale(1);
}

.aiva-agent-message-text {
	display: inline-block;
}

/* Text slot-machine animations */
.aiva-slide-up-out {
	animation: aiva-text-slide-out 0.4s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
}

.aiva-slide-up-in {
	animation: aiva-text-slide-in 0.4s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
}

@keyframes aiva-text-slide-out {
	0% { transform: translateY(0); opacity: 1; }
	100% { transform: translateY(-15px); opacity: 0; }
}

@keyframes aiva-text-slide-in {
	0% { transform: translateY(15px); opacity: 0; }
	100% { transform: translateY(0); opacity: 1; }
}

.aiva-agent-message-text.is-fading-out {
	opacity: 0;
}

/* Focus state */
.aiva-launcher:focus-visible {
	outline: 3px solid var(--aiva-accent);
	outline-offset: 3px;
	border-radius: 12px;
}

.aiva-launcher-agent:focus-visible {
	border-radius: 50%;
}

/* Animations */
@keyframes aiva-float-blob {
	0%, 100% {
		transform: translateX(-50%) translateY(0);
	}
	50% {
		transform: translateX(-50%) translateY(-6px);
	}
}

@keyframes aiva-float-avatar {
	0%, 100% {
		transform: translateX(-50%) translateY(0);
	}
	50% {
		transform: translateX(-50%) translateY(-8px);
	}
}

/* Idle "breathing" glow on the closed launcher — echoes the aura's own
   listening/speaking pulse so the closed button previews that the panel
   behind it is alive, not a static icon. */
@keyframes aiva-glow-pulse {
	0%, 100% {
		box-shadow:
			0 0 0 1px rgba(255, 255, 255, 0.14) inset,
			0 8px 28px rgba(0, 0, 0, 0.35),
			0 0 32px color-mix(in srgb, var(--aiva-accent) 35%, transparent);
	}
	50% {
		box-shadow:
			0 0 0 1px rgba(255, 255, 255, 0.14) inset,
			0 8px 28px rgba(0, 0, 0, 0.35),
			0 0 44px color-mix(in srgb, var(--aiva-accent) 55%, transparent);
	}
}

/* Note: the launcher itself is hidden whenever a session is actually
   connecting/live (see .aiva-mode-floating.aiva-panel-open .aiva-launcher
   below — start() adds aiva-panel-open before connect() ever changes
   state), so the glow only ever needs an idle treatment above; there is no
   visible "connecting" or "speaking" launcher state to style. */
.aiva-widget[data-aiva-state="error"] .aiva-agent-blob {
	animation-play-state: paused;
	box-shadow:
		0 0 0 1px rgba(255, 255, 255, 0.18) inset,
		0 8px 28px rgba(0, 0, 0, 0.35),
		0 0 40px color-mix(in srgb, var(--aiva-error) 45%, transparent);
}

.aiva-mode-floating.aiva-panel-open .aiva-launcher {
	opacity: 0;
	visibility: hidden;
	pointer-events: none;
}

.aiva-backdrop {
	display: none; /* Hide on desktop */
	position: fixed;
	inset: 0;
	background: rgba(2, 4, 12, 0.6);
	backdrop-filter: blur(6px);
	-webkit-backdrop-filter: blur(6px);
	opacity: 0;
	visibility: hidden;
	transition: opacity 0.28s ease, visibility 0.28s;
	pointer-events: none;
}

.aiva-widget.aiva-panel-open .aiva-backdrop {
	opacity: 1;
	visibility: visible;
	pointer-events: auto;
}

/* ==========================================================================
   Panel — centered glass card
   ========================================================================== */

.aiva-panel {
	position: fixed;
	inset: auto;
	bottom: 24px;
	right: 24px;
	margin: 0;
	width: 400px;
	height: calc(100vh - 48px);
	/* dvh (dynamic viewport height) tracks the actual visible viewport,
	   shrinking when a mobile on-screen keyboard opens instead of staying
	   pinned to the pre-keyboard 100vh — this is what stops the panel from
	   visibly resizing/jumping under the visitor's message as they type.
	   Falls back to the vh line above in browsers without dvh support. */
	height: calc(100dvh - 48px);
	max-width: 94vw;
	max-height: 680px;
	background:
		radial-gradient(ellipse 90% 60% at 50% 100%, color-mix(in srgb, var(--aiva-accent) 14%, transparent) 0%, transparent 60%),
		linear-gradient(180deg, color-mix(in srgb, #ffffff 12%, transparent) 0%, color-mix(in srgb, #ffffff 3%, transparent) 100%),
		color-mix(in srgb, var(--aiva-primary) 62%, transparent);
	backdrop-filter: blur(28px) saturate(150%);
	-webkit-backdrop-filter: blur(28px) saturate(150%);
	color: #f4f6fb;
	border-radius: var(--aiva-radius);
	border: 1px solid rgba(255, 255, 255, 0.16);
	box-shadow:
		0 8px 32px rgba(0, 0, 0, 0.35),
		inset 0 1px 0 rgba(255, 255, 255, 0.12),
		0 0 100px color-mix(in srgb, var(--aiva-accent) 16%, transparent);
	display: flex;
	flex-direction: column;
	overflow: hidden;
	opacity: 0;
	visibility: hidden;
	transform: translateX(100%) scale(0.96); /* slide from right */
	transition: opacity 0.35s ease, transform 0.4s cubic-bezier(0.34, 1.56, 0.64, 1), visibility 0.35s;
	pointer-events: none;
}

/* Frosted-glass fallback for browsers without backdrop-filter support —
   raise the panel's own opacity so it stays legible without the blur. */
@supports not (backdrop-filter: blur(1px)) {
	.aiva-panel {
		background:
			radial-gradient(ellipse 90% 60% at 50% 100%, color-mix(in srgb, var(--aiva-accent) 16%, transparent) 0%, transparent 60%),
			radial-gradient(ellipse 120% 70% at 50% 0%, #232323 0%, #121212 55%, var(--aiva-primary) 100%);
	}
}

.aiva-widget.aiva-panel-open .aiva-panel {
	opacity: 1;
	visibility: visible;
	transform: translateX(0) scale(1);
	pointer-events: auto;
}

.aiva-panel-dots {
	position: absolute;
	inset: 0;
	background-image: radial-gradient(rgba(255, 255, 255, 0.14) 1px, transparent 1px);
	background-size: 16px 16px;
	-webkit-mask-image: radial-gradient(ellipse 90% 70% at 50% 100%, #000 0%, transparent 75%);
	mask-image: radial-gradient(ellipse 90% 70% at 50% 100%, #000 0%, transparent 75%);
	pointer-events: none;
	z-index: 0;
}

/* ==========================================================================
   Header
   ========================================================================== */

.aiva-panel-header {
	display: flex;
	align-items: center;
	justify-content: flex-end;
	padding: 18px 18px 0;
	flex-shrink: 0;
	position: relative;
	z-index: 2;
}

/* Explicit background/color (with !important) on this and .aiva-send-btn:
   theme/page-builder/cache-generated CSS on the surrounding site (e.g.
   Elementor's own generic button styles, or a critical-CSS optimizer)
   can otherwise leak in and override these to a default white button with
   an invisible white-on-white icon. Pinning the two properties that were
   actually getting clobbered is enough — no need for !important elsewhere
   in this file where no such conflict exists. */
.aiva-icon-btn {
	width: 36px;
	height: 36px;
	border-radius: 50% !important;
	border: none !important;
	background: rgba(255, 255, 255, 0.08) !important;
	color: #f4f6fb !important;
	align-items: center;
	justify-content: center;
	cursor: pointer;
	transition: background 0.15s ease;
}

.aiva-icon-btn:not([hidden]) {
	display: flex;
}

.aiva-icon-btn svg {
	stroke: currentColor !important;
	fill: none !important;
	flex-shrink: 0;
}

.aiva-icon-btn:hover {
	background: rgba(255, 255, 255, 0.16) !important;
}

.aiva-icon-btn:focus-visible {
	outline: 2px solid #fff;
	outline-offset: 2px;
}

/* ==========================================================================
   Body: greeting, transcript, wave, sources
   ========================================================================== */

.aiva-panel-body {
	--aiva-body-inset: 28px;
	flex: 1;
	overflow-y: auto;
	/* .aiva-aura-canvas intentionally renders at 150% of .aiva-aura-stage
	   (see realtime-voice-widget.js _onAuraResize) so the glow can bleed
	   past the stage's own edges — on narrow mobile viewports that 150%
	   canvas is wider than the available panel width, which pushed this
	   flex column (and the page, in inline/preview mode) into horizontal
	   scroll. Clipping X here keeps the bleed effect intact while
	   preventing it from ever widening this container. */
	overflow-x: hidden;
	padding: 8px var(--aiva-body-inset) 0;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: space-evenly;
	gap: 16px;
	min-height: 0;
	text-align: center;
	position: relative;
	z-index: 1;
}

.aiva-greeting {
	max-width: 480px;
	/* Base state for the connecting -> connected reveal. While connecting the
	   greeting is collapsed + faded (see the [data-aiva-state="connecting"]
	   rule further down); on connect these transition back to their natural
	   values, so the aura appears to settle and the title rises in beneath it
	   with no reflow jump. transition-delay staggers it after the aura. */
	opacity: 1;
	transform: translateY(0);
	max-height: 40vh;
	transition: opacity 0.45s ease, transform 0.45s cubic-bezier(0.22, 1, 0.36, 1), max-height 0.45s ease;
	transition-delay: 0.18s;
	will-change: opacity, transform;
}

.aiva-greeting-eyebrow {
	margin: 0 0 6px;
	font-size: 13px;
	font-weight: 500;
	color: rgba(244, 246, 251, 0.55);
}

.aiva-greeting-title {
	margin: 0;
	font-family: var(--aiva-font-display);
	font-size: clamp(20px, 4vw, 30px);
	font-weight: 700;
	line-height: 1.25;
	color: #f4f6fb;
	letter-spacing: -0.01em;
}

/* Transcript — collapsed entirely (via the native `hidden` attribute) until
   the first message arrives; JS reveals it on first append (see req: chat
   only shown when needed). */
.aiva-transcript {
	width: 100%;
	max-width: 480px;
	flex-direction: column;
	gap: 8px;
	overflow-y: auto;
	max-height: 26vh;
}

/* Thin, theme-matched scrollbar for the two scrollable chat surfaces
   (.aiva-panel-body in voice mode, .aiva-transcript in chat mode) — covers
   every current desktop engine on both Windows and macOS:
     - Firefox: scrollbar-width/scrollbar-color (its only styling API).
     - Chrome/Edge/Opera/other Chromium, plus Safari: ::-webkit-scrollbar*.
   macOS Safari/Chrome with "Show scroll bars: When scrolling" already
   overlay a thin auto-hiding bar by OS default; these rules only take over
   the (much more common) always-visible case — Windows Chromium/Firefox,
   and macOS set to "Always show scrollbars". */
.aiva-panel-body,
.aiva-transcript {
	scrollbar-width: thin;
	/* Very subtle: a faint accent-tinted thumb on a transparent track. Kept
	   deliberately low-opacity so the bar barely registers at a glance and
	   blends into the panel; it firms up a little on hover. */
	scrollbar-color: color-mix(in srgb, var(--aiva-accent) 22%, transparent) transparent;
}

/* Ultra-slim ~2px bar. The thumb is inset via a transparent border so the
   visible pill reads even thinner and softer than the track width. */
.aiva-panel-body::-webkit-scrollbar,
.aiva-transcript::-webkit-scrollbar {
	width: 4px;
	height: 4px;
}

.aiva-panel-body::-webkit-scrollbar-track,
.aiva-transcript::-webkit-scrollbar-track {
	background: transparent;
}

.aiva-panel-body::-webkit-scrollbar-thumb,
.aiva-transcript::-webkit-scrollbar-thumb {
	/* ~2px visible pill: a 4px track minus a 1px transparent border each side.
	   Low-opacity accent tint so it's barely noticeable and blends naturally. */
	background-color: color-mix(in srgb, var(--aiva-accent) 22%, transparent);
	border-radius: 999px;
	border: 1px solid transparent;
	background-clip: padding-box;
	transition: background-color 0.2s ease;
}

.aiva-panel-body:hover::-webkit-scrollbar-thumb,
.aiva-transcript:hover::-webkit-scrollbar-thumb {
	background-color: color-mix(in srgb, var(--aiva-accent) 40%, transparent);
}

.aiva-panel-body::-webkit-scrollbar-corner,
.aiva-transcript::-webkit-scrollbar-corner {
	background: transparent;
}

/* Chat mode — once the visitor has typed a message (see
   text-widget-fallback.js), this is a real text conversation, not a voice
   call: drop the voice orbit/aura entirely and let the transcript behave
   like a normal chat list instead of a small scroll box squeezed under it. */
.aiva-widget[data-aiva-chat-mode="true"] .aiva-aura-stage {
	display: none;
}

.aiva-widget[data-aiva-chat-mode="true"] .aiva-greeting {
	display: none;
}

.aiva-widget[data-aiva-chat-mode="true"] .aiva-panel-body {
	justify-content: flex-start;
	padding-top: 16px;
}

.aiva-widget[data-aiva-chat-mode="true"] .aiva-transcript {
	max-width: none;
	max-height: none;
	flex: 1;
	width: 100%;
}

/* Voice-chat mode — set on the widget root (data-aiva-voice-chat) once the
   first message appears in a *voice* call (distinct from data-aiva-chat-mode,
   which is the typed-text path). As the spoken conversation grows the small
   capped transcript box feels cramped under the orb + greeting, so here we:
     - hide the title/subtitle,
     - drop the aura out of the flex flow and pin it as a dimmed BACKGROUND
       layer behind the chat (it keeps animating, so the glow stays visible),
     - let the transcript fill the whole panel and scroll.
   Guarded with :not([data-aiva-chat-mode="true"]) so the typed-text layout,
   which removes the aura entirely, always wins when both could apply. */
.aiva-widget[data-aiva-voice-chat="true"]:not([data-aiva-chat-mode="true"]) .aiva-greeting {
	display: none;
}

.aiva-widget[data-aiva-voice-chat="true"]:not([data-aiva-chat-mode="true"]) .aiva-panel-body {
	justify-content: flex-start;
	padding-top: 16px;
	/* Drop the position:relative it carries by default so it stops acting as
	   the containing block for the absolutely-positioned aura below — the aura
	   then anchors to the non-scrolling .aiva-panel and stays put while only
	   this column's content scrolls. Its own stacking (z-index:1) still works
	   via the flex/isolation context, keeping the chat above the aura. */
	position: static;
}

.aiva-widget[data-aiva-voice-chat="true"]:not([data-aiva-chat-mode="true"]) .aiva-aura-stage {
	/* Absolutely positioned against .aiva-panel (which is position:fixed, so it
	   is the containing block now that .aiva-panel-body is static) and centered.
	   Because it's anchored to the panel, not the scrolling body, it stays
	   fixed and centered no matter how far the chat scrolls. Small, compact,
	   1:1 so it reads as a tight blob rather than a stretched ellipse. */
	position: absolute;
	/* NB: do NOT add `inset: auto` here — as shorthand it resets top/left back
	   to auto and the aura snaps to the top-left corner instead of centering.
	   The base .aiva-aura-stage rule sets no inset, so top/left alone suffice. */
	top: 50%;
	left: 50%;
	transform: translate(-50%, -50%);
	right: auto;
	bottom: auto;
	margin: 0;
	max-width: none;
	width: 42%;
	height: auto;
	aspect-ratio: 1 / 1;
	z-index: 0;
	opacity: 0.5;
	pointer-events: none;
}

/* Drop the round clip in the background aura so it reads as the natural
   waveform blob rather than a circle. */
.aiva-widget[data-aiva-voice-chat="true"]:not([data-aiva-chat-mode="true"]) .aiva-aura-canvas {
	border-radius: 0;
}

.aiva-widget[data-aiva-voice-chat="true"]:not([data-aiva-chat-mode="true"]) .aiva-transcript {
	position: relative;
	z-index: 1;
	max-width: none;
	max-height: none;
	flex: 1;
	width: 100%;
}

.aiva-transcript:not([hidden]) {
	display: flex;
}

.aiva-message {
	max-width: 88%;
	padding: 9px 14px;
	border-radius: 16px;
	font-size: 13.5px;
	word-wrap: break-word;
	text-align: left;
	animation: aiva-msg-in 0.18s ease;
}

@keyframes aiva-msg-in {
	from { opacity: 0; transform: translateY(4px); }
	to { opacity: 1; transform: translateY(0); }
}

.aiva-message-user {
	align-self: flex-end;
	background: var(--aiva-primary);
	color: #fff;
	border-bottom-right-radius: 4px;
}

.aiva-message-agent {
	align-self: flex-start;
	background: rgba(255, 255, 255, 0.08);
	color: #f4f6fb;
	border-bottom-left-radius: 4px;
}

/* An assistant bubble that ended up with no text (e.g. a placeholder created
   only to anchor an action button, when the reply was audio-only with no
   transcript) must not show as an empty box. Once it's no longer streaming and
   has no content, collapse it. The :empty check ignores whitespace-only text
   nodes, so a bubble with a stray space still hides via the JS cleanup that
   strips the streaming class. */
.aiva-message-agent:not(.aiva-message-streaming):empty {
	display: none;
}

/* A user bubble reserved at speech-start but not yet filled with the
   transcribed text. Kept in the DOM to hold the visitor's turn *above* the
   assistant's reply (which streams in first), but visually collapsed so no
   empty box flashes while the transcription is still in flight. */
.aiva-message-user.aiva-message-pending {
	display: none;
}

.aiva-message-streaming::after {
	content: '';
	display: inline-block;
	width: 6px;
	height: 6px;
	margin-left: 4px;
	border-radius: 50%;
	background: currentColor;
	opacity: 0.6;
	animation: aiva-blink 1s ease-in-out infinite;
	vertical-align: middle;
}

@keyframes aiva-blink {
	0%, 100% { opacity: 0.2; }
	50% { opacity: 0.9; }
}

/* Center animated visual — the widget's main focal point. A self-contained
   canvas-drawn "aura" (soft glowing blobs) replaces the old ribbon wave;
   AIVoiceAgentRealtime draws into the canvas per animation frame based on
   the current state + live microphone/assistant audio amplitude. */
.aiva-aura-stage {
	position: relative;
	width: 100%;
	/* Scales with available viewport height, not just a fixed 240px, so it
	   shrinks automatically in any short-viewport situation — landscape
	   phones (see the max-height media query below) and a mobile keyboard
	   eating vertical space (--aiva-vvh, set from window.visualViewport in
	   realtime-voice-widget.js) — instead of staying full-size and forcing
	   the rest of the panel to compress or scroll around it. 18vh keeps it
	   proportional to whatever room is actually left; the two clamp bounds
	   are the original 240px ceiling and a floor small enough to stay
	   legible/tappable even in a very short landscape strip. */
	max-width: clamp(120px, 18vh, 240px);
	aspect-ratio: 1 / 1;
	flex: 0 0 auto;
	display: flex;
	align-items: center;
	justify-content: center;
	isolation: isolate;
	/* Eases the size change between the enlarged connecting aura and the normal
	   size once the title/controls reveal on connect. */
	transition: max-width 0.45s cubic-bezier(0.22, 1, 0.36, 1);
}

.aiva-aura-stage::before {
	content: "";
	position: absolute;
	inset: -30%;
	background: radial-gradient(ellipse 60% 60% at 50% 50%, color-mix(in srgb, var(--aiva-accent) 26%, transparent) 0%, transparent 70%);
	filter: blur(32px);
	opacity: 0.6;
	pointer-events: none;
	animation: aiva-glow-pulse 3.6s ease-in-out infinite;
}

@keyframes aiva-glow-pulse {
	0%, 100% { opacity: 0.45; transform: scale(0.96); }
	50% { opacity: 0.8; transform: scale(1.05); }
}

.aiva-widget[data-aiva-state="speaking"] .aiva-aura-stage::before,
.aiva-widget[data-aiva-state="listening"] .aiva-aura-stage::before {
	animation-duration: 2.2s;
}

.aiva-aura-canvas {
	position: absolute;
	top: 50%;
	left: 50%;
	transform: translate(-50%, -50%);
	width: 150%;
	height: 150%;
	display: block;
	border-radius: 50%;
	opacity: 1;
	transition: opacity 0.25s ease;
	/* Forces its own compositor layer, separate from .aiva-panel's
	   backdrop-filter raster pass — without this, several Android
	   Chrome/WebView + GPU driver combinations flatten this WebGL canvas's
	   alpha channel and paint it as an opaque white circle instead of the
	   transparent glow (see the matching comment in _initAura() in
	   realtime-voice-widget.js, which is the other half of this fix). */
	will-change: transform;
	transform-style: preserve-3d;
	isolation: isolate;
}

.aiva-widget[data-aiva-state="disconnected"] .aiva-aura-stage,
.aiva-widget[data-aiva-state="offline"] .aiva-aura-stage {
	filter: grayscale(0.85) brightness(0.6);
}

/* Pure-CSS fallback for devices with no usable WebGL (context creation
   failed, or the shader wouldn't compile even at mediump — see
   _initAura()/_compileShaders() in realtime-voice-widget.js, both of which
   set data-aiva-no-webgl="true" on the widget root instead of leaving the
   canvas blank). A centered mic icon with pulsing ripple rings — same
   visual language (accent-colored glow, centered focal point) as the
   WebGL aura, with zero GPU dependency. Hidden by default; only the
   [data-aiva-no-webgl] branch below reveals it, and it hides the (in this
   case inert) canvas in the same rule so the two never show together. */
.aiva-aura-fallback {
	display: none;
	position: absolute;
	top: 50%;
	left: 50%;
	transform: translate(-50%, -50%);
	width: 72px;
	height: 72px;
	align-items: center;
	justify-content: center;
}

.aiva-widget[data-aiva-no-webgl="true"] .aiva-aura-canvas {
	display: none;
}

.aiva-widget[data-aiva-no-webgl="true"] .aiva-aura-fallback {
	display: flex;
}

.aiva-aura-fallback-icon {
	position: relative;
	z-index: 1;
	display: flex;
	align-items: center;
	justify-content: center;
	width: 72px;
	height: 72px;
	border-radius: 50%;
	color: var(--aiva-aura-color, #1fd5f9);
	background: color-mix(in srgb, var(--aiva-aura-color, #1fd5f9) 16%, transparent);
	box-shadow: 0 0 0 1px color-mix(in srgb, var(--aiva-aura-color, #1fd5f9) 35%, transparent) inset;
}

.aiva-aura-fallback-ripple {
	position: absolute;
	top: 50%;
	left: 50%;
	width: 72px;
	height: 72px;
	border-radius: 50%;
	border: 1.5px solid color-mix(in srgb, var(--aiva-aura-color, #1fd5f9) 55%, transparent);
	transform: translate(-50%, -50%) scale(1);
	opacity: 0;
	animation: aiva-fallback-ripple 2.4s ease-out infinite;
}

.aiva-aura-fallback-ripple:nth-child(2) {
	animation-delay: 1.2s;
}

@keyframes aiva-fallback-ripple {
	0% { transform: translate(-50%, -50%) scale(0.9); opacity: 0.6; }
	100% { transform: translate(-50%, -50%) scale(2.1); opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
	.aiva-aura-fallback-ripple {
		animation: none;
		opacity: 0.35;
	}
}

/* "Connecting…" text — shown only while the widget is fetching its
   ephemeral client secret from our own backend (POST
   {restUrl}/realtime/client-secret). The widget flips data-aiva-state to
   "listening" as soon as that call resolves (see connect() in
   realtime-voice-widget.js) — the RTCPeerConnection/SDP exchange with
   OpenAI and ICE/DTLS/SCTP negotiation that follow happen in the
   background against an already-live UI, not behind this label. */
/* "Connecting…" label. Pinned to the FOOT of the widget while connecting (aura
   animating in the center, this label at the bottom). It's a direct child of
   .aiva-panel-body (position: relative), so bottom anchors to the panel body's
   lower edge — and since the input bar is collapsed during connecting, that's
   effectively the bottom of the widget. */
.aiva-connecting-status {
	position: absolute;
	left: 50%;
	bottom: 22px;
	transform: translateX(-50%);
	font-size: 14px;
	font-weight: 500;
	color: rgba(244, 246, 251, 0.75);
	letter-spacing: 0.01em;
	opacity: 0;
	pointer-events: none;
	transition: opacity 0.25s ease;
}

@keyframes aiva-connecting-pulse {
	0%, 100% { opacity: 0.5; }
	50% { opacity: 1; }
}

/* ---- Connecting screen: only the aura (calm) + the bottom label ----
   The aura canvas stays visible while connecting but dimmed and calm; it then
   ramps to full opacity/intensity on connect (the canvas already has an
   opacity transition). The title + input bar are collapsed and faded so the
   aura is the sole, centered focus. */
/* Make the aura a bit larger while connecting — it's the sole focus of the
   screen (title/controls collapsed), so give it more presence. Scales up from
   the base clamp; the transition on .aiva-aura-stage lets it ease back down as
   the title/controls reveal on connect. */
.aiva-widget[data-aiva-state="connecting"] .aiva-aura-stage {
	max-width: clamp(160px, 26vh, 320px);
}

.aiva-widget[data-aiva-state="connecting"] .aiva-aura-canvas {
	opacity: 0.55;
}

.aiva-widget[data-aiva-state="connecting"] .aiva-connecting-status {
	opacity: 1;
	pointer-events: auto;
	animation: aiva-connecting-pulse 1.4s ease-in-out infinite;
}

/* Calmer, slower glow while connecting; the base 3.6s pulse already applies,
   this just dims it a touch so "connect" feels like it brightens. */
.aiva-widget[data-aiva-state="connecting"] .aiva-aura-stage::before {
	opacity: 0.35;
}

/* Hide the title/eyebrow and the whole input bar during connecting (and the
   brief disconnected state right before it), collapsed out of layout so the
   aura is truly centered in the panel body. They animate back in (opacity +
   slide up) once the state leaves "connecting" — see the transitions on
   .aiva-greeting / .aiva-panel-controls. Including "disconnected" here means
   the panel's very first painted frame on open already has the input hidden,
   so it can never flash into view before "connecting" takes over. */
.aiva-widget[data-aiva-state="connecting"] .aiva-greeting,
.aiva-widget[data-aiva-state="connecting"] .aiva-panel-controls,
.aiva-widget[data-aiva-state="disconnected"]:not([data-aiva-chat-mode="true"]) .aiva-greeting,
.aiva-widget[data-aiva-state="disconnected"]:not([data-aiva-chat-mode="true"]) .aiva-panel-controls {
	opacity: 0;
	transform: translateY(14px);
	pointer-events: none;
	/* No stagger on the way OUT — collapse immediately so the connecting
	   screen never briefly shows the old content. The stagger delay only
	   applies to the reveal (the base-rule delay), so override to 0 here. */
	transition-delay: 0s;
}

/* Kill the reveal transition entirely while the widget is CLOSED or in the
   pre-connect states, so opening the panel never animates the input bar in/out
   (the flicker). The reveal animation only runs once the widget is open AND has
   actually connected (listening/speaking/thinking), handled by the base
   .aiva-greeting / .aiva-panel-controls transitions. */
.aiva-widget:not(.aiva-panel-open) .aiva-greeting,
.aiva-widget:not(.aiva-panel-open) .aiva-panel-controls,
.aiva-widget[data-aiva-state="disconnected"]:not([data-aiva-chat-mode="true"]) .aiva-greeting,
.aiva-widget[data-aiva-state="disconnected"]:not([data-aiva-chat-mode="true"]) .aiva-panel-controls,
.aiva-widget[data-aiva-state="connecting"] .aiva-greeting,
.aiva-widget[data-aiva-state="connecting"] .aiva-panel-controls {
	transition: none;
}

/* Keep the greeting/controls from occupying vertical space while collapsed so
   the aura sits dead-center. max-height + margins clamp their box; the
   opacity/transform above handle the visible fade/slide. */
.aiva-widget[data-aiva-state="connecting"] .aiva-greeting,
.aiva-widget[data-aiva-state="disconnected"]:not([data-aiva-chat-mode="true"]) .aiva-greeting {
	max-height: 0;
	margin: 0;
	overflow: hidden;
}

/* While connecting, the greeting/controls are collapsed to nothing, so re-
   center the aura in the body even on short viewports (where the base body
   rule switches to flex-start to reclaim space for a full conversation). */
.aiva-widget[data-aiva-state="connecting"] .aiva-panel-body,
.aiva-widget[data-aiva-state="disconnected"]:not([data-aiva-chat-mode="true"]) .aiva-panel-body {
	justify-content: center;
}

.aiva-widget[data-aiva-state="connecting"] .aiva-panel-controls,
.aiva-widget[data-aiva-state="disconnected"]:not([data-aiva-chat-mode="true"]) .aiva-panel-controls {
	max-height: 0;
	padding-top: 0;
	padding-bottom: 0;
	overflow: hidden;
}



.aiva-widget[data-aiva-state="error"] .aiva-aura-stage {
	animation: aiva-aura-shake 420ms ease;
}

@keyframes aiva-aura-shake {
	10%, 90% { transform: translateX(-1px); }
	20%, 80% { transform: translateX(2px); }
	30%, 50%, 70% { transform: translateX(-4px); }
	40%, 60% { transform: translateX(4px); }
}

@media (prefers-reduced-motion: reduce) {
	.aiva-aura-stage,
	.aiva-aura-stage::before,
	.aiva-aura-stage::after,
	.aiva-connecting-status {
		animation: none !important;
	}

	/* Reveal the title/controls instantly rather than sliding/fading them in —
	   the collapse-vs-shown state still changes, it just doesn't animate. */
	.aiva-greeting,
	.aiva-panel-controls {
		transition: none !important;
	}
}

/* Microphone-permission-denied notice — unlike .aiva-connecting-status this
   carries an actual explanatory sentence, so it reads as a small banner
   rather than a centered pulsing label; JS unhides it and sets its text
   only when getUserMedia rejects with NotAllowedError (see
   _handleConnectError in realtime-voice-widget.js). */
.aiva-mic-denied-status {
	margin: 0 0 12px;
	padding: 10px 14px;
	border-radius: calc(var(--aiva-radius) * 0.5);
	background: color-mix(in srgb, var(--aiva-error) 16%, transparent);
	border: 1px solid color-mix(in srgb, var(--aiva-error) 32%, transparent);
	color: #f4f6fb;
	font-size: 13px;
	line-height: 1.4;
	text-align: center;
}

.aiva-widget[data-aiva-state="mic-denied"] .aiva-aura-stage {
	animation: aiva-aura-shake 420ms ease;
}

/* Per-message action buttons (Call / Email / Get Directions / Book Now) —
   rendered directly under the specific chat bubble they belong to, never a
   shared panel repeated across every message. */
.aiva-message-actions {
	display: flex;
	flex-wrap: wrap;
	gap: 6px;
	margin-top: 8px;
	max-width: 88%;
	align-self: flex-start;
}

.aiva-action-btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 6px;
	/* Explicit box-model reset: the widget renders directly in the page (no
	   Shadow DOM isolation), so a theme's or page builder's generic
	   button/.button rules (larger padding, min-height, line-height) can
	   otherwise leak in and inflate this beyond the intended compact pill
	   size — pin every relevant property here instead of relying on cascade
	   order to keep it. */
	box-sizing: border-box;
	margin: 0;
	padding: 5px 12px;
	min-height: 0;
	line-height: 1.3;
	border-radius: 999px;
	background: rgba(255, 255, 255, 0.1);
	border: 1px solid rgba(255, 255, 255, 0.16);
	color: #f4f6fb;
	font-family: inherit;
	font-size: 12.5px;
	font-weight: 600;
	text-decoration: none;
	white-space: nowrap;
	cursor: pointer;
	transition: all 0.3s ease;
}

/* Matches this site's Elementor CTA buttons (e.g. "Talk to our Expert"),
   which have no custom hover state configured anywhere in the Elementor Kit
   or per-widget settings — only Elementor core's own generic default
   (color:#fff on hover/focus/visited, animated by the button's own
   transition). Reproduced literally and self-contained here so the plugin
   never depends on Elementor/theme CSS actually being present. */
.aiva-action-btn:hover,
.aiva-action-btn:focus-visible,
.aiva-action-btn:visited {
	color: #fff;
}

.aiva-action-btn:focus-visible {
	outline: 2px solid var(--aiva-accent);
	outline-offset: 2px;
}

.aiva-action-btn svg {
	width: 14px;
	height: 14px;
	flex-shrink: 0;
}

/* Per-message source accordion — collapsed by default (just the toggle
   line); clicking reveals the preview card directly under that one message
   only, instead of a single shared box repeated below every reply. */
.aiva-message-source {
	max-width: 88%;
	align-self: flex-start;
	margin-top: 6px;
}

/* Same pill shape/sizing as .aiva-action-btn (Call/Email/Directions/Book
   Now) so "View source" reads as one consistent family of buttons rather
   than a separate underlined text link. Deliberately does NOT use
   transform/translateY for its hover/active feedback (unlike
   .aiva-action-btn, which is a static link) — this is a real <button> the
   visitor repeatedly clicks to expand/collapse, so any position shift on
   press is far more noticeable here; background/border/box-shadow changes
   only, so the button never moves. */
.aiva-source-toggle {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 6px;
	box-sizing: border-box;
	margin: 0;
	padding: 5px 12px;
	min-height: 0;
	border: 1px solid rgba(255, 255, 255, 0.16);
	border-radius: 999px;
	background: rgba(255, 255, 255, 0.1);
	color: #f4f6fb;
	font-family: inherit;
	font-size: 12.5px;
	font-weight: 600;
	line-height: 1.3;
	cursor: pointer;
	text-decoration: none;
	white-space: nowrap;
	transition: background 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease;
}

.aiva-source-toggle:hover {
	background: rgba(255, 255, 255, 0.16);
	border-color: rgba(255, 255, 255, 0.28);
}

.aiva-source-toggle:active {
	background: rgba(255, 255, 255, 0.2);
	border-color: rgba(255, 255, 255, 0.32);
	box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.2);
}

.aiva-source-toggle:focus-visible {
	outline: 2px solid var(--aiva-accent);
	outline-offset: 2px;
}

/* Active/expanded state — the toggle itself (not just the chevron icon)
   reflects that the source card is open, so "View source" reads clearly as
   pressed/active rather than only relying on the rotated arrow. */
.aiva-message-source.aiva-source-expanded .aiva-source-toggle {
	background: rgba(255, 255, 255, 0.16);
	border-color: rgba(255, 255, 255, 0.28);
}

.aiva-source-toggle-icon {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	line-height: 1;
	transition: transform 0.15s ease;
}

.aiva-message-source.aiva-source-expanded .aiva-source-toggle-icon {
	transform: rotate(180deg);
}

.aiva-source-toggle-label {
	display: inline-block;
	line-height: 1.3;
}

.aiva-message-source .aiva-source-preview {
	margin-top: 8px;
	display: none;
}

.aiva-message-source.aiva-source-expanded .aiva-source-preview {
	display: flex;
}

/* Source preview card — the image area (when a featured image exists) is a
   large rectangle, not a small square thumbnail: 4:3 on desktop, capped in
   height so the card never dominates the whole panel; a shorter wide ratio
   on mobile where vertical space in the widget is tighter (see the
   responsive block below). */
.aiva-source-preview {
	flex-direction: column;
	width: 100%;
	max-width: 320px;
	min-height: 84px;
	border-radius: 16px;
	overflow: hidden;
	background: rgba(255, 255, 255, 0.06);
	border: 1px solid rgba(255, 255, 255, 0.12);
	/* Explicit color reset: this is an <a> wrapping plain <span>s with no
	   color of their own (e.g. .aiva-source-preview-label below), so
	   without this they inherit the browser's default link-blue instead of
	   the widget's dark-theme text color — set here once so every child
	   text element inherits the correct neutral color instead of blue. */
	color: #f4f6fb;
	text-align: left;
	text-decoration: none;
	transition: background 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease;
}

.aiva-source-preview:hover,
.aiva-source-preview:focus-visible {
	background: rgba(255, 255, 255, 0.1);
	border-color: rgba(255, 255, 255, 0.2);
	box-shadow: 0 6px 16px rgba(0, 0, 0, 0.18);
}

.aiva-source-preview:focus-visible {
	outline: 2px solid var(--aiva-accent);
	outline-offset: 2px;
}

.aiva-source-preview:active {
	background: rgba(255, 255, 255, 0.14);
	border-color: rgba(255, 255, 255, 0.24);
	box-shadow: 0 2px 6px rgba(0, 0, 0, 0.16);
}

.aiva-source-preview-media {
	width: 100%;
	aspect-ratio: 4 / 3;
	max-height: 220px;
	background: rgba(255, 255, 255, 0.04);
	overflow: hidden;
}

.aiva-source-preview-img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
}

.aiva-source-preview-body {
	display: flex;
	flex-direction: column;
	gap: 4px;
	padding: 14px 18px 16px;
}

.aiva-source-preview-label {
	color: #f4f6fb;
	font-size: 11px;
	text-transform: uppercase;
	letter-spacing: 0.04em;
	opacity: 0.5;
	font-weight: 600;
}

.aiva-source-preview-title {
	font-family: var(--aiva-font-display);
	font-size: 15px;
	font-weight: 700;
	color: #f4f6fb;
	line-height: 1.3;
}

/* Neutral light grey, matching the rest of the dark-theme text hierarchy —
   intentionally not var(--aiva-accent) (a link-style accent color) so this
   never reads as a blue "link" color against the dark card. */
.aiva-source-preview-url {
	font-size: 12px;
	color: #f4f6fb;
	opacity: 0.6;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

/* ==========================================================================
   Controls
   ========================================================================== */

.aiva-panel-controls {
	flex-shrink: 0;
	padding: 18px 22px 30px;
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 12px;
	position: relative;
	z-index: 1;
	/* Reveal target for the connecting -> connected transition (mirrors
	   .aiva-greeting). Revealed slightly after the title for a gentle stagger. */
	opacity: 1;
	transform: translateY(0);
	max-height: 40vh;
	transition: opacity 0.45s ease, transform 0.45s cubic-bezier(0.22, 1, 0.36, 1), max-height 0.45s ease, padding 0.45s ease;
	transition-delay: 0.26s;
	will-change: opacity, transform;
}

/* Text fallback */
.aiva-text-fallback {
	width: 100%;
	max-width: 420px;
	display: flex;
	align-items: center;
	gap: 8px;
	background: rgba(255, 255, 255, 0.08);
	border: 1px solid rgba(255, 255, 255, 0.14);
	border-radius: 999px;
	padding: 6px 8px 6px 18px;
}

.aiva-text-input {
	flex: 1;
	min-width: 0;
	min-height: 40px;
	border: none;
	background: transparent;
	color: #fff;
	font-size: 14px;
	font-family: inherit;
}

.aiva-text-input::placeholder {
	color: rgba(255, 255, 255, 0.55);
}

.aiva-text-input:focus {
	outline: none;
}

/* Send / voice button — solid black circle, white icon (matches the design
   reference). It shows a waveform glyph while the input is empty ("voice"
   mode) and swaps to a forward arrow once the visitor has typed something
   ("send" mode); the mode is driven by data-aiva-send-mode, toggled in
   realtime-voice-widget.js. Kept explicitly black/white with !important for
   the same theme-leak reason documented on .aiva-icon-btn above. */
.aiva-send-btn {
	width: 40px;
	height: 40px;
	background: #111 !important;
	color: #fff !important;
	flex-shrink: 0;
}

.aiva-send-btn:hover {
	background: #000 !important;
}

.aiva-send-icon {
	display: none;
	align-items: center;
	justify-content: center;
	line-height: 0;
}

.aiva-send-btn[data-aiva-send-mode="voice"] .aiva-send-icon-voice,
.aiva-send-btn[data-aiva-send-mode="arrow"] .aiva-send-icon-arrow {
	display: inline-flex;
}

/* Mic mute/unmute button — white circle with a dark outline mic by default
   (unmuted). When muted (data-aiva-muted="true") it turns solid red with a
   white slashed-mic glyph. Sits between the input and the send button.
   Default = unmuted. Hidden entirely in chat/text mode (see the
   data-aiva-chat-mode rule below). */
.aiva-mic-btn {
	width: 40px;
	height: 40px;
	background: #fff !important;
	color: #1a1a1a !important;
	flex-shrink: 0;
}

.aiva-mic-btn:hover {
	background: #f0f0f0 !important;
}

.aiva-mic-icon {
	display: none;
	align-items: center;
	justify-content: center;
	line-height: 0;
}

.aiva-mic-btn[data-aiva-muted="false"] .aiva-mic-icon-on,
.aiva-mic-btn[data-aiva-muted="true"] .aiva-mic-icon-off {
	display: inline-flex;
}

.aiva-mic-btn[data-aiva-muted="true"] {
	background: #e5484d !important;
	color: #fff !important;
}

.aiva-mic-btn[data-aiva-muted="true"]:hover {
	background: #d93a3f !important;
}

/* The mic mute button is only meaningful during a live voice call, so it is
   shown ONLY in the voice-active states (connecting/listening/thinking/
   speaking) and hidden everywhere else — including chat/text mode
   (data-aiva-chat-mode, set by text-widget-fallback.js the moment the visitor
   types) and the disconnected/offline/error states. Because it keys off the
   live data-aiva-state, it correctly reappears if the widget returns to a
   voice call. Hidden by default; each voice state re-shows it below. */
.aiva-mic-btn {
	display: none !important;
}

.aiva-widget[data-aiva-state="connecting"]:not([data-aiva-chat-mode="true"]) .aiva-mic-btn,
.aiva-widget[data-aiva-state="listening"]:not([data-aiva-chat-mode="true"]) .aiva-mic-btn,
.aiva-widget[data-aiva-state="thinking"]:not([data-aiva-chat-mode="true"]) .aiva-mic-btn,
.aiva-widget[data-aiva-state="speaking"]:not([data-aiva-chat-mode="true"]) .aiva-mic-btn {
	display: inline-flex !important;
}

/* ==========================================================================
   Responsive
   ========================================================================== */

@media (max-width: 600px) {
	.aiva-backdrop {
		display: block; /* Restore on mobile */
	}

	.aiva-panel {
		/* Centered modal on mobile: margin:auto only distributes slack space
		   when all four inset edges are pinned to 0 - leaving right/bottom as
		   auto (as this previously did) gives margin:auto nothing to split,
		   so the panel just sits pinned to the top-left corner instead. */
		inset: 0;
		margin: auto;
		width: min(94vw, 480px);
		height: min(80vh, 740px);
		max-width: 94vw;
		max-height: 80vh;
		transform: translateY(40px) scale(0.96); /* slide from bottom */
	}

	@supports ( height: 100dvh ) {
		/* Same dvh rationale as the desktop .aiva-panel rule above — on
		   mobile this is the rule that actually matters, since this is the
		   breakpoint active while a visitor is typing into the on-screen
		   keyboard. min()/max() don't support mixed vh/dvh cleanly across
		   engines yet, so this is gated behind @supports and repeats the
		   min() with dvh substituted rather than trying to mix units. */
		.aiva-panel {
			height: min(80dvh, 740px);
			max-height: 80dvh;
		}
	}

	/* Strongest override: --aiva-vvh (defaulted at the top of this file,
	   overwritten from window.visualViewport.height by
	   initViewportHeightVar() in realtime-voice-widget.js wherever
	   supported) is the one signal that reliably reflects the space
	   actually left after a mobile on-screen keyboard opens — dvh's
	   keyboard behavior is inconsistent enough across engines (iOS Safari
	   in particular: the layout viewport doesn't shrink on keyboard-open,
	   only the visual one does) that it isn't sufficient alone. */
	.aiva-panel {
		height: min(80vh, 740px, calc(var(--aiva-vvh) * 0.8));
		max-height: min(80vh, calc(var(--aiva-vvh) * 0.8));
	}

	.aiva-widget.aiva-panel-open .aiva-panel {
		transform: translateY(0) scale(1);
	}

	.aiva-widget {
		/* 10% smaller than the desktop 64px launcher (Task: reduce mic
		   launcher size on mobile) — overridden only inside this breakpoint
		   so desktop is untouched. */
		--aiva-launcher-size: 57.6px;
	}

	.aiva-launcher-agent {
		/* Overwrite the desktop 1.25 multiplier to shrink the massive avatar on mobile */
		width: calc(var(--aiva-launcher-size) * 1.0);
		height: calc(var(--aiva-launcher-size) * 1.0);
	}

	.aiva-agent-message {
		/* Scale down the message bubble and tuck it closer */
		padding: 10px 14px;
		font-size: 13px;
		margin-right: 0px;
		bottom: 65px;
	}

	.aiva-panel-body {
		--aiva-body-inset: 18px;
		padding-top: 0;
		gap: 14px;
	}

	.aiva-greeting-title {
		font-size: clamp(18px, 6vw, 24px);
	}

	.aiva-panel-controls {
		padding: 14px 16px 26px;
	}

	/* Wider/shorter than the desktop 4:3 crop — mobile widget height is
	   more constrained, so the image trades some vertical presence for
	   more room for the transcript/status below it. */
	.aiva-source-preview-media {
		aspect-ratio: 16 / 9;
		max-height: 160px;
	}
}

/* ==========================================================================
   Short viewport (landscape phones, and a very reduced height once a
   mobile keyboard is open) — a HEIGHT query, deliberately independent of
   the max-width: 600px query above: a landscape phone is commonly
   600-900px wide but only ~320-420px tall, so the width query alone never
   fires there and the panel was falling back to the desktop sizing (up to
   680px tall, fixed paddings/gaps) on a viewport nowhere near that tall.
   CSS-only, no JS involved — this reflows purely from the viewport
   itself, and layers on top of (doesn't replace) the --aiva-vvh keyboard
   handling above, which already shrinks .aiva-panel's outer height; this
   query additionally shrinks what's *inside* it so short viewports get a
   proportionally tightened layout instead of the same fixed-size content
   scrolling inside a shorter box.
   ========================================================================== */
@media (max-height: 500px) {
	.aiva-panel {
		/* Nearly the full short viewport, not a fixed vh/px budget sized
		   for portrait — 8px top/bottom breathing room is enough once the
		   panel is this short. */
		height: min(calc(100dvh - 16px), calc(var(--aiva-vvh, 100vh) - 16px));
		max-height: none;
	}

	.aiva-panel-header {
		padding: 10px 14px 0;
	}

	.aiva-panel-body {
		--aiva-body-inset: 16px;
		gap: 8px;
		padding-top: 4px;
		/* justify-content: space-evenly (the base rule) fights for space
		   it doesn't have once every element is already shrunk as far as
		   it usefully can go — flex-start plus the tightened gap above
		   lets the body scroll cleanly (see the shared scrollbar styling)
		   instead of stretching gaps to fill a height that isn't there. */
		justify-content: flex-start;
	}

	.aiva-greeting-eyebrow {
		margin: 0 0 2px;
	}

	.aiva-greeting-title {
		font-size: clamp(16px, 4vh, 22px);
	}

	.aiva-transcript {
		max-height: 40vh;
	}

	.aiva-panel-controls {
		padding: 8px 16px 12px;
		gap: 6px;
	}

	.aiva-text-input {
		min-height: 34px;
	}

	.aiva-send-btn,
	.aiva-icon-btn {
		width: 32px;
		height: 32px;
	}
}
