/*
	A layer over Bootstrap, not a design system.

	Pass 4 shipped the class contract: the structures the section 21 screens need
	and a non-colour cue for every state they can be in. Pass 5 brings the brand -
	palette, typography, spacing rhythm - and it did that by replacing the custom
	properties below rather than by editing a view. No .cshtml changed.

	Two constraints shape the whole file:

	- Section 23 forbids style= attributes, so every state a view can be in has to
	  be reachable by class name from here. A state that needed an inline style
	  would be a state the stylesheet could not own.
	- No colour carries meaning on its own. Each indicator renders a glyph and a
	  word, so this file may tint them and nothing is lost when it does not. In
	  greyscale the four state tints collapse to nearly one grey, which is the
	  reason the glyph and the label are not negotiable. The colour added here is
	  always a third cue behind a glyph and a word, never a second one and never
	  the only one: no state was introduced whose signal is a hue, and no word or
	  glyph was taken away to make room for one.

	The palette is the K Group brand, taken from kds-dnntheme-kgroup2026 rather
	than from a screenshot. It lives in the :root block below and nowhere else:
	charts.js reads these same custom properties through getComputedStyle, so a
	hue changed here changes the charts too.

	Every colour pair carrying text meets WCAG AA (4.5:1) on its own background;
	the computed ratio is recorded beside each token.
*/

/*
	The brand faces, vendored because the policy is font-src 'self' and the DNN
	theme's own Google Fonts link is unreachable here. Latin subsets, variable
	weight, 82 KB for the pair. See wwwroot/fonts/OFL.txt.

	font-display: swap - a blocked or slow font leaves the fallback rendered
	rather than a page of invisible text.
*/
@font-face {
	font-family: "Inter";
	font-style: normal;
	font-weight: 100 900;
	font-display: swap;
	src: url("../fonts/inter-latin-var.woff2") format("woff2");
}

@font-face {
	font-family: "Sora";
	font-style: normal;
	font-weight: 100 800;
	font-display: swap;
	src: url("../fonts/sora-latin-var.woff2") format("woff2");
}

