/* =========================================================
   THE SPECIMEN PLATE
   =========================================================
   The asset grid is the screen everyone uses, so it carries
   the design. Every other surface stays quiet.

   The rule that drives all of it: an asset library must never
   misrepresent an artifact. The previous card cropped every
   asset to 4:3 with background-size:cover, so a wide lockup
   lost its ends, a tall poster showed only its middle, and
   transparency was invisible. Here the artwork is contained,
   never cropped, on a neutral ground, with a checkerboard
   behind anything that can carry alpha.
   ========================================================= */

.bv-asset-grid {
	display: grid;
	/* 350px was too wide for the browser's content column beside the ~340px
	   filter rail (~710px at a 1140px viewport): two 350px tracks plus the gap
	   did not fit, so the grid collapsed to one full-width card. min(280px,100%)
	   — the same track the brand-page variant already uses — packs 2 tracks
	   there and 3+ on wider frames, while 1fr keeps the cards large. */
	grid-template-columns: repeat(auto-fill, minmax(min(280px, 100%), 1fr));
	gap: var(--space-6);
}

#brand-page .bv-asset-grid {
	display: grid;
	/* auto-fill, not a hard repeat(4): the brand page's main column now sits in
	   a contained frame (.bv-slice__inner, 1280px) minus the 300px rail — about
	   940px — where a fixed 4×280px grid (min ~1192px) overflowed rightward into
	   the sidebar. auto-fill packs as many ~280px tracks as the column has room
	   for (3 here, 4+ on wider frames); min(280px,100%) stops a lone card from
	   overflowing a column narrower than 280px on small screens. */
	grid-template-columns: repeat(auto-fill, minmax(min(280px, 100%), 1fr));
	gap: var(--space-6);
}

@media (max-width: 480px) {
	.bv-asset-grid {
		grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
		gap: var(--space-4);
	}
}

/* ----- The plate ----- */

.bv-plate {
	display: flex;
	flex-direction: column;
	background: var(--color-surface);
	border: 1px solid var(--color-rule);
	border-radius: var(--radius-md);
	text-decoration: none;
	color: inherit;
	overflow: hidden;
	transition:
		border-color var(--transition-fast),
		transform var(--transition-fast);
}

.bv-plate:hover,
.bv-plate:focus-visible {
	/* border-color: var(--color-ink); */
}

.bv-plate:focus-visible {
	outline: 2px solid var(--color-brass);
	outline-offset: 2px;
}

/* ----- The stage: neutral ground the artwork sits on ----- */

.bv-plate__stage {
	position: relative;
	display: grid;
	place-items: center;
	aspect-ratio: 4 / 3;
	padding: 0;
	border-radius: 0; /* .bv-plate clips the top corners */
	background-color: var(--bv-ground, var(--color-specimen));
	overflow: hidden; /* clips the specs strip while it is parked */
	transition: background-color var(--transition-fast);
}

/* NO CHECKERBOARD ON CARDS. It existed to show whether a logo was
   transparent, which a cover crop makes moot — and the format test behind it
   (PNG or SVG) turned out to be a poor proxy for "this is a logo": twelve of
   this library's thirty-four featured images are PNG and most are video
   stills. The checkerboard still earns its place on the single-asset stage,
   where judging transparency is the actual task. */

/* The featured image fills the tile, always. A library of photographs,
   video stills and artwork reads as a grid of pictures; letterboxing every
   one of them inside padding turned each into a small stamp floating in
   white. Contain still governs the single-asset stage, where the artifact
   is being examined rather than scanned. */
