/* The app's status glyph -- one of the two icon systems, the other being the
   SVG line icons for chrome (ApplicationHelper::NAV_ICONS / HEADER_ICONS,
   styled where their chrome lives). The glyph itself is a text character from
   DashboardHelper::STATUS_ICONS -- bar the one snooze exception below; what
   this file draws is the ring it sits in, without which the characters
   visibly misalign beside text.

   Everything the icon owns lives here: the ring, its loading state, every
   size a call site asks for and the two filled verdict variants. Page
   sections elsewhere keep only their own layout.

   ON LOAD ORDER. `stylesheet_link_tag :app` bundles this whole directory and
   the order between files is not ours to choose, so nothing here may depend
   on running before or after application.css. Two rules follow from that:

   - the base DECLARES no --status-icon-size, it READS one with a fallback.
     A call-site rule setting the prop therefore always wins, whatever file
     it is in and whatever its specificity (signup/analyses#show sets it on
     its stacked spinner, from application.css).
   - anything that has to beat a plain property of the base -- a font-size, a
     fill -- lives in this file, below it, where the order IS ours. */

.status-badge-icon,
.scan-glyph {
  /* Derived, not configured: one size drives the box, the ring and the
     glyph together, so a call site sets --status-icon-size alone. */
  --status-icon-ring: max(2px, calc(var(--status-icon-size, 1.4rem) / 9));
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--status-icon-size, 1.4rem);
  height: var(--status-icon-size, 1.4rem);
  border: var(--status-icon-ring) solid var(--tone);
  border-radius: 999px;
  color: var(--tone);
  /* The page's own face, wherever the mark is drawn: a <button> mark (the
     uptime report's grades) would otherwise take the browser's control
     font and set ✓ ! ✕ in a different typeface from every other mark. */
  font-family: inherit;
  font-size: calc(var(--status-icon-size, 1.4rem) * 0.55);
  font-weight: 700;
  line-height: 1;
  flex-shrink: 0;
}

/* The snooze mark is the one glyph that is drawn rather than typed
   (ConcernsHelper::SNOOZE_GLYPH), because no text character says "sleeping"
   without arriving as a colour emoji -- which ignores --tone and brings its
   own metrics beside the ✓ it lines up with. currentColor on the FILL is
   what makes it a tone glyph like the rest; it is solid because every
   character it queues up with is.

   It takes its size from the ring's font-size rather than from
   --status-icon-size, so it scales with every call site for free and needs no
   size of its own in the list below. The 0.95 is optical: a solid shape
   carries more weight than a character in the same box, so it comes in a
   touch under the full em to sit level with ✓ and ✗. */
.status-glyph-svg {
  display: block;
  width: 0.95em;
  height: 0.95em;
  flex-shrink: 0;
}

/* Still being fetched: two quadrants of the same ring, turning. The rotation
   is on ::before and not on the badge, so the arc turns while a glyph in the
   middle sits still -- spinning the badge would spin its glyph with it.

   Call sites pass NO glyph while a badge turns: the ring is the news, and a
   `…` inside it says the same thing twice. The centring above is kept for
   the case where some other glyph is worth saying during a wait -- nothing
   has one today.

   A Check now over a verdict already held (concern.md B-19) turns the same
   way, as --rechecking: the badge's own ring turns and its mark stays put.

   The badge drops its own border to zero width rather than merely going
   transparent, which (box-sizing is border-box) leaves the outer box the
   same size and makes the padding box the border box. `inset: 0` then puts
   the arc exactly where the ring was: insetting a still-bordered badge by
   the ring width instead misses by up to a pixel, because the inset uses the
   unrounded --status-icon-ring while the border renders rounded.

   The rows reveal (application.css, ROWS REVEAL) lands each row still
   checking, so its mark wears this same arc for a moment, on ::after. It
   says there what it changes -- its grey, its place outside the mark's own
   ring, when the arc goes -- and :where() keeps this entry at no weight, so
   that rule wins whatever order the two files load in. */
.status-badge-icon--loading,
.status-badge-icon--rechecking {
  position: relative;
  border-width: 0;
}
.status-badge-icon--loading::before,
.status-badge-icon--rechecking::before,
:where(.resource-tabs--reveals:not([data-revealed])
  .resource-panel:not([hidden]) > .row-stack > .resource-section > .row-list > .row
  > .row-top > .row-glyph)::after {
  content: "";
  position: absolute;
  inset: 0;
  border: var(--status-icon-ring) solid transparent;
  border-top-color: var(--tone);
  border-right-color: var(--tone);
  border-radius: 999px;
  animation: status-icon-spin 0.8s linear infinite;
}
@keyframes status-icon-spin {
  to {
    transform: rotate(360deg);
  }
}