:root {
	/* Rhythm and geometry. The theme sets a 2px border for a marketing site;
	   at this density that reads as a grid of boxes, so the rule stays 1px. */
	--lt-gap: 1rem;
	--lt-gap-tight: 0.375rem;
	--lt-radius: 0.375rem;

	/* The page gutter, wider than the internal rhythm so the content stops
	   short of the screen edge. It scales with the viewport and is clamped at
	   both ends: a phone keeps the 1rem it had, and a wide monitor stops
	   widening at 3rem rather than pushing the content into a column. The
	   header uses the same value, so the brand mark stays on the same left
	   edge as the heading below it. */
	--lt-gutter: clamp(var(--lt-gap), 4vw, 3rem);
	--lt-border-color: #dadada;
	--lt-border: 1px solid var(--lt-border-color);

	/* Surface and ink. The page is tinted and the content sits on white, so a
	   card is a card because it is lighter than what is behind it rather than
	   because it has a line around it. Ratios below are against --lt-surface
	   unless a second figure names --lt-app-bg. */
	--lt-app-bg: #eef3f6;
	--lt-surface: #ffffff;
	--lt-surface-sunken: #f4f6f7;
	--lt-ink: #333333; /* 12.63:1, 11.30:1 on app-bg */
	--lt-muted: #6b6b6b; /*  5.33:1, 4.77:1 on app-bg */

	/* Brand. --lt-brand is 3.70:1 and is never used for text. --lt-brand-ink
	   carries links and is darkened past the theme value so it clears AA on the
	   tinted page as well as on white. --lt-brand-deep is the header bar and
	   every heading. --lt-accent is the K Group orange: rules, the focus ring
	   and the current-range underline, never text. */
	--lt-brand: #008fbe; /*  3.70:1 - rules, marks, chart series */
	--lt-brand-ink: #006d90; /*  5.85:1, 5.23:1 on app-bg */
	--lt-brand-deep: #004a61; /*  9.76:1 - white on it, 8.72:1 as text */
	--lt-brand-soft: #e3f1f7; /* table heads and hovers */
	--lt-accent: #ff7a1a; /*  2.61:1 as text, so never text */
	--lt-on-brand: #ffffff; /*  9.76:1 on brand-deep, 5.85:1 on ink */

	/* States. Four hues, as on the NRGHawk pages: green, amber, red and grey.
	   Each is a text colour at AA on its own -soft fill, and the fill and the
	   border are decoration over a word that already says the same thing. The
	   caution text is a darkened amber rather than the brand yellow, which is
	   1.62:1 and unreadable as text.

	   In greyscale the four fills sit between L 0.854 and L 0.902 - they are
	   one colour with the hue removed, which is the whole reason the glyph and
	   the label are not negotiable. */
	--lt-ok: #2f6e39; /*  6.16:1, 5.40:1 on ok-soft */
	--lt-ok-soft: #e7f3ea;
	--lt-caution: #8a5a00; /*  5.93:1, 5.37:1 on caution-soft */
	--lt-caution-soft: #fdf3dd;
	--lt-caution-edge: #ffc145; /* the brand yellow, surviving as an edge */
	--lt-alert: #b02a37; /*  6.50:1, 5.59:1 on alert-soft */
	--lt-alert-soft: #fbeaec;
	--lt-alert-edge: #e3a0a7;
	--lt-unknown: #5c5c5c; /*  6.69:1, 5.97:1 on unknown-soft */
	--lt-unknown-soft: #f1f2f3;

	/* Depth. One step. A shadow is not a state and nothing reads one. */
	--lt-shadow: 0 1px 2px rgba(0, 45, 60, 0.07);

	/* Chart series, read by charts.js. Hot and cold are separated in greyscale
	   as well as in hue (L 0.094 against 0.234) because a printed chart loses
	   the colour and keeps only the dash pattern. */
	--lt-chart-hot: #9a3412; /*  7.31:1 */
	--lt-chart-cold: #008fbe; /*  3.70:1 */
	--lt-chart-state: #2f6e39;
	--lt-chart-grid: #e6e9ea;
	--lt-chart-ink: #5c5c5c;

	/* Temperature tiles. Separate tokens from the state hues on purpose:
	   --lt-alert red means "something is wrong", and a hot fill is not a
	   fault. These are the chart series hues instead, so a tile matches the
	   line drawn underneath it - except cold, which takes --lt-brand-ink
	   because --lt-chart-cold is 3.70:1 and will not carry white text.

	   Each carries --lt-on-brand. The hue is still the third cue: Hot, Warm
	   and Cold are words in the markup and stay words in greyscale. */
	--lt-temp-hot: #9a3412; /*  7.31:1 - white on it */
	--lt-temp-warm: #b45309; /*  5.02:1 - white on it */
	--lt-temp-cold: #006d90; /*  5.85:1 - white on it */

	/* Type. Sora for headings and the brand mark, Inter for everything else,
	   each with a real fallback. The theme's 3.5rem/900 heading scale is tuned
	   for a marketing page and does not come across; the family does. */
	--lt-font-body:
		"Inter", -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
	--lt-font-head:
		"Sora", "Inter", -apple-system, "Segoe UI", Roboto, Helvetica, Arial,
		sans-serif;
}

/* --- Typography --------------------------------------------------------- */

body {
	font-family: var(--lt-font-body);
	color: var(--lt-ink);
	background-color: var(--lt-app-bg);
}

h1,
h2,
h3,
h4,
h5,
h6 {
	font-family: var(--lt-font-head);
	font-weight: 700;
	letter-spacing: -0.01em;
	color: var(--lt-brand-deep);
}

a {
	color: var(--lt-brand-ink);
	text-underline-offset: 0.15em;
}

/*
	One visible focus ring for every interactive element, in the brand rather
	than the browser default, which disappears against a tinted border.
	Keyboard reachability is a section 21 requirement.

	Two colours, and that is not decoration. A focus indicator is a state
	indicator, so 1.4.11 wants 3:1 against whatever sits next to it, and no
	single token in this palette clears that everywhere: the orange is 2.61:1
	on a white card and 2.33:1 on the page tint, while --lt-brand-deep is
	9.76:1 and 8.73:1 there but 1:1 inside the header, which is painted
	--lt-brand-deep itself. So the ring is deep blue from the element edge out
	to 2px and orange from 2px to 4px. On any light surface the inner band
	carries it at 8.73:1 or better; on the header the inner band vanishes into
	the bar and the orange carries it at 3.74:1. The two bands are also 3.74:1
	against each other, so the ring has its own boundary on a background this
	palette has not met yet.

	The shadow is the inner band - box-shadow spreads outward from the border
	box, so it fills the gap the outline-offset opens rather than sitting under
	the element. Nothing focusable carries a shadow of its own, so there is
	none to overwrite.
*/
a:focus-visible,
button:focus-visible,
[tabindex]:focus-visible {
	outline: 2px solid var(--lt-accent);
	outline-offset: 2px;
	box-shadow: 0 0 0 2px var(--lt-brand-deep);
	border-radius: var(--lt-radius);
}

