/* 04-dashboard.css. What a dashboard is built out of: tiles, coverage lines, charts, the
   ring and its key, the print block, cards, the page header, tabs, the gaps strip,
   the status list and the reconciliation block. */

/* ---------- Dashboard ---------- */
.sample {
  background: #fdf6e3; border-left: 4px solid var(--warn);
  padding: 0.6rem 0.8rem; border-radius: 4px; color: var(--warn);
}
/* Was 0.95rem uppercase muted, so a chart's own title rendered smaller and
   lighter than the caption beneath it. */
h3 { font-size: var(--step-0); margin: 1.5rem 0 0.5rem; color: var(--navy); font-weight: 600; }

.tiles { display: flex; flex-wrap: wrap; gap: 1.5rem; margin: 0.5rem 0 0.5rem; }
.tile { min-width: 10rem; }
.tile-label { display: block; font-size: var(--step--2); color: var(--muted); }
.tile-value { display: block; font-size: var(--step-2); font-weight: 600; line-height: 1.2; }
.tile-note { display: block; font-size: var(--step--2); color: var(--muted); }
/* Direction is stated in the text (+/-), never by colour alone. */
.tile-value.up { color: var(--emerald); }
.tile-value.down { color: var(--danger); }

/* A real number built from a set that is not whole yet. It stays full tile
   size and full colour on purpose: shrinking or greying it would say this
   figure matters less, and it does not, it is exactly as read-aloud-real as
   any other tile, just not yet finished. The signal is a shape instead of a
   colour, a dashed underline in the same language .recon-incomplete already
   uses for "not the whole story," so it survives a black-and-white photocopy
   carried into the Monday meeting the way a greyed number would not. */
.tile-value.partial {
  border-bottom: 3px dashed var(--field);
  padding-bottom: 0.05em;
}

/* The same fact as the number it sits beside, never a footnote about it: one
   step down from body and never italic, because italic muted is the language
   .tile-empty and .chart .missing already spend on "nothing here yet," and
   this is the opposite of nothing, it is what was actually written down. It
   appears inside a tile's .tile-note, inside a chart's own <h3>, and in plain
   body copy, so the size is pinned to a token instead of being left to
   inherit three different parent sizes in those three places. */
.coverage {
  font-size: var(--step--1);
  font-weight: 400;
  font-style: normal;
  color: var(--muted);
}

