/* ===========================================================================
   Round 6 · R5 — Lab Reports product selector.

   Naem: "replace the plain browser-like visual treatment with a premium
   professional selector consistent with the dark/turquoise system."

   What was actually plain was never the closed control — Round 5 already
   engraved that into the panel. It was the OPEN list. A native <select>
   renders its popup with the operating system's own menu widget: on macOS and
   on Android that arrives as a light, system-font, system-radius list dropped
   on top of a black page, and no stylesheet can reach inside it. That is the
   single thing this sheet and assets/js/round6-select.js exist to fix.

   The native control is NOT removed. lab-reports.php still renders it, it is
   still the value the page's filter script reads, and with script disabled it
   is still the whole control — everything below is scoped to `.rs-on`, a class
   that only round6-select.js can add. If the script never runs, this file
   changes nothing at all.

   Design notes that are load-bearing rather than decorative:
   - No backdrop-filter anywhere. Round 5 learned that an engine can declare
     support for it and then decline to composite it, which would leave this
     list unreadable over the page behind it. The popup is opaque.
   - Selection is a fill plus a check mark. No coloured side-stripe.
   - Availability keeps the site's telemetry language: a solid `.dot.ok` for a
     product with an uploaded file, a hollow `.ring` for one still pending. A
     pending row is never dressed to read as an available one.
     (Round 7: the owner replaced that glyph with the product's photograph —
     see the last section of this sheet. Availability is still the group a row
     sits under and the words in its second line; the glyph rules stay for a
     page that carries no `data-thumb` at all.)
   - Every option row clears 48px; on a phone they clear 52px.
   ========================================================================= */

/* --- Closed control ------------------------------------------------------ */

/* The native select stays in the box and stays the source of truth, so it is
   taken out of the paint rather than out of the DOM. It keeps its size so the
   well cannot change height between the no-JS and enhanced states, and the
   script gives it tabindex="-1" + aria-hidden so it is neither a tab stop nor a
   second announcement of the same control. */
.reports-page .reports-filter .reports-well.rs-on select {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	/* pharma-pass.css puts a 240px min-width on this element above 680px. It is
	   out of flow now, so it cannot push the layout, but zeroing both minimums
	   keeps it from ever painting outside the well it is hiding inside. */
	min-width: 0;
	min-height: 0;
	padding: 0;
	opacity: 0;
	pointer-events: none;
}

.reports-page .reports-well.rs-on .rs-button {
	position: relative;
	display: flex;
	align-items: center;
	gap: 10px;
	width: 100%;
	min-width: 0;
	min-height: 52px;
	margin: 0;
	padding: 8px 46px 8px 15px;
	border: 0;
	border-radius: var(--r-md);
	background: transparent;
	color: var(--text);
	font: 500 15px/1.35 "Inter Tight", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
	letter-spacing: 0;
	text-align: left;
	text-transform: none;
	cursor: pointer;
	-webkit-tap-highlight-color: transparent;
}

/* Long-name scanning, closed state. The NAME is the only part allowed to
   ellipsise; the record count that follows it is `flex: 0 0 auto`, so the one
   piece of information that reconciles this page's 24 products against its 28
   records can never be the piece that gets cut. */
.reports-page .reports-well.rs-on .rs-value {
	display: flex;
	align-items: baseline;
	gap: 8px;
	min-width: 0;
	flex: 1 1 auto;
}

.reports-page .reports-well.rs-on .rs-value-name {
	min-width: 0;
	overflow: hidden;
	white-space: nowrap;
	text-overflow: ellipsis;
	font-weight: 600;
}

.reports-page .reports-well.rs-on .rs-value-meta {
	flex: 0 0 auto;
	color: var(--quiet);
	font-size: 13px;
	font-weight: 500;
	font-variant-numeric: tabular-nums;
}

.reports-page .reports-well.rs-on .rs-value-meta:empty {
	display: none;
}