/* --- Chrome ------------------------------------------------------------- */

/*
	Visible on focus rather than permanently hidden. A skip link that never
	appears is a skip link no one can use.
*/
.lt-skip {
	position: absolute;
	left: -100vw;
	top: 0;
	z-index: 10;
	padding: var(--lt-gap-tight) var(--lt-gap);
	background: var(--lt-surface);
	color: var(--lt-brand-ink);
	font-weight: 600;
	border: var(--lt-border);
}

.lt-skip:focus {
	left: 0;
}

/*
	A solid brand bar rather than a white strip with a rule under it. The orange
	is ornament: the boundary between the bar and the page is the 9.76:1 step in
	the background, not the 3px line, so nothing is lost where the line is not
	seen. Orange on brand-deep is 3.74:1, which clears the non-text threshold
	anyway.
*/
.lt-header {
	border-bottom: 3px solid var(--lt-accent);
	padding: 0.625rem var(--lt-gutter);
	background-color: var(--lt-brand-deep);
}

.lt-header__brand {
	font-family: var(--lt-font-head);
	font-weight: 700;
	font-size: 1.125rem;
	letter-spacing: -0.01em;
	color: var(--lt-on-brand);
	text-decoration: none;
}

.lt-main {
	padding: var(--lt-gap) var(--lt-gutter);
}

/*
	The page heading, its state chips and its range caption sit on one raised
	block so the top of every screen has the same shape. The left rail is brand,
	not state: it is the same on all three pages and says nothing about the unit.
*/
.lt-page__head {
	margin-bottom: var(--lt-gap);
	padding: var(--lt-gap);
	border: var(--lt-border);
	border-left: 4px solid var(--lt-brand);
	border-radius: var(--lt-radius);
	background-color: var(--lt-surface);
	box-shadow: var(--lt-shadow);
}

.lt-page__meta {
	display: flex;
	flex-wrap: wrap;
	gap: var(--lt-gap);
	margin: 0;
	color: var(--lt-muted);
}

/* --- Cards -------------------------------------------------------------- */

/*
	A list, not a grid of divs. The overview is an enumeration of sites, and a
	screen reader announcing how many there are before reading them is the whole
	benefit of saying so in the markup.
*/
.lt-cards {
	display: grid;
	/* min() so the track can fall below its preferred width on a narrow phone.
	   A bare minmax(20rem, 1fr) is a hard floor and overflows the viewport. */
	grid-template-columns: repeat(auto-fill, minmax(min(20rem, 100%), 1fr));
	gap: var(--lt-gap);
	margin: 0;
	padding: 0;
	list-style: none;
}

.lt-cards__item {
	display: flex;
}

.lt-card {
	display: flex;
	flex: 1 1 auto;
	flex-direction: column;
	gap: var(--lt-gap-tight);
	padding: var(--lt-gap);
	border: var(--lt-border);
	border-top: 3px solid var(--lt-brand);
	border-radius: var(--lt-radius);
	background-color: var(--lt-surface);
	box-shadow: var(--lt-shadow);
}

/*
	The unassigned group is marked structurally, not only by its name. It is a
	real card - a device reporting telemetry that matches no configuration is an
	install problem someone has to see - but it is not a site, and the border
	says so without relying on the reader knowing what "Unassigned" means.
*/
/*
	Dashed all the way round, including the top rule, which also drops to the
	neutral grey. Brand blue on that edge would read as "a site like the others",
	which is the one thing this card is not.
*/
.lt-card--unassigned {
	border-style: dashed;
	border-top-color: var(--lt-unknown);
}

.lt-card__title {
	margin: 0;
	font-size: 1.125rem;
	font-family: var(--lt-font-head);
	font-weight: 700;
}

.lt-card__states {
	display: flex;
	flex-wrap: wrap;
	gap: var(--lt-gap-tight);
	margin: var(--lt-gap-tight) 0 0;
}

.lt-card__foot {
	margin-top: auto;
	padding-top: var(--lt-gap-tight);
	border-top: var(--lt-border);
	color: var(--lt-muted);
}

.lt-card__updated-label::after {
	content: ": ";
}

/* --- Metrics ------------------------------------------------------------ */

.lt-metrics {
	display: flex;
	flex-wrap: wrap;
	gap: var(--lt-gap);
	margin: 0;
}

