/**
 * 3D & AR Manager — hotspot markers and tooltips.
 *
 * Loaded alongside frontend.css and inherits its custom properties, so it works
 * unchanged in the modal viewer, the inline [wc_3d_viewer] shortcode and either
 * side of the dual-model switch.
 *
 * How <model-viewer> lays these out, because the rules below depend on it:
 *
 *   shadow root
 *     └─ div.annotation-wrapper      position:absolute, transform-positioned on
 *         └─ slot[name="hotspot-N"]  the projected 3D point, pointer-events:none
 *             └─ our <button>        ← normal flow inside the wrapper
 *
 * The wrapper is what moves. Our button therefore only has to be dot-sized and
 * `position: relative`, so the tooltip can hang off it as an absolute child.
 */

/* --------------------------------------------------------------- variables */

.wc3dar-stage,
.wc3dar-inline {
	--wc3dar-hotspot-size: 14px;
	--wc3dar-hotspot-hit: 26px;
	--wc3dar-hotspot-dot: #ffffff;
	--wc3dar-hotspot-ring: rgba(15, 23, 42, 0.55);
	--wc3dar-hotspot-pulse: rgba(255, 255, 255, 0.55);
	--wc3dar-hotspot-card-bg: rgba(17, 20, 26, 0.82);
	--wc3dar-hotspot-card-border: rgba(255, 255, 255, 0.14);
	--wc3dar-hotspot-card-text: #f4f6f9;
	--wc3dar-hotspot-card-muted: #c4ccd8;
	--wc3dar-hotspot-card-width: 230px;
	--wc3dar-hotspot-gap: 14px;
}

/*
 * Switch off <model-viewer>'s own occluded-hotspot dimming (default 0.25) and
 * take the fade over ourselves, below. Leaving both on produces a two-stage
 * fade that reads as a flicker while the model turns.
 *
 * 1, not 0. The property dims the shadow-DOM wrapper, which no author rule on
 * our slotted child can undo — so 0 would also erase the dimension overlay's
 * invisible corner probes and its measurement badges, which use the same
 * hotspot machinery but need their own visibility rules. Neutralising the
 * built-in fade and driving every state from `[data-visible]` keeps all three
 * kinds of hotspot under one mechanism we control.
 */
.wc3dar-viewer {
	--min-hotspot-opacity: 1;
}

/* ------------------------------------------------------------ marker (dot) */

.wc3dar-hotspot {
	/*
	 * `all: unset` because this button is slotted into someone else's page and
	 * every theme in existence styles `button`. Everything the element needs is
	 * re-declared immediately below — including pointer-events, which `unset`
	 * would otherwise resolve to the wrapper's inherited `none`.
	 */
	all: unset;

	position: relative;
	box-sizing: border-box;
	display: grid;
	place-items: center;
	width: var(--wc3dar-hotspot-hit);
	height: var(--wc3dar-hotspot-hit);
	pointer-events: auto;
	cursor: help;
	-webkit-tap-highlight-color: transparent;
	transition: opacity 0.22s ease, transform 0.22s ease;
}

.wc3dar-hotspot__dot {
	position: relative;
	display: block;
	box-sizing: border-box;
	width: var(--wc3dar-hotspot-size);
	height: var(--wc3dar-hotspot-size);
	border-radius: 50%;
	background: var(--wc3dar-hotspot-dot);
	box-shadow:
		0 0 0 1.5px var(--wc3dar-hotspot-ring),
		0 2px 6px rgba(15, 23, 42, 0.35);
	transition: transform 0.18s ease, box-shadow 0.18s ease;
}

/* The pulse is a pseudo-element so it never affects hit-testing or layout. */
.wc3dar-hotspot__dot::after {
	content: "";
	position: absolute;
	inset: 0;
	border-radius: 50%;
	background: var(--wc3dar-hotspot-pulse);
	opacity: 0.7;
	animation: wc3dar-hotspot-pulse 2.4s cubic-bezier(0.4, 0, 0.2, 1) infinite;
}

@keyframes wc3dar-hotspot-pulse {
	0% {
		transform: scale(1);
		opacity: 0.55;
	}

	70% {
		transform: scale(2.4);
		opacity: 0;
	}

	100% {
		transform: scale(2.4);
		opacity: 0;
	}
}

.wc3dar-hotspot:hover .wc3dar-hotspot__dot,
.wc3dar-hotspot:focus-visible .wc3dar-hotspot__dot,
.wc3dar-hotspot.is-open .wc3dar-hotspot__dot {
	transform: scale(1.25);
	box-shadow:
		0 0 0 2px var(--wc3dar-hotspot-ring),
		0 4px 12px rgba(15, 23, 42, 0.45);
}