/* Focus is the browser's own ring, drawn by style.css on :focus-visible — one
   ring, 2px --accent-bright, never weaker than the native control's. The well
   only echoes it on its own edge, exactly as the search field's does. */
.reports-page .reports-well.rs-on:has(.rs-button:focus-visible),
.reports-page .reports-well.rs-on.rs-open {
	border-color: var(--accent);
}

.reports-page .reports-well.rs-on.rs-open {
	background: #060911;
	background: color-mix(in srgb, var(--void) 62%, var(--panel));
}

.reports-page .reports-well.rs-on.rs-open .reports-well-caret {
	transform: translateY(-50%) rotate(180deg);
}

@media (prefers-reduced-motion: no-preference) {
	.reports-page .reports-well.rs-on .reports-well-caret {
		transition: transform 180ms var(--ease);
	}
}

/* --- Popup --------------------------------------------------------------- */

/* Absolutely positioned inside the well, so it travels with the page on scroll
   and needs no repositioning loop to stay attached to its control. The well is
   `position: relative` already and nothing in this block's ancestry clips:
   .reports-filter carries an explicit note that it must never gain
   overflow:hidden, for this reason and for the focus outline. */
.reports-page .reports-well.rs-on .rs-pop {
	position: absolute;
	z-index: 60;
	top: calc(100% + 8px);
	left: 0;
	right: 0;
	display: block;
	overflow: hidden;
	border: 1px solid var(--line-strong);
	border-radius: var(--r-md);
	/* Opaque, and opaque WITHOUT color-mix first: if the gradient below is ever
	   dropped as unsupported, this list must still be a solid dark panel and not
	   a transparent hole over the page behind it. */
	background: var(--panel);
	background:
		linear-gradient(180deg, color-mix(in srgb, var(--glass) 55%, var(--panel)), var(--panel) 42%);
	box-shadow:
		0 1px 0 rgba(235, 235, 236, .05) inset,
		0 22px 54px rgba(2, 4, 8, .74),
		0 2px 10px rgba(2, 4, 8, .6);
}

.reports-page .reports-well.rs-on .rs-pop.rs-up {
	top: auto;
	bottom: calc(100% + 8px);
}

@media (prefers-reduced-motion: no-preference) {
	.reports-page .reports-well.rs-on .rs-pop:not([hidden]) {
		animation: rsPopIn 150ms var(--ease) both;
	}

	.reports-page .reports-well.rs-on .rs-pop.rs-up:not([hidden]) {
		animation-name: rsPopInUp;
	}
}

/* Transform and opacity only, ease-out, no bounce, and nothing that animates a
   layout property. */
@keyframes rsPopIn {
	from { opacity: 0; transform: translateY(-6px); }
	to   { opacity: 1; transform: translateY(0); }
}

@keyframes rsPopInUp {
	from { opacity: 0; transform: translateY(6px); }
	to   { opacity: 1; transform: translateY(0); }
}

.reports-page .reports-well.rs-on .rs-list {
	position: relative;
	display: block;
	max-height: 380px;
	overflow-y: auto;
	overscroll-behavior: contain;
	padding: 6px;
	-webkit-overflow-scrolling: touch;
}

/* --- Groups -------------------------------------------------------------- */

/* The two honest groups are the page's availability statement, so they survive
   the enhancement as real role="group" containers with the <optgroup> label as
   their accessible name. The visible heading is aria-hidden because the group
   already carries that exact string as its name — without this a screen reader
   announces "Pending upload" twice per group. It sticks to the top of the
   scroller so a reader 18 rows into 24 pending products still knows which of
   the two lists they are inside. */
.reports-page .reports-well.rs-on .rs-group + .rs-group {
	margin-top: 4px;
}