/*
	The dashboard's site cards carry .lt-metrics--water on this flex-wrap
	list, not on the tile grid, so each item is sized by its own content
	rather than by a track. A card narrow enough leaves room for only one or
	three items per line before wrapping, which breaks the hot/cold/total/
	split figures out of the two-by-two grouping the tile panels show -
	Total and Hot to cold have landed on their own rows instead of sharing
	one. Forcing two columns keeps that grouping regardless of card width.

	:not(.lt-metrics--tiles) keeps this out of the tile panels, which already
	get their own two-by-two from .lt-metrics--tiles.lt-metrics--water below.
*/
.lt-metrics--water:not(.lt-metrics--tiles) {
	display: grid;
	grid-template-columns: repeat(2, 1fr);
}

.lt-metric__label {
	margin: 0;
	font-weight: 400;
	color: var(--lt-muted);
}

.lt-metric__value {
	margin: 0;
	font-variant-numeric: tabular-nums;
	font-weight: 600;
	font-size: 1.25rem;
	font-family: var(--lt-font-head);
	color: var(--lt-ink);
	line-height: 1.2;
}

/* --- Water -------------------------------------------------------------- */

.lt-water {
	padding-top: var(--lt-gap-tight);
	border-top: var(--lt-border);
}

.lt-water__title {
	margin: 0 0 var(--lt-gap-tight);
	font-size: 1rem;
}

/*
	The degraded cases are marked on the section itself so that a reader scanning
	several cards can see which figures are measured and which are timed, without
	reading each one. The words are still in the markup; this only makes them
	easier to find.

	Doubled up on .lt-water to outweigh .lt-panel. Both views render this section
	as lt-panel lt-water lt-water--<disclosure>, and .lt-panel sets the border
	shorthand further down the file at the same specificity, which reset the rail
	to the ordinary 1px grey. A single class here silently drew nothing.

	Deliberately a rail and not a bar, and deliberately not a fill either. Hot and
	cold valve-open minutes overlap and are never summed, so nothing here may
	render a proportion, a background or a total - a tinted panel behind two
	figures that do not add up is exactly the misreading this guards against.

	The rail is the darkened amber rather than the brand yellow: #ffc145 on white
	is 1.47:1, which is a rail most people will not see.
*/
.lt-water.lt-water--valvetimeonly,
.lt-water.lt-water--partiallymeasured,
.lt-water.lt-water--unreportedunit,
.lt-water.lt-water--nodata {
	border-left: 3px solid var(--lt-caution);
	padding-left: var(--lt-gap-tight);
}

.lt-water__unavailable {
	margin: 0;
	font-weight: 600;
}

.lt-water__note,
.lt-water__caveat {
	display: flex;
	flex-wrap: wrap;
	gap: var(--lt-gap-tight);
	align-items: baseline;
	margin: var(--lt-gap-tight) 0 0;
	color: var(--lt-muted);
}

/* --- State indicators --------------------------------------------------- */

/*
	The glyph and the tint are decoration. The label is the affordance, and it is
	always in the document, so this rule set can be replaced wholesale without
	losing information.

	Filled rather than outlined, which is the NRGHawk pattern and is why the
	border moved to the full-strength state colour: a soft fill needs a crisp
	edge or it reads as a smudge. Every text-on-fill pair below is AA - 5.40,
	5.37, 5.59 and 5.97 to one - and none of the four is distinguishable from the
	others once the hue is removed, so the glyph and the word carry it and the
	unknown chip is additionally dashed where the other three are solid.
*/
.lt-state {
	display: inline-flex;
	align-items: baseline;
	gap: 0.25rem;
	padding: 0.0625rem 0.5rem;
	border: var(--lt-border);
	border-radius: 999px;
	font-weight: 500;
	white-space: nowrap;
}

.lt-state__glyph {
	font-weight: 700;
}

.lt-state--ok {
	border-color: var(--lt-ok);
	background-color: var(--lt-ok-soft);
	color: var(--lt-ok);
}

.lt-state--caution {
	border-color: var(--lt-caution);
	background-color: var(--lt-caution-soft);
	color: var(--lt-caution);
}

.lt-state--alert {
	border-color: var(--lt-alert);
	background-color: var(--lt-alert-soft);
	color: var(--lt-alert);
}

/*
	Nothing is being asserted. This is the Q4 case: the thresholds are
	placeholders, no calibration data exists, and a neutral mark beside an N/A is
	the NRGHawk precedent for saying so without dressing a guess as a result.
*/
.lt-state--unknown {
	border-color: var(--lt-unknown);
	background-color: var(--lt-unknown-soft);
	color: var(--lt-unknown);
	border-style: dashed;
}

/* --- Notes and banners -------------------------------------------------- */