.chart { width: 100%; height: auto; display: block; overflow: visible; }
.chart .grid { stroke: #e2ddce; stroke-width: 1; }
.chart .axis { stroke: #c4bda8; stroke-width: 1; }
.chart .tick { fill: var(--muted); font-size: 13px; }
.chart .pointlabel { fill: var(--ink); font-size: 13px; font-weight: 600; }
.chart .barlabel { fill: var(--ink); font-size: 14px; }
.chart .barvalue { fill: var(--ink); font-size: 14px; font-weight: 600; }
.chart .missing { fill: var(--muted); font-size: 14px; font-style: italic; }

/* What was entered for a period the line will not draw a real point for yet.
   fill: none instead of the series colour lets whatever the circle sits over
   show through it, so it reads as "there is something here and it is not one
   of the real points" at a glance, which is exactly what the template's own
   comment on this circle says it needs to do. Same r="4.5" as the solid
   points, set in the markup rather than here, so size never has to carry the
   difference either; only the hollow fill and this stroke width do. */
.chart .partial {
  fill: none;
  stroke-width: 2;
}
.chart.bars { max-width: 100%; }

/* The average, drawn across the plot. One shade darker than the grid so it
   reads as a statement rather than as another gridline, and SOLID: a dashed
   rule on a chart reads as a projection or a threshold, and this is neither.
   It is named in a legend above the chart rather than labelled inside it,
   because the average sits by definition near the data and a label at the
   right-hand end printed straight through the last point's own value. */
.chart .avgrule { stroke: #9a9482; stroke-width: 1.5; }
.ruleswatch { width: 18px; height: 0; border-top: 1.5px solid #9a9482;
              display: inline-block; vertical-align: middle; }
.legenditem { display: inline-flex; align-items: center; gap: 0.4rem;
              font-size: var(--step--1); color: var(--muted); }

/* The ring, and the key that carries its numbers. The key is not decoration:
   a colour with no name beside it is identity by colour alone, which nobody
   reading in greyscale or printing this page can use, and the values in it are
   how the chart is read without hovering anything. */
.donutwrap { display: flex; flex-wrap: wrap; align-items: center;
             gap: 1.5rem 2rem; margin: 0.4rem 0 0.6rem; }
.chart.donut { width: auto; max-height: 15rem; flex: 0 0 auto; }
.chart .slicelabel { fill: var(--ink); font-size: 13px; font-weight: 600; }
.chart .donuttotal { fill: var(--ink); font-size: 26px; font-weight: 700; }
.chart .donutfoot { fill: var(--muted); font-size: 13px; }
.donutkey { list-style: none; margin: 0; padding: 0; flex: 1 1 16rem;
            min-width: 15rem; max-width: 26rem; }
.donutkey li { display: grid; grid-template-columns: 12px 1fr auto auto;
               align-items: center; gap: 0 0.6rem;
               padding: 0.28rem 0; border-bottom: 1px solid var(--line);
               font-size: var(--step--1); }
.donutkey li:last-child { border-bottom: 0; }
.donutkey .keyname { color: var(--ink); }
.donutkey .keyvalue { color: var(--ink); font-weight: 600;
                      font-variant-numeric: tabular-nums; }
.donutkey .keyshare { color: var(--muted); min-width: 2.6rem; text-align: right;
                      font-variant-numeric: tabular-nums; }

.legend { display: flex; gap: 1.2rem; margin: 0 0 0.3rem; }
.key { display: inline-flex; align-items: center; gap: 0.4rem;
       font-size: var(--step--1); color: var(--muted); }
.swatch { width: 12px; height: 12px; border-radius: 3px; display: inline-block; }

/* One print block. The previous pair hid every `form` with an unqualified
   selector, and the weekend grid, the sacraments grid and every person block
   each live inside one, so printing those screens produced a heading and a
   blank page, in an app whose premise is that paper is the backup.
   Hide the controls and the chrome, never the container. */
@media print {
  @page { margin: 14mm; }

  .bar nav, .button, button,
  form.inline, form.periodpick,
  .flashes, .nav-weekends { display: none; }

  /* .crumbs is deliberately NOT in the list above. It is a nav element, and the
     rule that hides navigation is scoped to `.bar nav` for that reason. On
     paper the trail is the only thing naming which weekend or which metric the
     sheet in somebody's hand belongs to, and a sheet carried into a meeting
     with no name on it is the failure this app exists to prevent. */

  /* Entered values print; empty cells print empty. Deliberately NOT ruled
     underlines: that would be a second blank count sheet competing with the
     real paper form, and D10 records that the sheet as drawn is the sheet. */
  table.entry input, table.entry textarea, label.block { display: none; }

  body { background: #fff; }
  .card { border: 1px solid #999; padding: 0.6rem; break-inside: avoid; }
  .tiles { gap: 1rem; }
  h2, h3 { break-after: avoid; }

  /* Survive a photocopy. */
  th, td { border-bottom-color: #999; }
  .chart .grid { stroke: #bbb; }

  /* A sample-data banner must never print looking like ordinary content. */
  .sample { print-color-adjust: exact; -webkit-print-color-adjust: exact; }
}

/* Column identity on the entry grid. The two columns are structurally
   identical and tab order is row-major, so five attendance numbers typed
   tab-by-tab could land in the offertory column with nothing to catch it. */
/* THE GRID IS AS WIDE AS THE NUMBERS IN IT, AND THE INPUTS FILL THEIR CELLS.
   `table { width: 100% }` put this sheet across the whole 1,476px page, so on
   one_mass.html an 81px box sat in a 1,100px cell: the widest gap between a box
   and its container anywhere in the app. Capping the table is the half that
   matters, because widening the inputs alone would have made five 300px boxes
   for three-digit numbers.
   The per-column widths are set here rather than left to the browser so the
   count and money columns are the same on every screen that uses this grid,
   which is what lets somebody check a column of typing against paper. The
   narrow-screen block at the end of this file overrides all three and still
   wins on source order. */
table.entry { max-width: 46rem; }
table.entry td.count, table.entry th.count { width: 7rem; }
table.entry td.money, table.entry th.money { width: 9rem; }
table.entry td.count input { width: 100%; }
/* The money cell holds a "$" and then the box. At width:100% the box claimed
   the whole cell and pushed the dollar sign onto its own line above it, so an
   empty offertory row read as two things stacked rather than one field. The
   calc leaves exactly the dollar's own width behind, and nowrap stops the pair
   being split at the space between them. The narrow-screen block at the end of
   this file hides the dollar outright, so it sets a plain 100% there. */
table.entry td.money { white-space: nowrap; }
table.entry td.money input { width: calc(100% - 1.1rem); }


table.entry .dollar { color: var(--muted); margin-right: 0.15rem; }
/* A half-filled sheet should not go ragged where an input became text. */
table.entry .recorded {
  display: inline-block; min-width: 4.5rem;
  padding: 0.4rem 0.5rem; border: 1px solid transparent;
}
table.entry th[scope="row"] {
  font-size: var(--step-0); text-transform: none; letter-spacing: 0;
  color: var(--ink); font-weight: 400; text-align: left; white-space: nowrap;
}
.visually-hidden {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}

/* Cards that sit beside each other. A card holding a heading, one status line
   and one button does not need 1,150px, and a column of them left the right two
   thirds of This Week empty. Eric, 2026-08-22: "you could land a plane on that
   white space on the right."
   auto-fit rather than a fixed column count, so this is one rule for every
   width and there is no breakpoint to keep in step with the content: three
   across on a wide screen, two on a laptop, one on a phone, decided by the
   21rem floor rather than by a media query. align-items:start so a card with a
   longer status line does not stretch its neighbour to match. */
.cardgrid {
  display: grid; align-items: start; gap: 1rem;
  /* min(21rem, 100%), not a bare 21rem. A bare floor is a HARD minimum: on a
     390px phone the content column is about 318px and the track stayed 378px,
     so This Week scrolled sideways. check_widths.py caught it the same run.
     The min() lets the track collapse to the container when the container is
     the smaller of the two, which is the whole point of a floor that is
     supposed to be about content rather than about the viewport. */
  /* 30rem, not 21rem. At 21 the four status cards on This Week came out
     three across with a lone fourth stranded on its own row, and each card was
     narrow enough that the 62ch prose cap inside it stopped well short of the
     card's edge, which is what Eric kept pointing at: "the test still gets cut
     before the end of the box." Two across makes 2x2 with no orphan, and at
     roughly 700px a 62ch line reaches the padding. The min() keeps a phone at
     one column. */
  grid-template-columns: repeat(auto-fit, minmax(min(30rem, 100%), 1fr));
  margin-bottom: 1rem;
}
.cardgrid > .card { margin-bottom: 0; height: 100%; }

/* A headline figure with its qualifying sentences beside it rather than under
   it. The figure is the thing somebody reads out; the sentences are what stops
   it being read out wrong, so they belong on the same line of sight. Wraps to
   stacked below about 40rem of card, where side-by-side would squeeze both. */
.figurerow {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.3rem 2rem;
}
.figurerow > .total { margin: 0; flex: 0 0 auto; }
.figurenotes { flex: 1 1 26rem; min-width: 0; }
.figurenotes > p { margin: 0 0 0.45rem; }
.figurenotes > p:last-child { margin-bottom: 0; }

/* A link inside a warning inherits the warning's colour. The type selector on
   `a` won it otherwise, so "Extend it" rendered emerald in the middle of an
   orange sentence and read as a different kind of thing from the words either
   side of it. Underlined, because colour is then no longer what marks it. */
.warn a, .warn-inline a { color: inherit; text-decoration: underline; }
.warn a:hover, .warn a:focus-visible { color: var(--navy); }

/* The page header row: what you are looking at on the left, which weekend it
   covers pushed to the right margin. Both facts used to stack on the left under
   a heading reading "SUPER-DASH", which named nothing and sat two inches from a
   sidebar already saying "PLT Dashboard". Eric, 2026-08-22: "the date can go
   right justified. The words SUPER-DASH kind of feels like an orphan."
   Baseline-aligned rather than centred, so the date sits on the same line the
   heading sits on rather than floating in the middle of its cap height. */
.pagehead {
  display: flex; flex-wrap: wrap; align-items: baseline;
  justify-content: space-between; gap: 0.15rem 1.5rem; margin: 0 0 0.75rem;
}
.pagehead h1 { margin: 0; }
.pagehead .lede { margin: 0; text-align: right; }
.pagemeta {
  display: flex; flex-direction: column; align-items: flex-end; gap: 0.3rem;
}

/* How far back the page is looking. Links, not a <select>, for the same reason
   the tabs are links: a range becomes part of the address, so a particular view
   can be sent to somebody and the back button works. No JavaScript anywhere on
   this page and none added here. */
.rangepick { display: flex; flex-wrap: wrap; align-items: center; gap: 0.15rem; }
.rangelabel {
  font-size: var(--step--2); text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--muted); margin-right: 0.4rem;
}
.rangepick a {
  padding: 0.28rem 0.6rem; border-radius: 4px; text-decoration: none;
  color: var(--muted); font-weight: 600; font-size: var(--step--1);
  border: 1px solid transparent; font-variant-numeric: tabular-nums;
}
.rangepick a:hover { color: var(--navy); background: #fff; }
.rangepick a[aria-current="true"] {
  background: #fff; color: var(--navy); border-color: var(--line);
}
/* The fiscal year is not a weekend count, so it does not sit under the
   "weekends" label with the four that are. */
.rangesplit {
  width: 1px; height: 1.1rem; background: var(--line); margin: 0 0.45rem;
}

/* Year over year, in a sentence, under the tiles it qualifies. Not a tile: a
   tile is one figure, and this one only means anything with its two windows and
   its caveat attached. */
.yoy {
  margin: 0 0 0.9rem; font-size: var(--step--1); color: var(--ink);
  max-width: 70ch;
}
.yoy .warn { display: inline; }

@media (max-width: 44rem) {
  /* Opposite nothing once the header wraps, so it stops reading as aligned to
     something off the right of the screen. */
  .pagemeta { align-items: flex-start; }
  .pagehead .lede { text-align: left; }
}
/* Wrapped onto its own line on a narrow screen, the date is not opposite
   anything, and a right-aligned orphan reads as a mistake. */
@media (max-width: 34rem) {
  .pagehead .lede { text-align: left; }
}

/* Tabs. One subject at a time, because this is a collector before it is an
   integrator: attendance, giving and work orders come from different places and
   reading them stacked in one column tells you nothing their own page does not.
   Links, not JavaScript, so a tab is a URL somebody can send to somebody else. */
.tabs {
  display: flex; flex-wrap: wrap; gap: 0.25rem;
  margin: 0 0 1.25rem; border-bottom: 2px solid var(--line);
}
.tabs a {
  padding: 0.6rem 0.95rem; text-decoration: none; color: var(--muted);
  font-weight: 600; border-bottom: 3px solid transparent; margin-bottom: -2px;
  min-height: 44px; display: flex; align-items: center;
}
.tabs a:hover { color: var(--ink); }
.tabs a[aria-current="page"] { color: var(--navy); border-bottom-color: var(--emerald); }

/* Completeness sits above the tabs and is never inside one. A gap the reader
   has to click a tab to discover is a gap that gets read aloud as a real
   number. */
.gapstrip {
  margin: 0 0 1rem; padding: 0.7rem 0.9rem;
  border-left: 4px solid var(--warn); background: #fdf6ec;
  border-radius: 0 6px 6px 0; font-size: var(--step--1);
}
.gapstrip.ok { border-left-color: var(--ok); background: #eef4f0; }
.gapstrip a { color: var(--emerald); }

/* A quiet inline action, not a second filled button beside the weekend link:
   the banner already reads as urgent from its warm ground and its warn-
   coloured rule, and a solid emerald button here would be the loudest thing
   in it for the smallest decision on the page. Coloured and underlined like
   the weekend link it sits next to instead of styled like button/.button.
   The warm ground it has to sit on is .gapstrip's own #fdf6ec just above,
   lighter than parchment, so emerald's measured 8.62:1 against parchment only
   gets better against it. min-height is a belt-and-suspenders 24px floor;
   this class does not touch display, so the print rule that hides every other
   button on the page (`button { display: none; }`, above) still hides this
   one without a fight over specificity. */
/* The gaps list, and the actions that live on it. A weekend, what it is short,
   and the one button that settles it, on one line. The form wrapper has to be
   inline or the button drops to a line of its own: a form is a block element,
   and the first version of this strip printed every action underneath its
   weekend with the separators stranded on lines between them. */
.gaplist { list-style: none; margin: 0.35rem 0 0; padding: 0; }
.gaplist li {
  display: flex; flex-wrap: wrap; align-items: baseline;
  gap: 0.15rem 0.55rem; padding: 0.2rem 0;
}
.gapform { display: inline; margin: 0; }

/* The settled strip sits under the gaps banner and must not look like another
   alarm: these weekends are answered, not outstanding. Quiet ground, no
   coloured edge, and it only exists at all so that writing a weekend off is
   never a one-way door. */
.settledstrip {
  margin: 0 0 1.1rem; padding: 0.7rem 0.9rem;
  border-left: 3px solid var(--line); background: transparent;
}
.settledstrip p { margin: 0; color: var(--muted); font-size: var(--step--1); }

.gapaction {
  background: none;
  border: 0;
  padding: 0.15rem 0.35rem;
  min-height: 24px;
  color: var(--emerald);
  font: inherit;
  text-decoration: underline;
  cursor: pointer;
}
.gapaction:hover { color: var(--navy); }

/* The read views get a wider page than the entry forms. A 60rem column on a
   1440 screen left a third of the width empty and pushed the charts into a
   ribbon. */
body.wide main { width: 80vw; max-width: 80vw; }

@media (max-width: 40rem) {
  .tabs { gap: 0; }
  .tabs a { padding: 0.6rem 0.7rem; font-size: var(--step--1); }
}

/* On a phone an SVG that scales to the viewport takes its axis labels down to
   about four pixels, which is a chart nobody can read pretending to be one. Hold
   the chart at a legible width and let it scroll inside its own card instead.
   The page itself never scrolls sideways; only the chart does. */
@media (max-width: 46rem) {
  .card { overflow-x: auto; }
  /* The long line chart genuinely needs the room: 52 points in 356px is a
     smudge. The per-Mass bars do not, and holding them wide cut the value off
     mid-digit, so 354 rendered as "35". A truncated number that still looks
     like a number is the one thing this page must never do. */
  .chart { min-width: 32rem; }
  .chart.bars { min-width: 0; }
  .chart.donut { min-width: 0; max-height: 13rem; }
  .donutkey { min-width: 0; }
}

/* What the team is looking at, in a sentence. */
.blurb { margin: 0 0 1rem; color: var(--muted); max-width: 46rem; }

/* Where the numbers come from. Folded away by default because it is reference,
   opened automatically when something is out of date, because that is the one
   time the team needs to see it without being told to look. */
.status { margin: 0 0 1.25rem; border: 1px solid var(--line); border-radius: 8px;
          background: #fff; }
.status > summary {
  cursor: pointer; padding: 0.7rem 0.9rem; font-weight: 600; color: var(--navy);
  display: flex; align-items: center; gap: 0.6rem; min-height: 44px;
}
.status-flag {
  font-weight: 600; font-size: var(--step--2); color: #fff; background: var(--warn);
  padding: 0.1rem 0.5rem; border-radius: 999px;
}
.status-list { list-style: none; margin: 0; padding: 0 0.9rem 0.9rem; }
.status-list li {
  display: grid; gap: 0.15rem; padding: 0.7rem 0; border-top: 1px solid var(--line);
}
.status-list li.is-stale { border-left: 3px solid var(--warn); padding-left: 0.6rem; }
.status-what { font-weight: 600; }
.status-how {
  justify-self: start; font-size: var(--step--2); font-weight: 600; letter-spacing: 0.02em;
  text-transform: uppercase; padding: 0.1rem 0.45rem; border-radius: 4px;
  border: 1px solid var(--line); color: var(--muted);
}
.status-how.auto   { color: var(--emerald); border-color: var(--emerald); }
.status-how.manual { color: var(--navy);    border-color: var(--field); }
.status-how.sample { color: var(--warn);    border-color: var(--warn); }

/* A slot somebody has recorded as never going to be counted, not a slot
   nobody has gotten to yet. .tile-empty and .chart .missing are muted italic
   for "nothing here" and this needs to read as the opposite of that: a person
   looked, and decided. Deliberately not one of the ledger's pills either:
   those three colours are a good/caution/bad verdict on a number (active,
   superseded, voided), and a closed gap carries no verdict at all, so
   borrowing one of them would claim a judgement this status does not make.
   Square corners instead of a pill, navy instead of a status colour, the same
   shape .status-how.manual already uses just above for "a plain fact, no
   direction to it." */
.not-counted {
  display: inline-block;
  padding: 0.1rem 0.45rem;
  border: 1px solid var(--field);
  border-radius: 4px;
  color: var(--navy);
  font-weight: 600;
  font-size: var(--step--2);
  letter-spacing: 0.02em;
  text-transform: uppercase;
  font-style: normal;
  white-space: nowrap;
}
.status-when { font-size: var(--step--1); }
.status-detail { font-size: var(--step--1); color: var(--muted); }
/* Two classes, because one loses. `.warn` is declared near the top of this file
   and `.status-detail` after it, so a bare `.warn` on a status line was
   overruled by the muted colour and the sentence saying a source has gone quiet
   read exactly like the sentence saying it has not. */
.status-detail.warn { color: var(--warn); }

/* The hover readout, on anything inside a chart that answers for a number: the
   line charts' hit bands, a donut slice, a bar, a stacked segment. The cursor
   is the only thing on the page that says a shape is worth pointing at before
   it has been pointed at. */
.hit { cursor: pointer; }
.hit:focus { outline: none; }
.hit:focus-visible { outline: 2px solid var(--emerald); outline-offset: 2px; }
.readout {
  position: absolute; z-index: 20; pointer-events: none;
  background: var(--navy); color: #fff; padding: 0.35rem 0.6rem;
  border-radius: 6px; font-size: var(--step--1); white-space: nowrap;
  box-shadow: 0 2px 8px rgba(20, 32, 46, 0.25);
}

/* The reconciliation block. The disagreement is the product here, so a
   divergence is a different shape and not a redder version of the same row. */
.recon { list-style: none; margin: 0 0 1rem; padding: 0; display: grid; gap: 0.75rem; }
.recon li {
  display: grid; gap: 0.3rem; padding: 0.85rem 1rem;
  border: 1px solid var(--line); border-radius: 8px; background: var(--parchment);
}
.recon li.recon-agrees { border-left: 4px solid var(--ok); }
.recon li.recon-diverges { border-left: 4px solid var(--danger); background: #fdf1f0; }
.recon li.recon-incomplete { border-left: 4px dashed var(--field); }
/* Apart, but not a fault: our side was not an exact count, so the two are not
   being held to the same standard. Deliberately NOT the danger red, and
   deliberately not the agreeing green either. The sentence carries the meaning;
   these pages print in black and white. */
.recon li.recon-not_comparable { border-left: 4px solid var(--warn); background: #fdf6ec; }
.recon-label { font-weight: 700; color: var(--navy); }
.recon-pair { display: flex; align-items: baseline; gap: 0.9rem; flex-wrap: wrap; }
.recon-side { display: flex; flex-direction: column; }
.recon-cap {
  font-size: var(--step--2); text-transform: uppercase; letter-spacing: 0.04em;
  color: var(--muted); font-weight: 600;
}
.recon-val { font-size: var(--step-2); font-weight: 700; font-variant-numeric: tabular-nums; }
.recon-vs { color: var(--muted); font-size: var(--step--1); align-self: center; }
.recon-gap { font-size: var(--step--1); }
.recon-diverges .recon-gap strong { color: var(--danger); }
.recon-says { font-size: var(--step--1); }
.recon-diverges .recon-says { font-weight: 600; }
.recon-note { font-size: var(--step--1); color: var(--muted); }

/* Nothing drawn inside a chart steals the hover except the hit bands, and now
   the partial markers: a weekend with only a partial figure has no entry in
   chart.points, so it never gets a hit band drawn for it at all, and its own
   native <title> is the only readout it will ever have. The selective point
   labels and the axis ticks sit on top of a few bands, and where they did the
   readout showed nothing at all for that week.

   THE SECOND LINE IS WHAT MAKES A SHAPE ANSWERABLE, and the first line will
   silently kill any shape that does not carry it. The donut arcs are the
   cautionary tale: every ring on the dashboard was drawn as a path with a
   <title> written for it, the blanket `.chart path` rule above meant the arcs
   never received a pointer event, and so not one of those tooltips had fired
   since the day this rule was written. Nothing looked wrong in the markup and
   nothing failed in the suite; it was only visible to somebody hovering it.
   `.chart .hit` outranks `.chart path` on specificity, so a slice opts back in
   by carrying the hit class the readout keys on anyway, and one class both
   restores the pointer and wires up the readout box.

   So: anything inside a chart that is meant to answer a person needs the .hit
   class, data-when, data-value, tabindex and an aria-label, together. Half of
   that set is a shape that looks interactive and says nothing. */
.chart text, .chart .grid, .chart .axis, .chart path, .chart circle { pointer-events: none; }
.chart .hit, .chart .partial { pointer-events: all; }

/* The stall tile. Not a redder version of the other tiles: this is the one
   figure the project was started over, and it earns a shape of its own. */
.tile.alarm {
  border-left: 4px solid var(--danger); padding-left: 0.7rem;
  background: #fdf1f0; border-radius: 0 6px 6px 0;
}
.tile.alarm .tile-value { color: var(--danger); }