.reports-page .reports-well.rs-on .rs-group-head {
	position: sticky;
	/* The scrollport for a sticky child is the list's PADDING box, and the list
	   has no border, so top:0 is already flush with the first visible pixel —
	   a negative offset here would clip the heading's own top edge. */
	top: 0;
	z-index: 1;
	display: block;
	padding: 10px 12px 6px;
	background: var(--panel);
	background: linear-gradient(180deg, var(--panel) 72%, color-mix(in srgb, var(--panel) 0%, transparent));
	color: var(--quiet);
	font: 600 11px/1.4 "Inter Tight", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
	letter-spacing: .09em;
	text-transform: uppercase;
}

.reports-page .reports-well.rs-on .rs-group-head::after {
	content: "";
	display: block;
	margin-top: 6px;
	height: 1px;
	background: var(--line);
	background: linear-gradient(90deg, var(--line-strong), color-mix(in srgb, var(--line) 0%, transparent));
}

/* --- Options ------------------------------------------------------------- */

.reports-page .reports-well.rs-on .rs-opt {
	display: grid;
	grid-template-columns: 12px minmax(0, 1fr) 18px;
	align-items: start;
	gap: 12px;
	min-height: 48px;
	padding: 11px 12px;
	border-radius: var(--r-sm);
	cursor: pointer;
	color: var(--text);
}

.reports-page .reports-well.rs-on .rs-opt-text {
	display: block;
	min-width: 0;
}

/* Options wrap rather than truncate: a list has the width to spend and the
   record count is worth more than a tidy single line. Nothing is hidden from
   assistive tech either way — the option's accessible name is the <option>'s
   own text, verbatim. */
.reports-page .reports-well.rs-on .rs-opt-name {
	display: block;
	overflow-wrap: anywhere;
	font-size: 15px;
	font-weight: 600;
	line-height: 1.3;
}

.reports-page .reports-well.rs-on .rs-opt-meta {
	display: block;
	margin-top: 2px;
	color: var(--muted);
	font-size: 12.5px;
	font-weight: 500;
	line-height: 1.35;
	font-variant-numeric: tabular-nums;
}

.reports-page .reports-well.rs-on .rs-opt-meta:empty {
	display: none;
}

.reports-page .reports-well.rs-on .rs-mark {
	display: flex;
	align-items: center;
	justify-content: center;
	height: 21px;
}

.reports-page .reports-well.rs-on .rs-tick {
	display: flex;
	align-items: center;
	justify-content: center;
	height: 21px;
	color: var(--accent-bright);
	opacity: 0;
}

.reports-page .reports-well.rs-on .rs-tick svg {
	display: block;
	width: 16px;
	height: 16px;
}

/* Committed value first, so that when a row is BOTH the committed value and the
   keyboard-active row — the state the list opens in — the active treatment is
   the one that wins on source order at equal specificity. Getting this pair the
   wrong way round is how a combobox loses its active row on open. */
.reports-page .reports-well.rs-on .rs-opt[aria-selected="true"] {
	background: #082630;
	background: color-mix(in srgb, var(--accent) 10%, var(--panel));
}

.reports-page .reports-well.rs-on .rs-opt[aria-selected="true"] .rs-tick {
	opacity: 1;
}

.reports-page .reports-well.rs-on .rs-opt[aria-selected="true"] .rs-opt-name {
	color: var(--accent-bright);
}

/* Hover and keyboard-active are the same visual state, so a pointer user and a
   keyboard user are looking at the same row. It is a fill plus a hairline inset
   ring — an inset ring is not a side-stripe, and it survives forced-colors,
   where a background-only highlight does not. */
.reports-page .reports-well.rs-on .rs-opt:hover,
.reports-page .reports-well.rs-on .rs-opt.is-active {
	background: #092b34;
	background: color-mix(in srgb, var(--accent) 14%, var(--panel));
	box-shadow: inset 0 0 0 1px rgba(0, 212, 200, .46);
}