/*
	Where the caveats are actually readable. Not a tooltip: a tooltip is
	unreachable by keyboard and by touch, so a caveat that lived in one would be
	a caveat most readers never see.
*/
.lt-notes {
	margin: var(--lt-gap-tight) 0 0;
	padding: 0;
	list-style: none;
	color: var(--lt-muted);
}

.lt-notes__item + .lt-notes__item {
	margin-top: var(--lt-gap-tight);
}

.lt-notes__label {
	font-weight: 600;
}

.lt-notes__label::after {
	content: " — ";
}

.lt-banner {
	display: flex;
	flex-wrap: wrap;
	gap: var(--lt-gap-tight);
	align-items: baseline;
	margin-bottom: var(--lt-gap);
	padding: var(--lt-gap-tight) var(--lt-gap);
	border: var(--lt-border);
	border-radius: var(--lt-radius);
	background-color: var(--lt-surface);
	box-shadow: var(--lt-shadow);
}

.lt-banner__text {
	margin: 0;
	color: var(--lt-muted);
}

/*
	Dashed, because an empty region and a region that failed to load look the
	same otherwise. The sentence inside says which one it is.
*/
.lt-empty {
	padding: var(--lt-gap);
	border: 1px dashed var(--lt-border-color);
	border-radius: var(--lt-radius);
	background-color: var(--lt-surface);
	color: var(--lt-muted);
}

/*
	Site details (SPECIFICATION.md section 21).

	Still a layer over Bootstrap rather than a skin: spacing, borders and layout
	only. Palette, typography and iconography are Pass 5. Nothing here carries
	meaning that the markup does not also carry in words - section 21 forbids a
	state told by colour alone, so every rule below is decoration over a label
	that already says the same thing.
*/

.lt-page__states {
	display: flex;
	flex-wrap: wrap;
	gap: var(--lt-gap-tight);
	margin: var(--lt-gap-tight) 0 0;
}

.lt-page__back {
	margin: var(--lt-gap) 0 0;
}

.lt-range {
	margin-bottom: var(--lt-gap);
}

.lt-range__list {
	display: flex;
	flex-wrap: wrap;
	gap: var(--lt-gap-tight);
	margin: 0;
	padding: 0;
	list-style: none;
}

.lt-range__option {
	display: inline-block;
	padding: 0.25rem 0.75rem;
	border: var(--lt-border);
	border-radius: var(--lt-radius);
	background-color: var(--lt-surface);
	color: var(--lt-brand-ink);
	text-decoration: none;
}

.lt-range__option:hover {
	background-color: var(--lt-brand-soft);
	border-color: var(--lt-brand);
}

/*
	The selected option is also marked with aria-current in the view, and the
	range it selects is named in the page heading. The weight and the rule below
	are a third cue, not the only one.
*/
.lt-range__option--current,
.lt-range__option--current:hover {
	font-weight: 600;
	border-color: var(--lt-brand-ink);
	border-bottom-width: 3px;
	border-bottom-color: var(--lt-accent);
	background-color: var(--lt-brand-ink);
	color: var(--lt-on-brand);
}

.lt-panels {
	display: grid;
	gap: var(--lt-gap);
	grid-template-columns: repeat(auto-fit, minmax(18rem, 1fr));
	margin-bottom: var(--lt-gap);
}

.lt-panel {
	padding: var(--lt-gap);
	border: var(--lt-border);
	border-radius: var(--lt-radius);
	background-color: var(--lt-surface);
	box-shadow: var(--lt-shadow);
}

.lt-panel__title {
	margin-top: 0;
	font-size: 1.1rem;
}

.lt-panel__caveat {
	display: flex;
	flex-wrap: wrap;
	gap: var(--lt-gap-tight);
	align-items: baseline;
	margin: var(--lt-gap-tight) 0 0;
	color: var(--lt-muted);
}

/* The total is the sum of every bucket above it, including the unclassified one. */
.lt-metric--total {
	font-weight: 600;
}

.lt-metric--total .lt-metric__value {
	color: var(--lt-brand-deep);
}

/*
	Tiles, as on the NRGHawk device summary. A count that has its own box is a
	count a reader can find without reading the ones beside it.

	The markup underneath is unchanged: still a <dl> of <dt>/<dd> pairs, and
	still label above value in document order as well as on the screen. No
	column-reverse anywhere here - a tile whose visual order disagrees with its
	DOM order reads back in the wrong order to anything that does not see it.
*/
.lt-metrics--tiles {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(7.5rem, 1fr));
	gap: var(--lt-gap-tight);
}

