/* SAB Portal — How one measured value is drawn. State pills, last contact, capture time,
 * freshness, and the absence of a value — which is a value.
 *
 * These are the smallest components in the portal and the most reused: a state
 * pill is the same pill in a table, on a detail page and in the map's legend.
 * Changing one here changes it everywhere, which is the point.
 *
 * One of the files listed in layers.css; read that first. Every rule below
 * is in the `app` cascade layer, so it beats Pico without needing to be
 * more specific than Pico. Sizes come from tokens.css and nowhere else. */

@layer app {

/* --- State pills -------------------------------------------------------- */

.sab-pill {
  display: inline-block;
  padding: 0.05rem var(--sab-gap);
  border-radius: 1rem;
  font-size: var(--sab-text-small);
  font-weight: var(--sab-weight-strong);
  white-space: nowrap;
}

.sab-state-online { color: var(--sab-online); background: var(--sab-online-bg); }
.sab-state-silent { color: var(--sab-silent); background: var(--sab-silent-bg); }
.sab-state-never  { color: var(--sab-never);  background: var(--sab-never-bg); }

/* A dot in the state's own colour, for the places that carry the state on one
 * line with the words rather than in a pill of its own.
 *
 * It wears the same `.sab-state-*` class the pill does, so the three colours
 * are defined once, above; this rule comes after them and spends the pill's
 * pale ground on the dot itself. Never alone — the word beside it is what a
 * reader in greyscale, or a screen reader, actually reads. */
.sab-dot {
  display: inline-block;
  width: 0.55rem;
  height: 0.55rem;
  border-radius: 50%;
  background: currentColor;
  flex: none;
}

/* --- Last contact -------------------------------------------------------
 *
 * One line: the state as a dot and a word, then how long ago. The exact
 * moment is a second question and opens on a click, so the line stays a line —
 * see portal/templates/portal/components/last_contact.html. */
.sab-contact {
  position: relative;
  display: inline-block;
  font-size: var(--sab-text-body);
}

.sab-contact > summary,
.sab-contact-line {
  display: inline-flex;
  align-items: baseline;
  gap: var(--sab-gap-tight);
  /* One line, always. "Reporting yesterday" broken across two is read as two
   * facts, and the dotted underline under half a word looks like damage. */
  white-space: nowrap;
}

.sab-contact > summary {
  cursor: pointer;
  /* Three ways to say the same thing, because the disclosure triangle is drawn
   * by a different pseudo-element in each engine and a stray arrow beside a
   * status dot is a second mark for the reader to interpret. The word carries
   * the affordance instead. */
  list-style: none;
}

.sab-contact > summary::-webkit-details-marker {
  display: none;
}

.sab-contact > summary::marker {
  content: "";
}

/* Pico's own chevron, the fourth way. */
.sab-contact > summary::after {
  display: none;
}

.sab-contact-word {
  font-weight: var(--sab-weight-medium);
  color: var(--sab-ink);
}

/* Between the state and its age, because "reporting" and "yesterday" are two
 * answers and not one phrase. Drawn here rather than written into the
 * component: it is punctuation, and punctuation is not something a translator
 * should be handed. On the word and not on the age, so that the age's dotted
 * underline — the thing that says it opens — stops where the age does. */
.sab-contact > summary .sab-contact-word::after {
  content: "·";
  margin-left: var(--sab-gap-tight);
  color: var(--pico-muted-color);
  font-weight: var(--sab-weight-normal);
}

/* The dot is round and small, so it sits on the text's middle rather than on
 * its baseline. */
.sab-contact .sab-dot {
  align-self: center;
}

/* Dotted, because it is the part that opens: an affordance nobody can see is
 * no affordance, and a touch reader never hovers. */
.sab-contact-age {
  border-bottom: var(--sab-hairline) dotted currentColor;
}

.sab-contact[open] > summary .sab-contact-age,
.sab-contact > summary:hover .sab-contact-age {
  border-bottom-style: solid;
}

/* The exact moment, lifted off the page the way every other panel a reader
 * opened is. Absolutely placed so that opening it does not push the two
 * columns of the card apart. */
.sab-contact-exact {
  position: absolute;
  top: 100%;
  left: 0;
  z-index: var(--sab-layer-panel);
  margin: var(--sab-gap-tight) 0 0;
  padding: var(--sab-gap-tight) var(--sab-gap);
  border: var(--sab-hairline) solid var(--sab-rule);
  border-radius: var(--sab-radius);
  background: var(--pico-card-background-color);
  box-shadow: var(--sab-panel-shadow);
  font-size: var(--sab-text-small);
  color: var(--pico-muted-color);
  white-space: nowrap;
}

.sab-contact-exact time {
  color: var(--sab-ink);
}

/* --- Capture time ------------------------------------------------------- */

/* When a box listens, on the card for the box. The clock is beside the words
 * and never instead of them. */
.sab-listen {
  display: flex;
  align-items: center;
  gap: var(--sab-gap-tight);
  margin: 0;
  font-size: var(--sab-text-meta);
  color: var(--pico-muted-color);
  white-space: nowrap;
}

.sab-listen-icon {
  width: 0.85rem;
  height: 0.85rem;
  flex: none;
}

.sab-listen .sab-mono {
  color: var(--sab-ink);
}

/* --- Freshness ---------------------------------------------------------- */

.sab-freshness-fresh  { color: var(--sab-fresh); }
.sab-freshness-ageing { color: var(--sab-ageing); }
.sab-freshness-stale  { color: var(--sab-stale); }
.sab-freshness-future { color: var(--sab-future); font-weight: var(--sab-weight-strong); }

/* --- Absent values ------------------------------------------------------ */

/* Italic, muted, and always words — never an empty cell. An empty cell is a
 * failure to say that the value is missing; "length unknown" is a fact. */
.sab-absent {
  color: var(--sab-absent);
  font-style: italic;
}

}