@media (prefers-reduced-motion: no-preference) {
	.reports-page .reports-well.rs-on .rs-opt {
		transition: background-color 120ms var(--ease), box-shadow 120ms var(--ease);
	}
}

/* --- Phone --------------------------------------------------------------- */

/* The field is already full-bleed in the single-column grid below 680px, and
   the popup inherits that width, so the list is full-width by construction and
   cannot introduce a horizontal scrollbar: it is `left: 0; right: 0` on a
   border-box parent, never a fixed width.

   It deliberately stays an anchored list rather than becoming a modal bottom
   sheet. A sheet would have to move focus off the control, hold it inside a
   scrim, and hand it back on dismissal — three chances to strand focus on
   <body> — to gain nothing this page needs. The list is the full width of the
   viewport minus the wrap gutter, its rows clear 52px, it scrolls inside itself
   with overscroll containment, and its height is measured against the real
   viewport by round6-select.js on every open, so it cannot run off-screen. What
   it must never be is the OS dropdown, and it is not. */
@media (max-width: 680px) {
	.reports-page .reports-well.rs-on .rs-button {
		font-size: 16px;
	}

	.reports-page .reports-well.rs-on .rs-value-meta {
		font-size: 13.5px;
	}

	.reports-page .reports-well.rs-on .rs-opt {
		min-height: 52px;
		padding: 13px 12px;
	}

	.reports-page .reports-well.rs-on .rs-opt-name {
		font-size: 16px;
	}

	.reports-page .reports-well.rs-on .rs-opt-meta {
		font-size: 13px;
	}
}

/* --- Forced colours ------------------------------------------------------ */

/* color-mix fills and a tinted name both disappear under a forced palette, so
   the two states that carry meaning are restated in system colours. */
@media (forced-colors: active) {
	.reports-page .reports-well.rs-on .rs-pop {
		border-color: CanvasText;
	}

	.reports-page .reports-well.rs-on .rs-opt.is-active,
	.reports-page .reports-well.rs-on .rs-opt:hover {
		background: Highlight;
		color: HighlightText;
		forced-color-adjust: none;
	}

	.reports-page .reports-well.rs-on .rs-tick {
		color: CanvasText;
	}
}

/* ===========================================================================
   Round 7 · NAEM-SPEC #2 — a product photograph where the dot was.

   "Replace the small circle next to each product name with a small product
   thumbnail (~24–32px, rounded)." 28px, in the option rows and in the closed
   control. Everything here hangs off `.rs-thumbs`, which round6-select.js adds
   only when the server sent `data-thumb`; without it this section is inert and
   the Round 6 list above is what renders.

   WHY THE CHIP IS BUILT THE WAY IT IS
   The catalogue photographs are studio shots on a near-white ground. Dropped
   raw onto a #0a0f1c panel, 23 of them read as a column of white stickers and
   out-shout the product names they sit beside. Three things seat them instead,
   none of which needs a colour the theme does not already have:
   - a hairline ring in --line-strong, the same edge every well on this page has;
   - an inset shade from --void (the ::after), so the tile's rim falls away into
     the panel instead of ending in a hard white corner;
   - the picture itself at 92% brightness, which lands a #fff ground on #ebebeb
     — the theme's own --text value — so the brightest thing in the row is no
     brighter than the type next to it.
   The ring and shade live on the WRAPPER, never on the <img>: an <img> cannot
   carry a pseudo-element, and an inset shadow on a replaced element paints
   underneath its pixels, i.e. nowhere.
   ========================================================================= */

.reports-page .reports-well.rs-on.rs-thumbs .rs-opt {
	grid-template-columns: 28px minmax(0, 1fr) 18px;
}

.reports-page .reports-well.rs-on .rs-thumb {
	position: relative;
	display: block;
	flex: 0 0 28px;
	align-self: center;
	width: 28px;
	height: 28px;
	overflow: hidden;
	border-radius: var(--r-sm);
	background: var(--void);
	box-shadow: 0 0 0 1px var(--line-strong);
	/* A chip must never become the press target's identity: the row (or the
	   button) underneath owns the pointer. */
	pointer-events: none;
}