.lt-metrics--tiles .lt-metric {
	padding: var(--lt-gap-tight) 0.625rem;
	border: var(--lt-border);
	border-radius: var(--lt-radius);
	background-color: var(--lt-surface-sunken);
}

.lt-metrics--tiles .lt-metric__value {
	font-size: 1.5rem;
}

/*
	The counting cards - fills, water, valve time - centred and squared up, on
	the NRGHawk overview pattern the customer already reads. Two words above one
	number, both on the tile's centre line, is the shape that pattern gets its
	legibility from: the eye lands on the middle of the box and the number is
	already there.

	Every selector here is compounded with .lt-metrics--tiles, and that is load
	bearing. The dashboard's site cards carry .lt-metrics--water and
	.lt-metrics--valve on a plain flex list; a display size meant for a tile
	would not be inert there, it would be four times the size of the text beside
	it.

	The identity cards (.lt-metrics--site, .lt-metrics--unit) are deliberately
	left out. They hold sentences, timestamps and marks of varying length, and
	centring ragged text gives every line a different left edge to find.
*/
.lt-metrics--tiles.lt-metrics--fills .lt-metric,
.lt-metrics--tiles.lt-metrics--water .lt-metric,
.lt-metrics--tiles.lt-metrics--valve .lt-metric {
	display: flex;
	flex-direction: column;
	justify-content: center;
	align-items: center;
	gap: var(--lt-gap-tight);
	padding: var(--lt-gap);
	text-align: center;
}

/*
	A floor, not a height. The tile grows for a label that wraps to two lines -
	"Devices with recent alerts" in the reference is two lines and keeps its
	box - and a fixed height would clip it. At the two-column widths these cards
	sit at, the floor is what makes the box read as square rather than as a row.
*/
.lt-metrics--tiles.lt-metrics--fills .lt-metric,
.lt-metrics--tiles.lt-metrics--water .lt-metric {
	min-height: 9rem;
}

.lt-metrics--tiles.lt-metrics--fills .lt-metric__value,
.lt-metrics--tiles.lt-metrics--water .lt-metric__value,
.lt-metrics--tiles.lt-metrics--valve .lt-metric__value {
	font-size: 2.5rem;
}

/*
	The fills card, two by two rather than one auto-fit row. Four tiles across a
	panel this narrow came out at the 7.5rem floor with the count wrapping under
	its label; two wide columns give each count the width to sit beside the
	others and read as a tile rather than as a table cell.

	These two rules must stay after the .lt-metrics--tiles block: same
	specificity, so source order is what decides which grid wins.
*/
.lt-metrics--fills {
	grid-template-columns: repeat(2, 1fr);
}

/*
	Five tiles when a fill could not be classified, which leaves the total alone
	on the last row. It spans the row instead - a half-width tile beside an empty
	half reads as a sixth bucket that failed to render. The total is the fifth
	child exactly when the unclassified tile is present, so the selector needs no
	second class on the list.
*/
.lt-metrics--fills .lt-metric--total:nth-child(5) {
	grid-column: 1 / -1;
}

/*
	Two by two: hot and cold above, and under them the two figures that are read
	off the pair rather than measured beside it - the total they sum to, and the
	proportion they are in. The total keeps the left column, directly under hot,
	because it is the column a reader coming down from the volumes is already in.

	The split tile is why the total no longer spans the foot. A spanning total
	said "this is the sum of the two above and nothing else", which was worth
	saying; a half-width tile beside an empty half would have said less, and the
	column it leaves open is where the proportion belongs.

	Compounded with .lt-metrics--tiles for the same reason as the block above:
	the dashboard's site cards carry .lt-metrics--water on a flex list, and these
	declarations have no business reaching it.
*/
.lt-metrics--tiles.lt-metrics--water {
	grid-template-columns: repeat(2, 1fr);
}

