/* THE CHARTS THE APPS SHARE (2026-10-29) — horizontal bars, stacked bars and the
   donut, with the tooltip, the tier and category classes and the table twin.
   Moved here from the Asset Manager's styles.css, rule for rule and in the same
   order, when Device Manager's dashboard needed them: one look, no copy to drift
   (the top bar's lesson, 2026-10-28). Their templates are views/chrome/charts/.
   Linked by chrome/head.ejs straight after chrome.css, so an app's own stylesheet
   and the themes still come after it, as they did. Structure only: the colours are
   the tokens in chrome.css (--chart-bar-*, --chart-cat-*, --chart-tier-*), which
   every theme re-pitches. The report-only kinds (columns, grouped, dumbbell,
   heatmap, scatter, timeline) are still the Asset Manager's, in its styles.css. */

/* Horizontal bar charts — plain HTML/CSS, no charting library. */
.chart-row {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin-bottom: 0.5rem;
}

.chart-label {
  /* a basis, not a fixed width: it may give way to the track and the value
     when the column is narrow (the ellipsis below is what makes that safe) */
  flex: 0 1 8rem;
  min-width: 3.5rem;
  font-size: 0.85em;
  color: var(--pico-muted-color);
  /* No text-transform (2026-10-02): `capitalize` turned the category "Co-op Gas
     Card" into "Co-Op Gas Card" on the dashboard. A label is a record's own
     name and is printed as the record spells it (found by the sweep agent). */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.chart-track {
  flex: 1;
  background: var(--pico-muted-border-color);
  border-radius: 4px;
  height: 20px;
  overflow: hidden;
}

.chart-bar {
  height: 100%;
  border-radius: 0 4px 4px 0;
  min-width: 3px;
  /* A HAIRLINE EDGE, because the bar sits inside `.chart-track` and the track
     is what decides whether you can see where the bar ends. Measured against
     the real composited track, every light theme's worst bar was under WCAG
     1.4.11's 3:1 (1.02 to 2.86 across the seven).
     `inset` rather than a border, so it costs no layout: a real border would
     add 2px to a 20px-high bar and shift the fill inside the track. The colour
     is one token per mode (`--chart-bar-edge` in chrome.css) rather than per
     theme, so re-pitching a theme's palette needs no recomputation here. */
  box-shadow: inset 0 0 0 1px var(--chart-bar-edge, rgba(0, 0, 0, 0.5));
}

.chart-value {
  width: 2rem;
  flex-shrink: 0;
  text-align: right;
  font-variant-numeric: tabular-nums;
  font-size: 0.85em;
}

/* Status-mark colors for chart bars, picked (and contrast-checked against
   their surface) separately from the pastel status-badge colors above —
   a solid bar fill needs ~3:1 against the page background, not text contrast
   against a light pill. */
.chart-bar-available, .chart-swatch.chart-bar-available { background: var(--chart-bar-available); }
.chart-bar-checked_out { background: var(--chart-bar-checked_out); }
.chart-bar-in_maintenance { background: var(--chart-bar-in_maintenance); }
.chart-bar-not_working { background: var(--chart-bar-not_working); }
.chart-bar-lost { background: var(--chart-bar-lost); }
.chart-bar-disposed { background: var(--chart-bar-disposed); }
.chart-bar-donated { background: var(--chart-bar-donated); }
.chart-bar-category { background: var(--chart-bar-category); }

/* ===========================================================================
   DASHBOARD CHARTS, rebuilt 2026-09-20 (backlog S48b) per the dataviz method:
   thin marks, a 4px data-end, a hairline edge, values at the tip, hover that
   adds a tooltip and never gates, a table twin, colour from the theme's tokens.
   =========================================================================== */
.chart-row { text-decoration: none; color: inherit; position: relative; border-radius: 4px; padding: 1px 2px; }
.chart-row:hover, .chart-row:focus-visible { background: color-mix(in srgb, var(--pico-primary) 8%, transparent); }
.chart-row:hover .chart-label, .chart-row:focus-visible .chart-label { color: var(--pico-color); }
/* the row is an <a> and the track and bar are <span>s since 2026-09-20 — inline
   elements ignore width and height, so both are made blocks here */
.chart-track { display: block; height: 18px; background: color-mix(in srgb, var(--pico-muted-border-color) 55%, transparent); }
.chart-bar { display: block; border-radius: 0 4px 4px 0; transform-origin: left center; }
.chart-value { width: 3rem; color: var(--pico-muted-color); }

/* the ordinal ramp for an ordered scale: one hue, three steps, darkest first.
   MIXED WITH THE CARD COLOUR, NOT --pico-background-color (S76, 2026-09-21 —
   the maintainer's Phosphor screenshot: "these bars don't match the legend
   in colour"). Pico resets --pico-background-color to `transparent` on every
   <a>, and a chart row IS an <a>, so a bar inside it mixed its hue with
   nothing — a translucent step over the track — while the legend swatch, in
   a <li>, mixed with the real page. Same class, two colours. The card token
   is never reset on a link, and both sit on the card. */
.chart-bar-step-2 { background: color-mix(in srgb, var(--chart-bar-category) 66%, var(--pico-card-background-color)); }
.chart-bar-step-3 { background: color-mix(in srgb, var(--chart-bar-category) 36%, var(--pico-card-background-color)); }
/* the tooltip: one attribute, CSS only, shown on hover AND keyboard focus */
[data-tip] { position: relative; }
[data-tip]:hover::after, [data-tip]:focus-visible::after,
.donut-seg-link:hover .donut-seg::after { }
.chart-row[data-tip]:hover::after, .chart-row[data-tip]:focus-visible::after,
.donut-legend-row a[data-tip]:hover::after, .donut-legend-row a[data-tip]:focus-visible::after {
  content: attr(data-tip);
  position: absolute; left: 50%; bottom: calc(100% + 4px); transform: translateX(-50%);
  /* `--pico-card-background-color`, NOT `--pico-background-color`: this ::after
     sits on an <a>, and Pico sets `--pico-background-color: transparent` on
     links — measured 2026-09-20 as a dark pill with invisible text */
  background: var(--pico-color); color: var(--pico-card-background-color);
  font-size: 0.78rem; line-height: 1.2; padding: 0.3rem 0.55rem; border-radius: 4px; white-space: nowrap;
  pointer-events: none; z-index: 5; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
}
/* the donut */
/* THE LEGEND GOES UNDER THE DONUT WHEN ITS WORDS DO NOT FIT BESIDE IT
   (2026-10-05, DOCKET item 90). This was a grid — the donut 130-150px, the
   legend the rest — with each label `overflow-wrap: anywhere`, and the rest was
   not always enough: "in maintenance" printed as "maintenan" / "ce" at 1280 in
   every typeface (the dashboard's three-up card leaves the label about 70px)
   and as "maintenanc" / "e" in Phosphor under OpenDyslexic at 1366. The words
   were never too long for the card, only for the column the grid gave them.
   So it is a wrapping flex row now: the legend's narrowest is its longest word
   plus the swatch, count and share columns (the label track is
   minmax(min-content, 1fr) and the label breaks only a word that cannot fit a
   line on its own), the donut gives up to 40px of its 150 first, and when the
   two still do not fit side by side the legend takes the next line, full
   width, with the donut centred above it — which is what a phone already did.
   No breakpoint: it is decided by the words in the face being read. */
.donut-chart { display: flex; flex-wrap: wrap; gap: 1rem; align-items: center; }
/* the donut yields width to the legend: at 190px the three-column dashboard
   truncated "Checked out" to "Checke…" (measured 2026-09-20), and a legend
   that hides its own labels is a legend in name only */
.donut-svg { flex: 1 1 110px; min-width: 110px; max-width: 150px; margin-inline: auto; height: auto; overflow: visible; }
.donut-chart > .donut-legend { flex: 1 1 0%; }
.donut-rail { stroke: color-mix(in srgb, var(--pico-muted-border-color) 55%, transparent); stroke-width: 14; }
.donut-seg { stroke-width: 14; stroke: currentColor; transition: stroke-width 160ms ease; }
.donut-seg-link:hover .donut-seg, .donut-seg-link:focus-visible .donut-seg { stroke-width: 18; }
.donut-seg.chart-bar-available { color: var(--chart-bar-available); }
.donut-seg.chart-bar-checked_out { color: var(--chart-bar-checked_out); }
.donut-seg.chart-bar-in_maintenance { color: var(--chart-bar-in_maintenance); }
.donut-seg.chart-bar-not_working { color: var(--chart-bar-not_working); }
.donut-seg.chart-bar-lost { color: var(--chart-bar-lost); }
.donut-seg.chart-bar-disposed { color: var(--chart-bar-disposed); }
.donut-seg.chart-bar-donated { color: var(--chart-bar-donated); }
.donut-seg { background: none; }
.donut-hero { font-family: var(--pico-font-family); font-weight: 600; font-size: 22px; fill: var(--pico-color); }
.donut-hero-caption { font-size: 8.5px; fill: var(--pico-muted-color); letter-spacing: 0.04em; text-transform: uppercase; }
.donut-legend { list-style: none; margin: 0; padding: 0; }
.donut-legend li { list-style: none; margin: 0; padding: 0; }
.donut-legend li::marker { content: ''; }
.donut-legend-row a { display: grid; grid-template-columns: 0.75rem minmax(min-content, 1fr) auto 2.3rem; gap: 0.45rem; align-items: center; text-decoration: none; color: var(--pico-color); padding: 0.15rem 0.35rem; border-radius: 4px; font-size: 0.88em; }
.donut-legend-row a:hover, .donut-legend-row a:focus-visible { background: color-mix(in srgb, var(--pico-primary) 8%, transparent); }
.donut-legend-row.is-empty a { color: var(--pico-muted-color); }
.donut-legend-row.is-empty .chart-swatch { opacity: 0.35; }
/* No `capitalize` here either: the donut said "Checked Out" beside a bar legend
   and status badges that say "checked out" (2026-10-02). */
.legend-label { line-height: 1.15; overflow-wrap: break-word; }
.legend-value { font-variant-numeric: tabular-nums; }
.legend-share { font-variant-numeric: tabular-nums; color: var(--pico-muted-color); text-align: right; }
.chart-swatch { display: inline-block; width: 0.75rem; height: 0.75rem; border-radius: 3px; box-shadow: inset 0 0 0 1px var(--chart-bar-edge, rgba(0, 0, 0, 0.5)); }
.chart-table { margin: 0.25rem 0 0.5rem; }
.chart-table summary { font-size: 0.85em; color: var(--pico-muted-color); cursor: pointer; }
.chart-table table { font-size: 0.9em; margin-top: 0.5rem; }
/* motion: bars grow in, once, where motion is welcome — never when the reader
   or the theme says otherwise */
@media (prefers-reduced-motion: no-preference) {
  html:not([data-motion="off"]) .bars-chart .chart-bar { animation: chart-grow 480ms cubic-bezier(0.2, 0.7, 0.2, 1) both; animation-delay: calc(var(--i, 0) * 40ms); }
  html:not([data-motion="off"]) .donut-seg { animation: donut-in 600ms ease-out both; }
}
@keyframes chart-grow { from { transform: scaleX(0); } to { transform: scaleX(1); } }
@keyframes donut-in { from { opacity: 0; } to { opacity: 1; } }
@media (max-width: 480px) { .donut-chart { flex-direction: column; align-items: stretch; } .donut-svg { flex: none; width: 100%; max-width: 220px; margin: 0 auto; } .donut-chart > .donut-legend { flex: none; } }

.chart-note { margin: 0.35rem 0 0.25rem; color: var(--pico-muted-color); }
.chart-key { list-style: none; display: flex; flex-wrap: wrap; gap: 0.35rem 1rem; margin: 0 0 0.6rem; padding: 0; font-size: 0.85em; color: var(--pico-muted-color); }
.chart-key li { list-style: none; display: inline-flex; align-items: center; gap: 0.4rem; margin: 0; padding: 0; }
.chart-key li::marker { content: ''; }
.chart-value-wide { width: auto; min-width: 3rem; white-space: nowrap; }
.chart-extra { color: var(--pico-muted-color); font-size: 0.85em; }
.chart-row:not(a) { cursor: default; }
.chart-bar-step-4 { background: color-mix(in srgb, var(--chart-bar-category) 20%, var(--pico-card-background-color)); }

/* categorical series and the tiers — CLASSES onto TOKENS, once */
.chart-cat-1 { background: var(--chart-cat-1); } .chart-cat-2 { background: var(--chart-cat-2); }
.chart-cat-3 { background: var(--chart-cat-3); } .chart-cat-4 { background: var(--chart-cat-4); }
.chart-cat-5 { background: var(--chart-cat-5); } .chart-cat-6 { background: var(--chart-cat-6); }
.chart-cat-other { background: var(--chart-cat-other); }
.chart-tier-serious { background: var(--chart-tier-serious); }
.chart-tier-caution { background: var(--chart-tier-caution); }
.chart-tier-ok { background: var(--chart-tier-ok); }

/* stacked bars: the parts sit in the track with the 2px surface gap */
.stack-track { display: flex; gap: 2px; overflow: visible; background: transparent; }
.stack-seg { display: block; height: 100%; position: relative; box-shadow: inset 0 0 0 1px var(--chart-bar-edge, rgba(0, 0, 0, 0.5)); transform-origin: left center; }
.stack-seg:first-child { border-radius: 4px 0 0 4px; }
.stack-seg:last-child { border-radius: 0 4px 4px 0; }
.stack-seg:only-child { border-radius: 4px; }
.stack-seg[data-tip]:hover::after, .stack-seg[data-tip]:focus-visible::after { content: attr(data-tip); position: absolute; left: 50%; bottom: calc(100% + 4px); transform: translateX(-50%); background: var(--pico-color); color: var(--pico-card-background-color); font-size: 0.78rem; line-height: 1.2; padding: 0.3rem 0.55rem; border-radius: 4px; white-space: nowrap; pointer-events: none; z-index: 6; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2); }
.stack-seg:focus-visible { outline: 2px solid var(--pico-primary); outline-offset: 1px; }
/* A part that links to what it counts (Device Manager's Protection, 2026-11-03). */
a.stack-seg:hover { box-shadow: inset 0 0 0 2px var(--pico-color); }

/* The stacked chart's row labels and motion — split out of combined rules that
   stay with the Asset Manager's report-only kinds. */
.stack-row .chart-label { width: 11rem; }
/* a legend's label, in its own inline span (report.ejs says why) */
.chart-key-label { display: inline; }
@media (prefers-reduced-motion: no-preference) {
  html:not([data-motion="off"]) .stacked-chart .stack-seg { animation: chart-grow 480ms cubic-bezier(0.2, 0.7, 0.2, 1) both; animation-delay: calc(var(--i, 0) * 40ms); }
}
@media (max-width: 640px) {
  .stack-row .chart-label { width: 5.5rem; }
}