.reports-page .reports-well.rs-on .rs-thumb img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
	filter: brightness(.92);
}

.reports-page .reports-well.rs-on .rs-thumb::after {
	content: "";
	position: absolute;
	inset: 0;
	border-radius: inherit;
	box-shadow:
		inset 0 0 0 1px rgba(4, 6, 8, .26),
		inset 0 -7px 8px -6px rgba(4, 6, 8, .34);
}

/* No photograph yet: the gallery's own "pending" language at chip size — dashed
   keyline, obsidian ground, the corner brackets from inc/round6-placeholder.php.
   Visibly NOT a picture, so an empty slot can never pass for a product shot. */
.reports-page .reports-well.rs-on .rs-thumb.is-pending {
	box-shadow: none;
	outline: 1px dashed var(--line-strong);
	outline-offset: -1px;
	/* The gallery inks these brackets in a 22% accent mix, which is right for a
	   64px tile and vanishes at 28px. --quiet is the theme's step for "present,
	   not competing", and is what keeps the empty chip a drawn thing. */
	color: var(--quiet);
}

.reports-page .reports-well.rs-on .rs-thumb.is-pending::after {
	content: none;
}

.reports-page .reports-well.rs-on .rs-thumb.is-pending svg {
	position: absolute;
	inset: 3px;
	display: block;
	width: calc(100% - 6px);
	height: calc(100% - 6px);
}

/* "All products" is not a product. Its slot is kept — so every name in the list
   shares one left edge — and left empty. */
.reports-page .reports-well.rs-on .rs-thumb.is-blank {
	background: none;
	box-shadow: none;
}

.reports-page .reports-well.rs-on .rs-thumb.is-blank::after {
	content: none;
}

/* With a 28px chip in the row, a 21px tick pinned to the first text line sits
   visibly high; both now centre on the row. */
.reports-page .reports-well.rs-on.rs-thumbs .rs-tick {
	align-self: center;
}

/* The committed row's chip picks up the accent edge, so "selected" is carried by
   the picture as well as by the fill, the tick and the name. */
.reports-page .reports-well.rs-on .rs-opt[aria-selected="true"] .rs-thumb:not(.is-blank):not(.is-pending) {
	box-shadow: 0 0 0 1px var(--accent);
}

/* --- closed control ------------------------------------------------------ */

/* The slot is a flex item of .rs-button (gap: 10px). `display` would defeat the
   `hidden` attribute the script uses for "All products", so that case is
   restated — otherwise the reset option shows a 28px hole before its label. */
.reports-page .reports-well.rs-on .rs-value-thumb {
	display: block;
	flex: 0 0 28px;
	width: 28px;
	height: 28px;
}

.reports-page .reports-well.rs-on .rs-value-thumb[hidden] {
	display: none;
}

/* 8 + 28 + 8 = 44px of content inside a 52px-minimum button: the chip never
   makes the closed control taller than Round 6 left it, so choosing a product
   cannot nudge the search field beside it or the ledger below. */
.reports-page .reports-well.rs-on.rs-thumbs .rs-button {
	padding-left: 12px;
}

@media (forced-colors: active) {
	/* box-shadow is dropped under a forced palette; a real border keeps the chip's
	   edge. The photograph itself is content and is left alone. */
	.reports-page .reports-well.rs-on .rs-thumb {
		outline: 1px solid CanvasText;
		outline-offset: -1px;
	}

	.reports-page .reports-well.rs-on .rs-thumb.is-blank {
		outline: 0;
	}

	.reports-page .reports-well.rs-on .rs-thumb.is-pending {
		outline-style: dashed;
		color: CanvasText;
	}

	.reports-page .reports-well.rs-on .rs-thumb img {
		filter: none;
	}
}