/*
	The count size wherever the tile is wide enough to hold it, and only smaller
	where it is not. The split has to hold together on one line: a volume breaks
	after its number and still reads correctly - "278.2" over "gal" is one figure
	on two lines - but a split broken at its separator leaves "30% :" on a line,
	and a reader has to work out that the colon is not a typo. Nine characters
	at 2.5rem need about 210px and the tile's content box is 124px on a phone,
	so a fixed count size can only be had by letting the figure run out of its
	tile.

	The tile is therefore its own query container and the figure is sized from
	the tile rather than from the viewport. That distinction is the whole reason
	for the container unit here: this tile is 124px wide at 375px and still
	124px at 768px, where the panels have gone side by side, so a vw-based size
	would grow the text at exactly the width the box did not grow. The widest
	string this figure can hold is "30% : 70%", which needs 5.25px of tile for
	every 1px of font size, so 18.5% of the tile fits it with a little to spare.
	min() lets it reach 2.5rem and stop, which it does at about 1100px and keeps
	for every width above.

	This is the stylesheet's first container query, and it is a deliberate
	exception rather than a door opened. Section 23 rules out script, not this,
	and the intrinsic layout elsewhere is sized by the grid itself; here a
	single glyph run has to fit a box whose width the viewport does not predict.
*/
.lt-metrics--tiles.lt-metrics--water .lt-metric--split {
	container-type: inline-size;
}

.lt-metrics--tiles.lt-metrics--water .lt-metric--split .lt-metric__value {
	font-size: min(2.5rem, 18.5cqi);
	white-space: nowrap;
}

/* The identity tiles hold sentences, timestamps and marks rather than counts, and
   a timestamp set at the count size wraps to three lines in its own tile. The
   tile treatment is worth keeping for the grouping; the display size is not. */
.lt-metrics--site .lt-metric__value,
.lt-metrics--unit .lt-metric__value {
	font-size: 1.125rem;
}

/*
	The three temperature tiles, tinted. Decoration over three words that
	already say which is which: in greyscale the fills collapse to within 0.02 L
	of one another and nothing is lost, because the label is the signal and the
	hue is a scanning aid behind it.

	The text colour is set once on the tile and inherited, rather than restated
	on the label and the value, so a tile cannot end up white on one line and
	ink on the other if a modifier is ever added.
*/
.lt-metric--hot,
.lt-metric--warm,
.lt-metric--cold {
	color: var(--lt-on-brand);
}

.lt-metric--hot .lt-metric__label,
.lt-metric--hot .lt-metric__value,
.lt-metric--warm .lt-metric__label,
.lt-metric--warm .lt-metric__value,
.lt-metric--cold .lt-metric__label,
.lt-metric--cold .lt-metric__value {
	color: inherit;
}

.lt-metrics--tiles .lt-metric--hot {
	border-color: var(--lt-temp-hot);
	background-color: var(--lt-temp-hot);
}

.lt-metrics--tiles .lt-metric--warm {
	border-color: var(--lt-temp-warm);
	background-color: var(--lt-temp-warm);
}

.lt-metrics--tiles .lt-metric--cold {
	border-color: var(--lt-temp-cold);
	background-color: var(--lt-temp-cold);
}

.lt-units__title {
	font-size: 1.1rem;
}

/*
	The table scrolls, not the document. Nine columns on a phone would otherwise
	make the whole page slide sideways and take the headings with it.
*/
.lt-units__scroll {
	overflow-x: auto;
}

.lt-units__caption {
	caption-side: top;
	padding-bottom: var(--lt-gap-tight);
	color: var(--lt-muted);
}

.lt-units__table {
	width: 100%;
	margin-bottom: var(--lt-gap);
	font-variant-numeric: tabular-nums;
	border-collapse: collapse;
}

.lt-units__table th {
	font-family: var(--lt-font-head);
	font-weight: 600;
	font-size: 0.9375rem;
	text-align: left;
	border-bottom: 2px solid var(--lt-border-color);
	padding: var(--lt-gap-tight);
}

/*
	Only the column heads, not the row heads - scope="row" cells are unit names
	and belong with the data. The tint is what keeps nine columns readable once
	the table scrolls sideways under its own heading.
*/
.lt-units__table thead th {
	background-color: var(--lt-brand-soft);
	border-bottom-color: var(--lt-brand);
	color: var(--lt-brand-deep);
}

/*
	Zebra striping, which is the one thing that makes a nine-column row traceable
	across a phone-width scroll. It carries no meaning: which row a stripe lands
	on depends on sort order.

	Set on the cells rather than on the row, and this is not a style choice.
	Bootstrap paints every cell - `.table > :not(caption) > * > *` sets
	`background-color: var(--bs-table-bg)`, which is opaque white - so a
	background on the <tr> is covered over and draws nothing at all. This is on
	the cells, at a specificity that outweighs Bootstrap's (0,2,3 against 0,1,1)
	without !important.
*/
.lt-units__table tbody tr:nth-child(even) th,
.lt-units__table tbody tr:nth-child(even) td {
	background-color: var(--lt-surface-sunken);
}

.lt-units__table td {
	border-top: var(--lt-border);
	padding: var(--lt-gap-tight);
	vertical-align: top;
}

