/* =========================================================
   EXPLORE CANVAS
   One markup, two presentations. Without .is-canvas this is a
   readable nested list — that is the no-JS, mobile and screen
   reader experience, and it must stay usable on its own.
   With .is-canvas the same elements become an absolutely
   positioned plane under a single transform.
   ========================================================= */

.bv-canvas__stage {
	position: relative;
}

.bv-canvas__list,
.bv-canvas__children {
	list-style: none;
	margin: 0;
	padding: 0;
}

/* ---------- List presentation (the default) ---------- */

.bv-canvas__children {
	padding-left: 1.5rem;
	border-left: 1px solid var(--color-border-subtle);
	margin-left: 0.75rem;
}

.bv-canvas__node {
	margin: 0.5rem 0;
}

.bv-canvas__tile {
	display: flex;
	align-items: center;
	gap: 0.75rem;
	text-decoration: none;
	color: var(--color-text);
	border-radius: var(--radius-md);
	padding: 0.25rem;
}

.bv-canvas__tile:focus-visible {
	outline: 2px solid var(--color-accent);
	outline-offset: 3px;
}

.bv-canvas__img,
.bv-canvas__fallback {
	width: 48px;
	height: 48px;
	flex: none;
	border-radius: var(--radius-sm);
	background: var(--color-bg-alt);
}

.bv-canvas__img {
	object-fit: cover;
}

.bv-canvas__fallback {
	display: grid;
	place-items: center;
	color: var(--color-text-muted);
	font-size: 0.6rem;
	line-height: 1.1;
	text-align: center;
	overflow: hidden;
	padding: 2px;
}

.bv-canvas__node--brand > .bv-canvas__tile {
	font-weight: 600;
	font-size: 1.05rem;
}

/* ---------- Canvas presentation ---------- */

.bv-canvas__stage.is-canvas {
	height: 78vh;
	overflow: hidden;
	touch-action: none;
	cursor: grab;
	background: var(--color-bg-alt);
	border-radius: var(--radius-lg);
	border: 1px solid var(--color-border-subtle);
}

.bv-canvas__stage.is-canvas:focus-visible {
	outline: 2px solid var(--color-accent);
	outline-offset: 2px;
}

.bv-canvas__stage.is-canvas.is-dragging {
	cursor: grabbing;
}

/* The single transformed layer. Everything inside is positioned in canvas
   units; only this element is ever transformed, so pan and zoom stay one
   composited operation regardless of tile count. */
.is-canvas .bv-canvas__list {
	position: absolute;
	top: 0;
	left: 0;
	width: 100%;
	height: 100%;
	transform-origin: 0 0;
	will-change: transform;
}

.is-canvas .bv-canvas__children {
	padding: 0;
	margin: 0;
	border: 0;
}

.is-canvas .bv-canvas__node {
	position: absolute;
	margin: 0;
	/* left/top are set inline by the JS from data-x/data-y. */
}

.is-canvas .bv-canvas__tile {
	flex-direction: column;
	gap: 0.35rem;
	padding: 0;
	/* Centre the tile on its coordinate rather than hanging it below-right. */
	transform: translate(-50%, -50%);
	width: max-content;
	align-items: center;
}

.is-canvas .bv-canvas__img,
.is-canvas .bv-canvas__fallback {
	width: var(--tile-size, 72px);
	height: var(--tile-size, 72px);
	font-size: 0.55rem;
	box-shadow: 0 1px 3px rgb(0 0 0 / 12%);
	transition: box-shadow var(--transition-fast), transform var(--transition-fast);
}

.is-canvas .bv-canvas__tile:hover .bv-canvas__img,
.is-canvas .bv-canvas__tile:focus-visible .bv-canvas__img {
	box-shadow: 0 4px 14px rgb(0 0 0 / 22%);
	transform: scale(1.04);
}

.is-canvas .bv-canvas__node--brand .bv-canvas__img,
.is-canvas .bv-canvas__node--brand .bv-canvas__fallback {
	border-radius: 50%;
	border: 2px solid var(--color-accent);
}

.is-canvas .bv-canvas__node--campaign .bv-canvas__img,
.is-canvas .bv-canvas__node--campaign .bv-canvas__fallback {
	border-radius: var(--radius-md);
	border-bottom: 3px solid var(--color-accent);
}

.is-canvas .bv-canvas__label {
	font-size: 0.7rem;
	color: var(--color-text-muted);
	max-width: 12ch;
	text-align: center;
	line-height: 1.2;
}

.is-canvas .bv-canvas__node--brand .bv-canvas__label {
	font-size: 0.85rem;
	color: var(--color-text);
	max-width: 16ch;
}

/* Labels are noise at distance. Brands keep theirs — they are the landmarks
   you navigate by. Campaigns and assets reveal theirs as you zoom in; the JS
   sets .is-zoom-mid / .is-zoom-detail on the stage. */