.bv-plate__art {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.bv-plate__noart {
	font-family: var(--font-mono);
	font-size: var(--font-size-xs);
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: var(--color-text-soft);
}

.bv-plate__status {
	position: absolute;
	top: var(--space-3);
	right: var(--space-3);
	padding: 2px 8px;
	font-family: var(--font-mono);
	font-size: 0.625rem;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: var(--color-surface);
	background: var(--color-ink);
	border-radius: var(--radius-pill);
}

/* ----- The caption block ----- */

.bv-plate__caption {
	display: flex;
	flex-direction: column;
	gap: var(--space-1);
	padding: var(--space-3) var(--space-4) var(--space-4);
	border-top: 1px solid var(--color-rule);
}

.bv-plate__ref {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: var(--space-2);
	font-family: var(--font-mono);
	font-size: 0.6875rem;
	letter-spacing: 0.04em;
}

.bv-plate__accession {
	color: var(--color-brass);
	font-weight: 600;
}

.bv-plate__format {
	color: var(--color-text-soft);
	text-transform: uppercase;
	letter-spacing: 0.08em;
	text-align: right;
}

.bv-plate__title {
	font-family: var(--font-sans);
	font-size: var(--font-size-md);
	font-weight: 400;
	letter-spacing: var(--track-title);
	line-height: 1.25;
	color: var(--color-text);
}

.bv-plate__specs {
	font-family: var(--font-mono);
	font-size: 0.6875rem;
	color: var(--color-text-soft);
	letter-spacing: 0.03em;
}

/* Nothing lifts, nothing glows. The plate is the one loud thing;
   its behaviour stays quiet. */
@media (prefers-reduced-motion: reduce) {
	.bv-plate {
		transition: none;
	}
}

/* =========================================================
   MEDIA CONTAINERS
   =========================================================
   Tiles and cards moved off CSS background-image onto real
   <img> elements, for srcset and lazy loading. These rules
   make the images fill their containers the way the
   backgrounds used to.

   The distinction that matters: editorial photography may be
   cropped (cover), artifacts may not (contain). A campaign
   hero photo losing its edges is fine. A logo lockup losing
   its edges is a lie about the file.
   ========================================================= */

/* NOTE: .bv-tile__media is deliberately absent here. It is already
   `position: absolute; inset: 0` in single-asset.css so it fills its tile,
   which makes it a perfectly good containing block for the image. An earlier
   version of this rule forced it to `position: relative`, and because this
   file loads later it won, collapsing the span to zero height and taking
   every tile image with it. Only give a containing block to media boxes that
   do not already have one. */
.bv-campaign-card__media,
.bv-featured__media,
.bv-slice-card__media {
	position: relative;
	overflow: hidden;
}

/* Editorial: crop is acceptable. */
.bv-tile__img,
.bv-campaign-card__img {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

/* Artifacts: never crop, and give them a neutral ground. */
.bv-featured__media,
.bv-slice-card__media {
	display: grid;
	place-items: center;
	background: var(--color-surface);
}

.bv-featured__img,
.bv-slice-card__img {
	max-width: 100%;
	max-height: 100%;
	width: auto;
	height: auto;
	object-fit: contain;
}

/* =========================================================
   GROUND SWITCHER
   =========================================================
   Answers the question a brand library actually gets asked:
   will this mark work on my background? Every brand colour
   on this site is dark, so a white-knockout logo previews as
   an empty box on the default white stage and reads as a
   broken file. Changing the ground makes it legible.
   ========================================================= */

.bv-ground {
	display: flex;
	align-items: center;
	gap: var(--space-3);
	flex-wrap: wrap;
}

.bv-ground__label {
	font-family: var(--font-mono);
	font-size: 0.6875rem;
	letter-spacing: var(--track-label);
	text-transform: uppercase;
	color: var(--color-text-soft);
}

.bv-ground__swatches {
	display: flex;
	gap: var(--space-2);
}

.bv-ground__swatch {
	width: 24px;
	height: 24px;
	padding: 0;
	border: 1px solid var(--color-rule);
	border-radius: var(--radius-pill);
	background: var(--bv-swatch, var(--color-surface));
	cursor: pointer;
	transition:
		box-shadow var(--transition-fast),
		border-color var(--transition-fast);
}

/* 'Default' reads as the checkerboard it represents. */
.bv-ground__swatch.is-auto {
	background-color: var(--color-surface);
	background-image:
		linear-gradient(45deg, var(--color-field) 25%, transparent 25%),
		linear-gradient(-45deg, var(--color-field) 25%, transparent 25%),
		linear-gradient(45deg, transparent 75%, var(--color-field) 75%),
		linear-gradient(-45deg, transparent 75%, var(--color-field) 75%);
	background-size: 10px 10px;
	background-position:
		0 0,
		0 5px,
		5px -5px,
		-5px 0;
}

.bv-ground__swatch:hover {
	border-color: var(--color-ink);
}

.bv-ground__swatch:focus-visible {
	outline: 2px solid var(--color-brass);
	outline-offset: 2px;
}

.bv-ground__swatch[aria-pressed="true"] {
	border-color: var(--color-ink);
	box-shadow:
		0 0 0 2px var(--color-surface),
		0 0 0 3px var(--color-ink);
}

.bv-ground__custom input[type="color"] {
	width: 24px;
	height: 24px;
	padding: 0;
	border: 1px solid var(--color-rule);
	border-radius: var(--radius-pill);
	background: none;
	cursor: pointer;
}

/* The single-asset poster gets the same treatment. */
.bv-slice__poster {
	background-color: var(--bv-ground, transparent);
	border-radius: var(--radius-md);
	transition: background-color var(--transition-fast);
}

@media (prefers-reduced-motion: reduce) {
	.bv-plate__stage,
	.bv-slice__poster {
		transition: none;
	}
}

/* ----- File-count signal -----
   Two of three assets in this library have nothing to download, and that
   was invisible until you clicked. The count turns a wasted click into an
   informed skip. */

.bv-plate__files {
	font-variant-numeric: tabular-nums;
	color: var(--color-text-muted);
}

.bv-plate__files.is-none {
	color: var(--color-text-soft);
}

.bv-plate.is-empty {
	border-style: dashed;
}

.bv-plate.is-empty .bv-plate__stage {
	opacity: 0.72;
}

/* Specs support the title rather than compete with it: present for
   assistive tech, revealed on hover and keyboard focus. */
/* ----- The specs strip -----
   A bar across the foot of the stage carrying accession, type, format and
   dimensions. It sits over the image rather than under the title for one
   reason: the old reveal animated max-height on the caption, so every card
   the pointer crossed grew taller and reflowed its whole grid row.

   On touch there is no hover and tapping navigates, so the strip is simply
   always visible — those four values are what someone scans a library for
   and they were unreachable on every phone and tablet. */
.bv-plate__specs {
	position: absolute;
	left: 0;
	right: 0;
	bottom: 0;
	padding: var(--space-2) var(--space-4);
	background: rgba(9, 9, 11, 0.82);
	color: var(--color-surface);
	font-family: var(--font-mono);
	font-size: 0.6875rem;
	letter-spacing: var(--track-label);
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
}

@media (hover: hover) and (pointer: fine) {
	/* Where hovering exists the strip slides up out of the stage's own
	   bottom edge, and the card lifts to meet the pointer. Both are
	   transforms, so neither costs a layout pass or moves a neighbour.
	   ("Nothing lifts, nothing glows" was the original rule here; the lift
	   is a deliberate later change, the glow is still off.) */
	.bv-plate__specs {
		transform: translateY(100%);
		transition: transform var(--transition-med);
	}

	.bv-plate:hover .bv-plate__specs,
	.bv-plate:focus-visible .bv-plate__specs,
	.bv-plate:focus-within .bv-plate__specs {
		transform: translateY(0);
	}

	.bv-plate:hover,
	.bv-plate:focus-within {
		transform: translateY(-4px);
	}
}

@media (hover: none) {
	.bv-plate__specs {
		max-height: 2.5em;
		opacity: 1;
	}
}

@media (prefers-reduced-motion: reduce) {
	.bv-plate__specs {
		transition: none;
	}
}

/* =========================================================
   ASSET PAGE — stage + action panel
   =========================================================
   The download is the reason the page exists, so it sits at
   the top of a sticky panel rather than below the prose. The
   stage gets the same treatment as the plate, because the
   page that should show an artifact best was showing it
   worse than the grid.
   ========================================================= */

.bv-stage {
	display: grid;
	/* place-items: center; */
	/* aspect-ratio: 4 / 3; */
	/* padding: var(--space-8); */
	border: 1px solid var(--color-rule);
	border-radius: var(--radius-lg);
	background-color: var(--bv-ground, var(--color-specimen));
	transition: background-color var(--transition-fast);
	overflow: hidden;
}

html:not([data-bv-ground]) .bv-stage.has-alpha,
html[data-bv-ground="auto"] .bv-stage.has-alpha {
	background-image:
		linear-gradient(45deg, var(--color-field) 25%, transparent 25%),
		linear-gradient(-45deg, var(--color-field) 25%, transparent 25%),
		linear-gradient(45deg, transparent 75%, var(--color-field) 75%),
		linear-gradient(-45deg, transparent 75%, var(--color-field) 75%);
	background-size: 22px 22px;
	background-position:
		0 0,
		0 11px,
		11px -11px,
		-11px 0;
}

.bv-stage__art {
	max-width: 100%;
	max-height: 100%;
	width: 100%;
	height: auto;
	object-fit: cover;
}

.bv-actions {
	display: flex;
	flex-direction: column;
	gap: var(--space-4);
	position: sticky;
	top: var(--space-6);
}

.bv-actions__download {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: var(--space-3);
	padding: var(--space-4) var(--space-5);
	border-radius: var(--radius-md);
	background: var(--color-ink);
	color: var(--color-surface);
	text-decoration: none;
	letter-spacing: var(--track-title);
	transition: background-color var(--transition-fast);
	flex-direction: column;
}

.bv-actions__download:hover,
.bv-actions__download:focus-visible {
	background: var(--color-brass);
	color: var(--color-surface);
}

.bv-actions__download-meta {
	font-family: var(--font-mono);
	font-size: 0.6875rem;
	letter-spacing: var(--track-label);
	opacity: 0.8;
}

.bv-actions__empty {
	margin: 0;
	padding: var(--space-4) var(--space-5);
	border: 1px dashed var(--color-border-strong);
	border-radius: var(--radius-md);
	color: var(--color-text-soft);
	font-size: var(--font-size-sm);
}

.bv-actions__formats-head,
.bv-meta-panel__title {
	margin: 0 0 var(--space-2);
	font-family: var(--font-mono);
	font-size: 0.6875rem;
	letter-spacing: var(--track-label);
	text-transform: uppercase;
	color: var(--color-text-soft);
}

.bv-formats {
	list-style: none;
	margin: 0;
	padding: 0;
	border-top: 1px solid var(--color-rule);
}

.bv-formats__row {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--space-2);
	border-bottom: 1px solid var(--color-rule);
}

/* Preview and download are separate affordances: the name previews on the
   stage, the arrow downloads. Conflating them meant you had to download a
   file to find out whether it was the one you wanted. */
.bv-formats__preview,
.bv-formats__name {
	flex: 1;
	padding: var(--space-2) 0;
	border: 0;
	background: none;
	text-align: left;
	font: inherit;
	font-size: var(--font-size-sm);
	color: var(--color-text);
	cursor: pointer;
}

.bv-formats__preview:hover,
.bv-formats__preview[aria-current="true"] {
	color: var(--color-brass);
}

.bv-formats__get {
	padding: var(--space-2);
	color: var(--color-text-muted);
	text-decoration: none;
}

.bv-formats__get:hover {
	color: var(--color-brass);
}

.bv-actions__copy {
	padding: var(--space-3) var(--space-5);
	border: 1px solid var(--color-rule);
	border-radius: var(--radius-md);
	background: var(--color-surface);
	font: inherit;
	font-size: var(--font-size-sm);
	color: var(--color-text);
	cursor: pointer;
}

.bv-actions__copy:hover {
	border-color: var(--color-ink);
}

@media (max-width: 900px) {
	.bv-actions {
		position: static;
	}
}

@media (prefers-reduced-motion: reduce) {
	.bv-stage,
	.bv-actions__download {
		transition: none;
	}
}

/* ----- What a download actually is -----
   The derived format sits beside the editor's label rather than replacing
   it: seeing "Full Color SVG · JPG" is what makes the mismatch fixable.
   Mono, quiet, right-aligned — it is evidence, not a headline. */
.bv-formats__meta {
	flex: none;
	font-family: var(--font-mono);
	font-size: 0.6875rem;
	letter-spacing: var(--track-label);
	color: var(--color-text-soft);
	white-space: nowrap;
}

/* A link that leaves the site is a different promise from a download, and
   the button says so rather than the arrow being the only clue. */
.bv-actions__download.is-offsite {
	background: var(--color-surface);
	color: var(--color-text);
	border: 1px solid var(--color-border-strong);
}
.bv-actions__download.is-offsite:hover,
.bv-actions__download.is-offsite:focus-visible {
	background: var(--color-bg-alt);
	color: var(--color-text);
	border-color: var(--color-ink);
}

/* =========================================================
   FIXED CARD METRICS
   =========================================================
   Every card is the same height, and so is every part of it. Titles wrap to
   one or two lines and campaigns come and go, so without reserved space the
   grid staggered: a two-line title pushed its neighbours' captions out of
   alignment and the eye lost the row. Each slot below is reserved whether or
   not it is filled, which is what makes a wall of cards scannable. */

.bv-plate__caption {
	display: flex;
	flex-direction: column;
	gap: var(--space-2);
	padding: var(--space-4);
	border-top: 1px solid var(--color-rule);
}

/* Two lines, always — reserved even when the title needs one. */
.bv-plate__title {
	display: -webkit-box;
	-webkit-line-clamp: 2;
	-webkit-box-orient: vertical;
	overflow: hidden;
	min-height: calc(2 * 1.25em);
	font-family: var(--font-sans);
	font-size: var(--font-size-md);
	font-weight: 400;
	line-height: 1.25;
	letter-spacing: var(--track-title);
	color: var(--color-text);
}

/* Brand and campaign, a line each. Sharing one line truncated both to
   "Scottish Rite Cha… · Grand Almon…" — two ellipses naming nothing. Sans
   rather than mono because it fits roughly a third more characters at the
   same size, which is the difference between a name and a stub. Two lines
   are reserved so a campaign-less asset keeps the card's height. */
.bv-plate__meta {
	display: flex;
	flex-direction: column;
	gap: 2px;
	min-height: calc(2 * 1.45em);
	font-size: var(--font-size-xs);
	line-height: 1.45;
}

.bv-plate__brand,
.bv-plate__campaign {
	display: block;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

.bv-plate__brand {
	color: var(--color-text-muted);
	font-weight: 600;
}
.bv-plate__campaign {
	color: var(--color-text-soft);
}
/* When the brand line is dropped (a brand's own page), the campaign is the
   only line left — promote it to the primary treatment so the card's context
   still reads clearly rather than as a faint afterthought. */
.bv-plate__campaign:only-child {
	color: var(--color-text-muted);
	font-weight: 600;
}

/* ----- File availability, on the image -----
   Two thirds of this library has nothing to download, so this is the first
   useful thing about a record. On the stage it reads at a glance and leaves
   the caption's full width to the names. */
.bv-plate__files {
	position: absolute;
	top: var(--space-3);
	left: var(--space-3);
	z-index: 1;
	padding: 3px 9px;
	border-radius: var(--radius-pill);
	background: rgba(9, 9, 11, 0.78);
	color: var(--color-surface);
	font-family: var(--font-mono);
	font-size: 0.6875rem;
	letter-spacing: var(--track-label);
}

.bv-plate__files.is-none {
	background: transparent;
	border: 1px dashed rgba(255, 255, 255, 0.55);
	color: #fff;
	text-shadow: 0 1px 2px rgba(9, 9, 11, 0.6);
}

/* Availability reads by kind, not just presence: a video is watchable and a
   story is readable, neither is a broken download. Only `is-none` — a record
   with no payload at all — is a defect worth flagging in red-adjacent terms. */
.bv-plate__files.is-watch,
.bv-plate__files.is-read,
.bv-plate__files.is-link {
	background: rgba(9, 9, 11, 0.78);
}

.bv-plate__files.is-none {
	background: transparent;
	border: 1px dashed rgba(255, 255, 255, 0.55);
	color: #fff;
	text-shadow: 0 1px 2px rgba(9, 9, 11, 0.6);
}