/* Asked for reduced motion, the arc stops (application.css), and a still
   part-ring reads as nothing at all. The wait keeps a mark of its own: the
   whole ring, still (accessibility.md B-06, "But not").

   EXCEPT --rechecking, WHOSE RING STOPS DASHED. It keeps its verdict's mark
   inside, so a whole ring around it is exactly a settled badge, and the row
   says ", checking again" only to a screen reader: a sighted User who asked
   for less motion would see no wait at all. Dashed, in tone and at the same
   width, never reads as settled (probe-registration 20, variant D).

   A whole ring is also what a settled badge looks like, so where the ring
   was a row's only sign of the wait (the Dashboard's rows, which name it
   only to a screen reader) the row shows the wait's word beside it: the
   same word the ring is named with, aria-hidden so it is not heard twice.
   A row that already shows a word for the wait, a pill or a sentence, has
   no need of it. */
.status-badge-wait-word {
  display: none;
}
@media (prefers-reduced-motion: reduce) {
  .status-badge-icon--loading::before {
    border-color: var(--tone);
  }
  .status-badge-icon--rechecking::before {
    border-color: var(--tone);
    border-style: dashed;
  }

  .status-badge-wait-word {
    display: inline;
    color: var(--tone);
    font-size: 0.85rem;
    font-weight: 600;
    white-space: nowrap;
  }
}

/* --- The sizes the app asks for. Nothing here sets a width, a font-size or
   a ring: one prop, and the base works the other two out. --- */

.scan-queue-title .scan-glyph {
  --status-icon-size: 1.15rem;
}

.action-card .list .glyph {
  --status-icon-size: 1.3rem;
}

.scan-glyph {
  --status-icon-size: 1.5rem;
}

/* A row's mark is sized through a prop of its own, set on :root and turned
   down by .row--compact below, because the mark's width is also a term in
   application.css's --row-gutter: the gutter reads this same number, so it
   cannot be resized here and left behind there (markup-audit 08). */
:root {
  --row-glyph-size: 2rem;
}

.row-glyph {
  --status-icon-size: var(--row-glyph-size);
  margin-top: 0.1rem;
}

.row-top .row-glyph {
  background: var(--color-surface);

  &.status-badge-icon--loading {
    background: none;
  }
}

/* Not a status: what the row is, a Report's icon or a User's initial, on a
   square of the accent's tint. Here rather than beside .row-top because it has
   to come after the white above. */
.row-top .row-glyph--tile {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: var(--control-place-size);
  height: var(--control-place-size);
  border-radius: var(--radius-sm);
  background: var(--color-accent-bg);
  color: var(--color-accent);
  font-weight: 700;
}

.row.pending .row-glyph--tile {
  background: var(--color-degraded-bg);
  color: var(--color-degraded);
}

.row-top:has(> .row-glyph--tile) {
  align-items: center;
}

/* A live update turned the row to another tone (live_update_shows_change.js):
   one ring goes out from the mark in its new tone. ::after, because the
   turning ring above is ::before. */
.row-glyph[data-changed] {
  position: relative;

  &::after {
    content: "";
    position: absolute;
    inset: 0;
    border: 2px solid var(--tone);
    border-radius: 50%;
    pointer-events: none;
    animation: mark-changed-ring 0.9s ease-out both;
  }
}

@keyframes mark-changed-ring {
  from {
    opacity: 0.55;
    transform: scale(1);
  }

  to {
    opacity: 0;
    transform: scale(1.9);
  }
}

/* The same mark, smaller, on a row that is smaller -- a reading inside a
   rollup's drawer (urls/_source_row's `compact:`). The margin above holds:
   what a compact row changes is one number, not the rule. */
:root {
  --row-compact-glyph-size: 1.5rem;
}

.row--compact {
  --row-glyph-size: var(--row-compact-glyph-size);
}

/* And on every row inside a drawer on a phone, which draws them all compact
   (application.css, after .row--compact). */
@media (max-width: 40rem) {
  .row-drawer .row {
    --row-glyph-size: var(--row-compact-glyph-size);
  }
}

/* --- The two filled ones. A page's verdict, not a row's, so it takes the
   tone ring with the tone's own wash behind the glyph: weight the rows
   deliberately don't carry, without the solid disc's shouting. The glyph
   stays --tone from the base rule -- a reversed white one needs the solid
   fill to sit on. Rows keep the clear middle: at 1.4rem the wash closes up
   behind the glyph and costs more than it adds. --- */

.resource-verdict-glyph {
  --status-icon-size: 3rem;
  background: var(--tone-bg);
  font-size: 1.5rem;
}

.scan-glyph--lg {
  --status-icon-size: 3rem;
  background: var(--tone-bg);
  font-size: 1.5rem;
}

/* Loose in the all-snoozed banner rather than in a ring, so nothing centres
   it: the box is 0.95em against a 1.5 line, and cross-start puts it that half
   line-gap high against the first line of the sentence. */
.row-stack-banner .status-glyph-svg {
  margin-top: 0.275em;
}
