ci / build-test (push) Successful in 2m41s
Three things a reported Heizoel page got wrong at once. Its tank is dipped a few times a year and its burner read every few months, which is exactly the shape the coverage rules had not been walked through. "No data" for data that exists. A tank books nothing until the next dipstick closes the interval, so the stretch after the last dipstick is covered by no run at all, and a bucket no run covers was reported missing. The burner, whose run reaches into the window, said "only coarser data" -- the honest answer -- so one card claimed there was nothing while the coverage panel beside it listed years of data. A bucket that no run covers, no gap overlaps and no opening balance explains now reports the meter's resolution when its preceding coverage is within one interval of its own class: it is not silent, it is read rarely. A meter that does book its own buckets and stops -- a dead hourly source, a sheet asked about a later month -- still reads missing. Auto answering twelve months with one bar. Coarse only means "longer than a month", so a dipstick taken each autumn straddles a New Year as surely as a month start: coarsening the chart to years bought nothing and cost every point. The planning resolution now caps coarse at month when a run crosses a local year edge, and a series that cannot resolve the natural size no longer coarsens the whole chart -- it is drawn at that size with its buckets marked, which the chart and table already explain. A page contradicting itself. The comparison line above the ranking was fed the leading measure's matched coverage but worded as if it spoke for the page, directly above a burner row that did compare. It now names the figure it is about. Alongside: the "largest changes" ranking no longer drops a meter whose change is not comparable. It ranks what can be ranked, then lists the rest with their values and the reason -- the tank had been vanishing from its own energy type. And every dated table now reads newest first, as lists are read; charts stay chronological left to right, and the CSV export stays ascending for spreadsheets. A-41 to A-43 in the note record the three rules.
165 lines
9.6 KiB
CSS
165 lines
9.6 KiB
CSS
h1:focus {
|
|
outline: none;
|
|
}
|
|
|
|
/* MeterVault helpers. Colours come from the MudBlazor palette variables, so light and dark mode both work. */
|
|
.mv-up { color: var(--mud-palette-error); }
|
|
.mv-down { color: var(--mud-palette-success); }
|
|
.mv-main { max-width: 1400px; }
|
|
.mv-muted { color: var(--mud-palette-text-secondary); }
|
|
|
|
/* Visually hidden, still read by screen readers. */
|
|
.mv-sr-only {
|
|
position: absolute !important;
|
|
width: 1px;
|
|
height: 1px;
|
|
padding: 0;
|
|
margin: -1px;
|
|
overflow: hidden;
|
|
clip: rect(0, 0, 0, 0);
|
|
white-space: nowrap;
|
|
border: 0;
|
|
}
|
|
|
|
/* Page header (Shared/Analysis/PageHeader): title h1 with chips, actions wrapping below on narrow screens. */
|
|
.mv-page-header { margin-bottom: 16px; }
|
|
.mv-page-header__row { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 16px; }
|
|
.mv-page-header__title { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; min-width: 0; flex: 1 1 auto; }
|
|
.mv-page-header__h1 { margin: 0; min-width: 0; overflow-wrap: anywhere; }
|
|
.mv-page-header__chips { display: flex; flex-wrap: wrap; gap: 4px; }
|
|
.mv-page-header__actions { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
|
|
.mv-breadcrumbs .mud-breadcrumbs { flex-wrap: wrap; padding: 0 0 4px 0; }
|
|
@media (max-width: 599.98px) {
|
|
.mv-page-header__h1 { font-size: 1.5rem; }
|
|
}
|
|
|
|
/* Period toolbar (Shared/Analysis/PeriodToolbar): controls wrap; each takes a full row on a phone. */
|
|
.mv-toolbar { display: flex; flex-wrap: wrap; align-items: flex-start; gap: 8px 12px; }
|
|
.mv-toolbar__field { flex: 1 1 180px; min-width: 160px; max-width: 280px; }
|
|
.mv-toolbar__info { align-self: center; }
|
|
.mv-toolbar__details { display: flex; flex-direction: column; gap: 2px; max-width: 280px; }
|
|
.mv-toolbar__custom { display: flex; flex-wrap: wrap; align-items: flex-start; gap: 8px; flex: 1 1 100%; }
|
|
.mv-toolbar__date { flex: 1 1 160px; max-width: 220px; }
|
|
.mv-toolbar__apply { align-self: center; min-height: 40px; }
|
|
.mv-toolbar__hint { flex: 1 1 100%; color: var(--mud-palette-error); }
|
|
.mv-toolbar__reset, .mv-toolbar__export { align-self: center; }
|
|
@media (max-width: 599.98px) {
|
|
.mv-toolbar__field, .mv-toolbar__date { max-width: none; flex-basis: 100%; }
|
|
}
|
|
|
|
/* Changes (Shared/Analysis/ChangeChip): tone by the metric's polarity; the words and the arrow carry the meaning. */
|
|
.mv-change { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 2px 6px; font-size: 0.875rem; line-height: 1.4; }
|
|
.mv-change__icon { flex: none; }
|
|
.mv-change__caption { color: var(--mud-palette-text-secondary); }
|
|
.mv-change-good { color: var(--mud-palette-success); }
|
|
.mv-change-bad { color: var(--mud-palette-error); }
|
|
.mv-change-neutral { color: var(--mud-palette-text-secondary); }
|
|
|
|
/* Metric cards. */
|
|
.mv-metric { height: 100%; }
|
|
.mv-metric__value-row { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 8px; }
|
|
.mv-metric__value { font-size: 1.5rem; font-weight: 500; line-height: 1.3; overflow-wrap: anywhere; }
|
|
.mv-metric__value--words { font-size: 1.1rem; color: var(--mud-palette-text-secondary); }
|
|
.mv-metric__link { display: block; width: fit-content; margin-top: 4px; }
|
|
|
|
/* Charts and tables. A wide table scrolls inside its container, never the page. */
|
|
.mv-chart-stack { display: flex; flex-direction: column; gap: 16px; }
|
|
.mv-chart { margin: 0; min-width: 0; }
|
|
.mv-chart__unit { font-size: 0.75rem; color: var(--mud-palette-text-secondary); }
|
|
.mv-chart__note { font-size: 0.75rem; color: var(--mud-palette-text-secondary); margin-top: 4px; }
|
|
.mv-chart--clickable .apexcharts-bar-area,
|
|
.mv-chart--clickable .apexcharts-marker,
|
|
.mv-chart--clickable .apexcharts-xaxis-label { cursor: pointer; }
|
|
/* Positioned, so visually hidden cells (absolute) stay inside the scrolling box instead of widening the page. */
|
|
.mv-table-scroll { position: relative; max-width: 100%; overflow-x: auto; }
|
|
.mv-table-scroll:focus-visible { outline: 2px solid var(--mud-palette-primary); outline-offset: 2px; }
|
|
|
|
/* Visible keyboard focus (brief §8): MudBlazor removes the outline of links and buttons and marks focus only with a ~6 %
|
|
tint. Every focusable control gets a solid ring in the text colour of the theme — readable on both the light and the
|
|
dark surface (the teal primary is under 3:1 on white). Nav links are drawn inside, so the drawer never clips the ring. */
|
|
.mud-button-root:focus-visible,
|
|
.mud-icon-button:focus-visible,
|
|
.mud-icon-button:has(:focus-visible),
|
|
.mud-chip:focus-visible,
|
|
.mud-link:focus-visible,
|
|
.mud-tab:focus-visible,
|
|
.mud-breadcrumb-item a:focus-visible,
|
|
.mv-drill a:focus-visible {
|
|
outline: 2px solid var(--mud-palette-text-primary);
|
|
outline-offset: 2px;
|
|
}
|
|
.mud-nav-link:focus-visible,
|
|
.mud-nav-group > button:focus-visible,
|
|
.mud-list-item:focus-visible {
|
|
outline: 2px solid var(--mud-palette-text-primary);
|
|
outline-offset: -2px;
|
|
}
|
|
.mv-analysis-table th, .mv-analysis-table td { white-space: nowrap; }
|
|
.mv-analysis-table td .mv-cell-secondary { white-space: normal; min-width: 12ch; }
|
|
.mv-num { text-align: right; font-variant-numeric: tabular-nums; }
|
|
.mv-cell-secondary { font-size: 0.75rem; color: var(--mud-palette-text-secondary); }
|
|
.mv-row-label { font-weight: 400; text-align: left; }
|
|
.mv-row-group th { text-align: left; font-weight: 600; padding-top: 12px; border-top: 1px solid var(--mud-palette-lines-default); white-space: normal; }
|
|
.mv-row-total th, .mv-row-total td { font-weight: 600; border-bottom: 2px solid var(--mud-palette-lines-default); }
|
|
.mv-qualified { font-style: italic; }
|
|
.mv-unknown { color: var(--mud-palette-text-secondary); }
|
|
.mv-drill { width: 1%; }
|
|
|
|
/* States: empty, refreshing, projection, comparison, attention, contributions. */
|
|
.mv-empty { display: flex; gap: 12px; align-items: flex-start; padding: 16px; border: 1px dashed var(--mud-palette-lines-default); border-radius: var(--mud-default-borderradius); }
|
|
.mv-empty__icon { color: var(--mud-palette-text-secondary); flex: none; }
|
|
.mv-refresh__bar { min-height: 4px; }
|
|
.mv-refresh--busy .mv-refresh__content { opacity: 0.55; transition: opacity 0.2s ease-in; }
|
|
.mv-projection { display: inline-flex; align-items: center; gap: 6px; font-size: 0.875rem; color: var(--mud-palette-text-secondary); }
|
|
.mv-comparison { display: flex; flex-direction: column; gap: 2px; font-size: 0.875rem; }
|
|
.mv-comparison__warning { display: inline-flex; align-items: center; gap: 4px; }
|
|
.mv-attention__list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
|
|
.mv-attention__item { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 8px; }
|
|
.mv-attention__icon { flex: none; align-self: center; }
|
|
.mv-attention__item--error .mv-attention__icon { color: var(--mud-palette-error); }
|
|
.mv-attention__item--warning .mv-attention__icon { color: var(--mud-palette-warning); }
|
|
.mv-attention__item--info .mv-attention__icon { color: var(--mud-palette-info); }
|
|
.mv-attention__text { flex: 1 1 16rem; min-width: 0; overflow-wrap: anywhere; }
|
|
.mv-contributions__formula { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 8px; }
|
|
.mv-formula { display: inline-flex; flex-wrap: wrap; align-items: baseline; gap: 4px; }
|
|
.mv-formula code { font-size: 0.8rem; color: var(--mud-palette-text-secondary); }
|
|
.mv-formula__ref { display: inline-flex; align-items: baseline; gap: 4px; }
|
|
|
|
@media (prefers-reduced-motion: reduce) {
|
|
.mv-refresh--busy .mv-refresh__content { transition: none; }
|
|
}
|
|
|
|
.valid.modified:not([type=checkbox]) {
|
|
outline: 1px solid #26b050;
|
|
}
|
|
|
|
.invalid {
|
|
outline: 1px solid #e50000;
|
|
}
|
|
|
|
.validation-message {
|
|
color: #e50000;
|
|
}
|
|
|
|
.blazor-error-boundary {
|
|
background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121;
|
|
padding: 1rem 1rem 1rem 3.7rem;
|
|
color: white;
|
|
}
|
|
|
|
.blazor-error-boundary::after {
|
|
content: "An error has occurred."
|
|
}
|
|
|
|
.darker-border-checkbox.form-check-input {
|
|
border-color: #929292;
|
|
}
|
|
|
|
.form-floating > .form-control-plaintext::placeholder, .form-floating > .form-control::placeholder {
|
|
color: var(--bs-secondary-color);
|
|
text-align: end;
|
|
}
|
|
|
|
.form-floating > .form-control-plaintext:focus::placeholder, .form-floating > .form-control:focus::placeholder {
|
|
text-align: start;
|
|
} |