.is-canvas .bv-canvas__node--campaign .bv-canvas__label,
.is-canvas .bv-canvas__node--asset .bv-canvas__label {
	opacity: 0;
	transition: opacity var(--transition-fast);
}

.is-canvas.is-zoom-mid .bv-canvas__node--campaign .bv-canvas__label,
.is-canvas.is-zoom-detail .bv-canvas__node--campaign .bv-canvas__label,
.is-canvas.is-zoom-detail .bv-canvas__node--asset .bv-canvas__label {
	opacity: 1;
}

.is-canvas .bv-canvas__tile:hover .bv-canvas__label,
.is-canvas .bv-canvas__tile:focus-visible .bv-canvas__label {
	opacity: 1;
}

/* Connective hairlines: brand → campaign → asset. These are what make the
   plane a map rather than a scatter — they draw the structure the data model
   has always held and the site has never shown. Sixteen of them cross between
   brand regions, which is the cross-brand tagging made visible. */
.bv-canvas__links {
	position: absolute;
	top: 0;
	left: 0;
	width: 100%;
	height: 100%;
	overflow: visible;
	pointer-events: none;
}

.bv-canvas__links line {
	stroke: var(--color-border-strong);
	stroke-width: 1;
	opacity: 0.35;
}

/* ---------- Controls ---------- */

.bv-canvas__controls {
	display: flex;
	gap: 0.5rem;
	margin: 0 0 0.75rem;
}

.bv-canvas__controls button {
	min-width: 2.5rem;
	min-height: 2.5rem;
	padding: 0 0.9rem;
	border-radius: var(--radius-pill);
	border: 1px solid var(--color-border-subtle);
	background: var(--color-surface);
	color: var(--color-text);
	font: inherit;
	font-size: 0.8rem;
	cursor: pointer;
}

.bv-canvas__controls button:hover {
	border-color: var(--color-accent);
}

.bv-canvas__controls button:focus-visible {
	outline: 2px solid var(--color-accent);
	outline-offset: 2px;
}

/* ---------- Peek panel ---------- */

.bv-canvas__peek {
	border: 1px solid var(--color-border-subtle);
	border-radius: var(--radius-lg);
	padding: 1.5rem;
	max-width: 32rem;
	width: calc(100% - 2rem);
	background: var(--color-surface);
	color: var(--color-text);
}

.bv-canvas__peek::backdrop {
	background: rgb(0 0 0 / 45%);
}

.bv-canvas__peek-close {
	float: right;
	border: 0;
	background: none;
	color: var(--color-text-muted);
	font-size: 1.5rem;
	line-height: 1;
	cursor: pointer;
}

.bv-canvas__peek-close:focus-visible {
	outline: 2px solid var(--color-accent);
	outline-offset: 2px;
}

.bv-canvas__peek-img {
	display: block;
	width: 100%;
	max-height: 20rem;
	object-fit: contain;
	border-radius: var(--radius-md);
	background: var(--color-bg-alt);
	margin-bottom: 1rem;
}

.bv-canvas__peek-chip {
	display: inline-block;
	font-size: 0.7rem;
	letter-spacing: var(--track-label);
	text-transform: uppercase;
	color: var(--color-accent-strong);
	border: 1px solid var(--color-accent-border);
	border-radius: var(--radius-pill);
	padding: 0.15rem 0.6rem;
}

.bv-canvas__peek-body h2 {
	margin: 0.5rem 0 0.25rem;
}

.bv-canvas__peek-crumb {
	color: var(--color-text-muted);
	margin: 0 0 1rem;
	font-size: 0.9rem;
}

/* ---------- Touch and reduced motion ---------- */

/* A drag-canvas competes with page scroll on touch and loses. Below this
   width the list presentation is the whole feature, and the JS does not
   enhance at all — this is a safety net for anything that slips through. */
@media (max-width: 767px) {
	.bv-canvas__stage.is-canvas {
		height: auto;
		overflow: visible;
		touch-action: auto;
		cursor: auto;
		border: 0;
		background: none;
	}

	.is-canvas .bv-canvas__list,
	.is-canvas .bv-canvas__node {
		position: static;
		width: auto;
		height: auto;
		transform: none;
	}

	.is-canvas .bv-canvas__tile {
		flex-direction: row;
		transform: none;
		align-items: center;
	}

	.is-canvas .bv-canvas__img,
	.is-canvas .bv-canvas__fallback {
		width: 48px;
		height: 48px;
	}

	.is-canvas .bv-canvas__label {
		opacity: 1;
		max-width: none;
		text-align: left;
	}

	.is-canvas .bv-canvas__children {
		padding-left: 1.5rem;
		border-left: 1px solid var(--color-border-subtle);
		margin-left: 0.75rem;
	}

	.bv-canvas__links,
	.bv-canvas__controls {
		display: none;
	}
}

@media (prefers-reduced-motion: reduce) {
	.is-canvas .bv-canvas__list,
	.is-canvas .bv-canvas__img,
	.is-canvas .bv-canvas__label {
		transition: none !important;
	}
}