.lt-units__name {
	font-weight: 600;
	white-space: nowrap;
}

.lt-units__water,
.lt-units__health {
	display: table-cell;
}

.lt-units__volume {
	display: block;
}

.lt-units__valve {
	display: block;
	color: var(--lt-muted);
}

.lt-units__seen {
	white-space: nowrap;
}

.lt-units__notes-title {
	font-size: 1rem;
}

/*
	The banner's own text says what failed. The tint and the thicker rail are the
	third and fourth cues, in that order of importance.
*/
.lt-banner--error {
	border-color: var(--lt-alert-edge);
	border-left-width: 4px;
	border-left-color: var(--lt-alert);
	background-color: var(--lt-alert-soft);
}

/* --- Unit details (section 21) ------------------------------------------ */

.lt-unit {
	padding: var(--lt-gap);
	border: var(--lt-border);
	border-radius: var(--lt-radius);
	margin-bottom: var(--lt-gap);
	background-color: var(--lt-surface);
	box-shadow: var(--lt-shadow);
}

.lt-unit__title {
	margin-top: 0;
	font-size: 1.1rem;
}

/* --- Charts (section 21) ------------------------------------------------ */

.lt-charts {
	margin-bottom: var(--lt-gap);
}

.lt-charts__title {
	font-size: 1.1rem;
}

/*
	Says in words what the window is, what the zone is, and that a break is
	missing data rather than downtime. The charts themselves cannot say any of
	that, and a reader who never reaches the canvas still needs all three.
*/
.lt-charts__note {
	color: var(--lt-muted);
}

.lt-chart {
	margin: 0 0 var(--lt-gap);
	padding: var(--lt-gap);
	border: var(--lt-border);
	border-radius: var(--lt-radius);
	background-color: var(--lt-surface);
	box-shadow: var(--lt-shadow);
}

/*
	The height lives here rather than on the canvas element, because section 23
	forbids a style attribute in a view and Chart.js needs a sized box to
	measure itself against. Chart.js writes the canvas dimensions through the
	CSSOM, which script-src does not police.
*/
.lt-chart__frame {
	position: relative;
	height: 18rem;
}

.lt-chart__canvas {
	display: block;
}

.lt-chart__caption {
	font-family: var(--lt-font-head);
	font-weight: 600;
	margin-bottom: var(--lt-gap-tight);
	color: var(--lt-brand-deep);
}

.lt-chart__summary {
	margin: var(--lt-gap-tight) 0 0;
	color: var(--lt-muted);
}

/*
	The stretch-by-stretch log, folded away. It is the chart's text equivalent
	rather than a second reading of it, so it has to stay reachable - but a
	hundred rows under a chart is a wall, and the chart is what the page is for.

	<details> is the whole mechanism. No script, which the 'self'-only script
	policy would not run inline anyway (section 23), and the contents stay in
	the document for find-in-page and for a screen reader that walks it.
*/
.lt-chart__log {
	margin-top: var(--lt-gap-tight);
	border-top: var(--lt-border);
	padding-top: var(--lt-gap-tight);
}

.lt-chart__log-summary {
	cursor: pointer;
	color: var(--lt-brand-ink);
}

/* The table scrolls, not the document. */
.lt-chart__scroll {
	overflow-x: auto;
}

.lt-chart__table {
	width: 100%;
	margin: var(--lt-gap-tight) 0 0;
}

.lt-chart__table-caption {
	caption-side: top;
	padding-bottom: var(--lt-gap-tight);
	color: var(--lt-muted);
}

/* Same treatment as the units table, for the same reason: a column head that
   holds its own tint stays a column head once the table scrolls sideways. */
.lt-chart__table thead th {
	background-color: var(--lt-brand-soft);
	border-bottom: 2px solid var(--lt-brand);
	color: var(--lt-brand-deep);
}

/*
	A break in the list of stretches. The row says No data in words; this rule
	only makes it easier to find while scanning.
*/
.lt-chart__gap-row {
	color: var(--lt-muted);
	font-style: italic;
}

/*
	Across every cell, the row header included. The first column of these tables
	is a <th scope="row"> carrying the timestamp, so a rule on td alone drew a
	break that started one column in - a partial line reads as a border that got
	clipped rather than as a hole in the series. A gap means no sample arrived:
	it is never downtime and never a zero, so the break has to look deliberate
	and has to cross the whole table.
*/
.lt-chart__gap-row th,
.lt-chart__gap-row td {
	border-top: 2px dashed var(--lt-border-color);
}

.lt-notes-title {
	font-size: 1rem;
}