/* Stop the pulse while the tooltip is up — two moving things is one too many. */
.wc3dar-hotspot:hover .wc3dar-hotspot__dot::after,
.wc3dar-hotspot:focus-visible .wc3dar-hotspot__dot::after,
.wc3dar-hotspot.is-open .wc3dar-hotspot__dot::after {
	animation-play-state: paused;
	opacity: 0;
}

.wc3dar-hotspot:focus-visible {
	outline: none;
}

.wc3dar-hotspot:focus-visible .wc3dar-hotspot__dot {
	box-shadow:
		0 0 0 2px var(--wc3dar-hotspot-ring),
		0 0 0 4px var(--wc3dar-accent, #2b6cb0);
}

/* ------------------------------------------------------------- occlusion */

/*
 * `data-visible` is added and removed by <model-viewer> because the markup asks
 * for it with data-visibility-attribute="visible". Absent = the point is facing
 * away from the camera.
 *
 * Both properties matter: opacity alone would leave an invisible 26px button
 * sitting in front of the model, swallowing the drag that starts on it.
 */
.wc3dar-hotspot:not([data-visible]) {
	opacity: 0;
	transform: scale(0.6);
	pointer-events: none;
}

.wc3dar-hotspot:not([data-visible]) .wc3dar-hotspot__card {
	opacity: 0;
	visibility: hidden;
	pointer-events: none;
}

/*
 * Mid-switch on a dual-model product.
 *
 * frontend.js adds `.is-switching` the moment the new `src` is assigned and
 * hotspots.js swaps the slotted set in the same tick, but the outgoing model is
 * still on the canvas until the replacement streams in. Without this the
 * arriving markers would spend that window pinned to the wrong mesh.
 */
.wc3dar-stage.is-switching .wc3dar-hotspot {
	opacity: 0;
	pointer-events: none;
	transition: opacity 0.12s ease;
}

/* ---------------------------------------------------------------- tooltip */

.wc3dar-hotspot__card {
	position: absolute;
	left: 50%;
	bottom: calc(100% + var(--wc3dar-hotspot-gap) - 8px);
	z-index: 2;

	display: flex;
	flex-direction: column;
	gap: 4px;
	box-sizing: border-box;
	width: max-content;
	max-width: var(--wc3dar-hotspot-card-width);
	padding: 10px 12px;

	border-radius: 12px;
	border: 1px solid var(--wc3dar-hotspot-card-border);
	background: var(--wc3dar-hotspot-card-bg);
	-webkit-backdrop-filter: blur(12px) saturate(140%);
	backdrop-filter: blur(12px) saturate(140%);
	box-shadow:
		0 12px 34px rgba(0, 0, 0, 0.34),
		0 1px 0 rgba(255, 255, 255, 0.06) inset;

	color: var(--wc3dar-hotspot-card-text);
	font-family: var(--wc3dar-font, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif);
	text-align: left;
	white-space: normal;
	overflow-wrap: anywhere;

	/*
	 * Closed state. `pointer-events: none` is the important one: the card is a
	 * child of the marker, so without it the invisible card would intercept the
	 * drag the shopper meant for the model.
	 */
	opacity: 0;
	visibility: hidden;
	pointer-events: none;
	transform: translate(-50%, 6px) scale(0.97);
	transform-origin: bottom center;
	transition:
		opacity 0.18s ease,
		transform 0.18s ease,
		visibility 0s linear 0.18s;
}

.wc3dar-hotspot[data-visible]:hover .wc3dar-hotspot__card,
.wc3dar-hotspot[data-visible]:focus-visible .wc3dar-hotspot__card,
.wc3dar-hotspot[data-visible]:focus-within .wc3dar-hotspot__card,
.wc3dar-hotspot[data-visible].is-open .wc3dar-hotspot__card {
	opacity: 1;
	visibility: visible;
	pointer-events: auto;
	transform: translate(-50%, 0) scale(1);
	transition-delay: 0s;
}

.wc3dar-hotspot__title {
	font-size: 13px;
	font-weight: 600;
	line-height: 1.35;
	letter-spacing: 0.01em;
}

.wc3dar-hotspot__text {
	font-size: 12px;
	font-weight: 400;
	line-height: 1.5;
	color: var(--wc3dar-hotspot-card-muted);

	/* Honour the line breaks the shop owner typed into the textarea. */
	white-space: pre-line;
}

/* Little pointer joining the card to the dot. */
.wc3dar-hotspot__card::after {
	content: "";
	position: absolute;
	top: 100%;
	left: 50%;
	width: 8px;
	height: 8px;
	margin: -4px 0 0 -4px;
	transform: rotate(45deg);
	border-right: 1px solid var(--wc3dar-hotspot-card-border);
	border-bottom: 1px solid var(--wc3dar-hotspot-card-border);
	background: var(--wc3dar-hotspot-card-bg);
}

/* ------------------------------------------------- edge-aware placement */

/*
 * Set by hotspots.js when the card would otherwise be clipped by the stage.
 * Everything still works without the script — these are corrections, not the
 * mechanism.
 */
.wc3dar-hotspot.is-below .wc3dar-hotspot__card {
	bottom: auto;
	top: calc(100% + var(--wc3dar-hotspot-gap) - 8px);
	transform-origin: top center;
	transform: translate(-50%, -6px) scale(0.97);
}

.wc3dar-hotspot.is-below[data-visible]:hover .wc3dar-hotspot__card,
.wc3dar-hotspot.is-below[data-visible]:focus-visible .wc3dar-hotspot__card,
.wc3dar-hotspot.is-below[data-visible]:focus-within .wc3dar-hotspot__card,
.wc3dar-hotspot.is-below[data-visible].is-open .wc3dar-hotspot__card {
	transform: translate(-50%, 0) scale(1);
}

.wc3dar-hotspot.is-below .wc3dar-hotspot__card::after {
	top: auto;
	bottom: 100%;
	margin: 0 0 -4px -4px;
	border: 0;
	border-left: 1px solid var(--wc3dar-hotspot-card-border);
	border-top: 1px solid var(--wc3dar-hotspot-card-border);
}

.wc3dar-hotspot.is-start .wc3dar-hotspot__card {
	left: 0;
	transform: translate(calc(-1 * var(--wc3dar-hotspot-hit) / 2 + 4px), 6px) scale(0.97);
}

.wc3dar-hotspot.is-start[data-visible]:hover .wc3dar-hotspot__card,
.wc3dar-hotspot.is-start[data-visible]:focus-visible .wc3dar-hotspot__card,
.wc3dar-hotspot.is-start[data-visible]:focus-within .wc3dar-hotspot__card,
.wc3dar-hotspot.is-start[data-visible].is-open .wc3dar-hotspot__card {
	transform: translate(calc(-1 * var(--wc3dar-hotspot-hit) / 2 + 4px), 0) scale(1);
}

.wc3dar-hotspot.is-start .wc3dar-hotspot__card::after {
	left: calc(var(--wc3dar-hotspot-hit) / 2);
}

.wc3dar-hotspot.is-end .wc3dar-hotspot__card {
	left: auto;
	right: 0;
	transform: translate(calc(var(--wc3dar-hotspot-hit) / 2 - 4px), 6px) scale(0.97);
}

.wc3dar-hotspot.is-end[data-visible]:hover .wc3dar-hotspot__card,
.wc3dar-hotspot.is-end[data-visible]:focus-visible .wc3dar-hotspot__card,
.wc3dar-hotspot.is-end[data-visible]:focus-within .wc3dar-hotspot__card,
.wc3dar-hotspot.is-end[data-visible].is-open .wc3dar-hotspot__card {
	transform: translate(calc(var(--wc3dar-hotspot-hit) / 2 - 4px), 0) scale(1);
}

.wc3dar-hotspot.is-end .wc3dar-hotspot__card::after {
	left: auto;
	right: calc(var(--wc3dar-hotspot-hit) / 2 - 8px);
}

/* ------------------------------------------------------------ fallbacks */

/* No backdrop-filter (Firefox <103, older Safari): use an opaque panel. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
	.wc3dar-hotspot__card,
	.wc3dar-hotspot__card::after {
		background: rgba(17, 20, 26, 0.96);
	}
}

@media (prefers-contrast: more) {
	.wc3dar-hotspot__card,
	.wc3dar-hotspot__card::after {
		background: #0b0e13;
		border-color: rgba(255, 255, 255, 0.5);
	}

	.wc3dar-hotspot__text {
		color: #e9edf3;
	}
}

@media (prefers-reduced-motion: reduce) {
	.wc3dar-hotspot,
	.wc3dar-hotspot__dot,
	.wc3dar-hotspot__card {
		transition-duration: 0.01ms !important;
	}

	.wc3dar-hotspot__dot::after {
		animation: none;
		opacity: 0;
	}
}

/* Touch and small screens: bigger target, roomier card. */
@media (hover: none) {
	.wc3dar-stage,
	.wc3dar-inline {
		--wc3dar-hotspot-hit: 34px;
		--wc3dar-hotspot-size: 16px;
	}
}

@media (max-width: 480px) {
	.wc3dar-stage,
	.wc3dar-inline {
		--wc3dar-hotspot-card-width: 190px;
	}

	.wc3dar-hotspot__text {
		font-size: 11.5px;
	}
}

/*
 * The dual-model switch sits bottom-centre of the stage. Nudge a tooltip that
 * would land underneath it so the two never overlap.
 */
.wc3dar-stage:has([data-wc3dar-switch]) .wc3dar-hotspot.is-below .wc3dar-hotspot__card {
	max-width: calc(var(--wc3dar-hotspot-card-width) - 20px);
}

/* Printing a page with a WebGL canvas gives a blank box; hide the furniture. */
@media print {
	.wc3dar-hotspot {
		display: none !important;
	}
}
