/* EVO TrustGuard — page-sales-metrics.css
 *
 * Owned by:    sales-metrics.html (admin-only Sales Metrics dashboard,
 *              C145-S5)
 * Category:    admin shell page (PERMANENTLY DARK — data-theme="dark" is
 *              pinned statically on <html>; no light variant, no toggle, no
 *              prefers-color-scheme branch. Matches the theme posture of the
 *              four sibling admin pages exactly.)
 * Cascade:     tokens → base → utilities → components → portal-chrome →
 *              shared → shared-themes → page-admin (admin shell layer) → page
 * Edit policy: rules unique to this page only. The shared admin-shell chrome
 *              (.ash-*, including .ash-gate) lives in /css/page-admin.css —
 *              see /css/AGENTS.md "Admin dark-glass shell".
 *
 * Design language: the same dark-glass vocabulary as page-outreach.css /
 * page-sales-pipeline.css — 3G.1 Glass tokens (--tier1-bg / --hairline /
 * --shadow-float / --glass-surface) plus the platform status hues. The funnel
 * strip and the KPI tiles are Tier-1 raised tiles lifted from the .om-stage
 * pattern; the bar rows are a new, deliberately plain primitive (legibility
 * at 375px beats charting polish on an internal tool).
 *
 * Page-scoped custom properties follow the rule-2 --sp-* / --om-* precedent.
 */
:root {
  /* The classified/unclassified dial split is the load-bearing distinction on
     this page, so it gets a colour axis of its own: red-lit for dials that
     carry an outcome, muted-dashed for quick dials that do not. */
  --sm-strong-edge: rgba(229, 52, 46, 0.45);
  --sm-warn-edge:   rgba(245, 158, 11, 0.45);
  --sm-warn-wash:   rgba(245, 158, 11, 0.12);
  /* Bar-track ground. A literal rgba rather than --tier3-tint: that token is
     rgba(30,30,32,0.30) in the dark set, which is all but invisible against
     the dark page and would leave the zero-length bars with no visible
     track at all. Literal-rgba-of-a-token-hue is the sanctioned C103 wash
     pattern. */
  --sm-track-bg:    rgba(255, 255, 255, 0.07);

  /* The at-risk streak edge. Amber, matching the page's existing
     "something needs your attention" hue rather than inventing a third. */
  --sm-risk-edge: rgba(245, 158, 11, 0.55);
}

/* ── App container — sits inside the M8.1 admin shell grid ── */
.sm-app {
  max-width: 860px;
  margin: 0 auto;
  width: 100%;
  padding: var(--space-5) var(--space-5) calc(var(--space-8) + env(safe-area-inset-bottom));
}

/* ── Header ── */
.sm-header {
  display: flex;
  align-items: flex-end;
  gap: var(--space-3-5);
  flex-wrap: wrap;
  margin-bottom: var(--space-5);
}
.sm-header-titles { min-width: 200px; }
.sm-title {
  font-family: 'DM Serif Display', serif;
  font-size: var(--text-3xl);
  color: var(--text);
  margin: 0;
  font-weight: var(--weight-regular);
}
.sm-subtitle {
  color: var(--text-muted);
  font-size: var(--text-md);
  margin: var(--space-1) 0 0;
}

/* ── Section ── */
.sm-section { margin-bottom: var(--space-6); }
.sm-section-title {
  font-family: 'DM Serif Display', serif;
  font-size: var(--text-xl);
  color: var(--text);
  margin: 0;
  font-weight: var(--weight-regular);
}
.sm-section-sub {
  color: var(--text-muted);
  font-size: var(--text-sm);
  margin: 2px 0 var(--space-3-5);
}
.sm-subblock { margin-top: var(--space-4); }
.sm-subtitle-h {
  font-size: var(--text-md);
  font-weight: 600;
  color: var(--text);
  margin: 0;
}
.sm-subnote {
  color: var(--text-muted);
  font-size: var(--text-sm);
  margin: 2px 0 var(--space-2-5);
}
.sm-note {
  color: var(--text-muted);
  font-size: var(--text-sm);
  line-height: 1.5;
  margin: var(--space-3) 0 0;
}
.sm-note strong { color: var(--text); font-weight: 600; }
.sm-foot {
  color: var(--text-disabled);
  font-size: var(--text-xs);
  line-height: 1.5;
  margin: var(--space-6) 0 0;
  padding-top: var(--space-3-5);
  border-top: 1px solid var(--hairline);
}

/* ── Funnel strip — Tier-1 raised tiles (the .om-stage pattern) ── */
.sm-funnel {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: var(--space-2-5);
}
.sm-stage {
  display: flex;
  flex-direction: column;
  gap: 2px;
  text-align: left;
  color: var(--text);
  background: var(--tier1-bg);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-float);
  padding: var(--space-3-5) var(--space-3-5) var(--space-3);
  min-height: 44px;
  min-width: 0;
}
.sm-stage-n {
  font-size: var(--text-2xl);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.sm-stage-l {
  font-size: var(--text-sm);
  color: var(--text-muted);
  overflow-wrap: anywhere;
}
/* An off-vocabulary status is not a normal state — flag it amber rather than
   letting it read like a sixth stage. */
.sm-stage-warn {
  border-color: var(--sm-warn-edge);
  background: linear-gradient(180deg, var(--sm-warn-wash), transparent 70%), var(--glass-surface);
}

/* ── KPI tiles ──
   COMPACT usage-panel format as of C149 (SM-DASH1): small muted label FIRST,
   bold value beneath — the previous big-value / label / routine-caption
   three-liner was oversized relative to the data it carried. The markup
   order is label-then-value (kpi() in the page JS), so no flex reordering is
   needed here. The third line (.sm-kpi-s) is EMITTED only when load-bearing
   (unavailable / truncated / at-risk / needs-more-data on the dashboard;
   the aggregate sections keep their captions) — equal tile heights per row
   come from the GRID's default stretch alignment, never from padding hacks,
   so a tile without it sits flush beside one that has it. */
.sm-kpis {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--space-2-5);
}
.sm-kpi {
  display: flex;
  flex-direction: column;
  gap: 3px;
  color: var(--text);
  background: var(--tier1-bg);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-float);
  padding: var(--space-3) var(--space-3-5);
  min-height: 44px;
  min-width: 0;
}
.sm-kpi-l {
  font-size: var(--text-xs);
  font-weight: 600;
  color: var(--text-muted);
  overflow-wrap: anywhere;
}
.sm-kpi-n {
  font-size: var(--text-xl);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.sm-kpi-s {
  font-size: var(--text-xs);
  color: var(--text-muted);
  line-height: 1.4;
  overflow-wrap: anywhere;
}

/* THE distinction this page exists to make legible. "Dials with an outcome"
   is red-lit and solid; "quick dials (no outcome logged)" is dashed and
   muted. The two are never adjacent-identical tiles, so no one can read them
   as one number at a glance — the difference is carried by border, fill and
   weight, not by a tooltip or a footnote. */
.sm-kpi-strong {
  border-color: var(--sm-strong-edge);
  background: linear-gradient(180deg, var(--red-wash), transparent 70%), var(--glass-surface);
}
.sm-kpi-soft {
  border-style: dashed;
  border-color: var(--border-strong);
  background: var(--glass-surface);
}
.sm-kpi-soft .sm-kpi-n { color: var(--text-muted); }

/* ── Bar rows (disposition mix + timing) ── */
.sm-bars {
  display: flex;
  flex-direction: column;
  gap: var(--space-1-5);
}
.sm-bar-row {
  display: grid;
  grid-template-columns: 130px 1fr 44px;
  align-items: center;
  gap: var(--space-2-5);
  min-height: 26px;
}
.sm-bar-label {
  font-size: var(--text-sm);
  color: var(--text);
  overflow-wrap: anywhere;
}
.sm-bar-label-tight {
  font-variant-numeric: tabular-nums;
  color: var(--text-muted);
}
.sm-bar-track {
  height: 8px;
  border-radius: 4px;
  background: var(--sm-track-bg);
  border: 1px solid var(--hairline);
  overflow: hidden;
  min-width: 0;
}
.sm-bar-fill {
  display: block;
  height: 100%;
  background: var(--red);
  border-radius: 4px 0 0 4px;
}
.sm-bar-n {
  font-size: var(--text-sm);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  text-align: right;
  color: var(--text);
}
.sm-bar-row.is-zero .sm-bar-label,
.sm-bar-row.is-zero .sm-bar-n { color: var(--text-disabled); font-weight: 400; }

/* ── Plain label/value rows (the quick-dial breakdown) ── */
.sm-rows {
  display: flex;
  flex-direction: column;
  gap: var(--space-1-5);
  margin-top: var(--space-2-5);
}
.sm-row {
  display: flex;
  align-items: baseline;
  gap: var(--space-2-5);
  font-size: var(--text-sm);
}
.sm-row-l { color: var(--text-muted); overflow-wrap: anywhere; min-width: 0; }
.sm-row-v {
  margin-left: auto;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--text);
  white-space: nowrap;
}

/* Changing a <summary>'s display away from list-item SUPPRESSES the UA
   disclosure triangle in Chrome and Safari, so the row would read as plain
   muted text with no hint that it opens. The page-help.css precedent is the
   rule to follow: kill the marker EXPLICITLY in both engines, then supply a
   replacement affordance rather than relying on one. Here that is red
   summary text plus a chevron that rotates on open. */
.sm-details { margin-top: var(--space-3-5); }
.sm-details > summary {
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--red);
  cursor: pointer;
  min-height: 44px;
  display: flex;
  align-items: center;
  gap: var(--space-1-5);
  list-style: none;
}
.sm-details > summary::-webkit-details-marker { display: none; }
.sm-details > summary::after {
  content: '\203A';                 /* single right-angle quote as a chevron */
  display: inline-block;
  font-size: var(--text-md);
  line-height: 1;
  transform: rotate(90deg);
  transform-origin: center;
  transition: transform 0.2s ease;
}
.sm-details[open] > summary::after { transform: rotate(-90deg); }
@media (prefers-reduced-motion: reduce) {
  .sm-details > summary::after { transition: none; }
}
.sm-details > summary:hover { color: var(--text); }

/* ── Recent dial sessions table (C145-S7) ──
   The one section on this page fed by STORED session records
   (public.call_sessions, mig 165) rather than activity_log reconstruction.
   Six columns do not fit 375px, so the table scrolls inside its OWN
   container — the page body must never scroll horizontally. Same Tier-1
   glass vocabulary as the KPI tiles; no new colour axis, because the only
   state this section carries (ended vs abandoned) is signalled by TEXT
   first with border + hue as reinforcement. */
/* Focusable: a plain overflow container is NOT keyboard-reachable in
   Chrome/Safari, so a keyboard user could not scroll to the columns that fall
   off the right edge at 375px. The markup carries tabindex="0" + role="region"
   + an aria-label; this gives that focus a visible ring. */
.sm-tablewrap:focus-visible {
  outline: 2px solid var(--red);
  outline-offset: 2px;
}
.sm-tablewrap {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  background: var(--tier1-bg);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-float);
}
.sm-table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--text-sm);
  color: var(--text);
  white-space: nowrap;
}
.sm-table th,
.sm-table td {
  text-align: left;
  padding: var(--space-2-5) var(--space-3-5);
  border-bottom: 1px solid var(--hairline);
}
.sm-table thead th {
  font-weight: 600;
  color: var(--text-muted);
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
/* No hairline under the final row — it would read as a cut-off table. */
.sm-table tbody tr:last-child td { border-bottom: none; }
/* SPECIFICITY: the base rule above is `.sm-table th, .sm-table td` = (0,1,1),
   so a bare `.sm-td-num` = (0,1,0) LOSES to it and source order is irrelevant.
   Both halves must therefore be qualified — the original shipped only the
   thead half, which left every numeric <td> rendering LEFT under a RIGHT
   header and defeated the tabular-nums alignment this rule exists for. */
.sm-td-num { font-variant-numeric: tabular-nums; }
.sm-table thead th.sm-td-num,
.sm-table tbody td.sm-td-num { text-align: right; }

/* Outcome marker. Carried by the word itself; the border and hue only
   reinforce it, so the distinction survives greyscale and colour blindness. */
.sm-sess-pill {
  display: inline-block;
  font-size: var(--text-xs);
  font-weight: 600;
  line-height: 1.4;
  padding: 2px var(--space-2);
  border-radius: var(--radius-sm);
  border: 1px solid var(--hairline);
  color: var(--text-muted);
  white-space: nowrap;
}
.sm-sess-pill.is-ended {
  color: var(--text);
  border-color: var(--border-strong);
}
.sm-sess-pill.is-abandoned {
  border-style: dashed;
  border-color: var(--sm-warn-edge);
  background: var(--sm-warn-wash);
}

/* Section-level empty state — distinct from the page-level .sm-empty, which
   is a 40vh centred takeover. This one sits inside a populated page and must
   read as "nothing here yet", never as an error or a zero. */
.sm-subempty {
  background: var(--glass-surface);
  border: 1px dashed var(--border-strong);
  border-radius: var(--radius-lg);
  padding: var(--space-4) var(--space-3-5);
}
.sm-subempty p {
  color: var(--text-muted);
  font-size: var(--text-sm);
  line-height: 1.5;
  margin: 0;
  max-width: 60ch;
}
.sm-subempty p + p { margin-top: var(--space-2); }
/* The FAILURE variant. Without this the one state meaning "something went
   wrong" rendered as a bare muted paragraph — quieter than the benign empty
   state beside it, and the easiest thing in the section to skim past. */
.sm-subempty.is-error { border-color: var(--sm-warn-edge); border-style: solid; }
.sm-subempty strong { color: var(--text); }
.sm-subempty a { color: var(--red); }

/* The table's screen-reader caption uses the SHARED `.u-sr-only` from
   /css/utilities.css (already loaded on this page) rather than a page-scoped
   clone — this file's edit policy is "rules unique to this page only", and a
   byte-identical copy of an existing utility is not unique. */

/* ── Empty / error state ── */
.sm-empty {
  min-height: 40vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  gap: var(--space-2);
  padding: var(--space-6);
}
.sm-empty h2 {
  font-family: 'DM Serif Display', serif;
  font-size: var(--text-xl);
  color: var(--text);
  margin: 0;
  font-weight: var(--weight-regular);
}
.sm-empty p {
  color: var(--text-muted);
  font-size: var(--text-md);
  margin: 0;
  max-width: 46ch;
  line-height: 1.5;
}
.sm-empty a { color: var(--red); }

/* ══════════════════════════════════════════════════════════════════════════
   DASHBOARD (C145-S6) — pill row, range toggle, stat tiles, calendar heat
   map, comparative footer.

   Sits at the TOP of the page, above the C145-S5 aggregate sections and the
   C145-S7 session table, which are unchanged. Reuses the existing .sm-kpi
   tile recipe rather than inventing a second tile — the strip below the
   pills IS the KPI grid, just with eight cells and a couple of state
   modifiers.
   ══════════════════════════════════════════════════════════════════════════ */
.sm-dash { margin-bottom: var(--space-7); }

.sm-dash-controls {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  flex-wrap: wrap;
  margin-bottom: var(--space-3-5);
}

/* Pill row + range toggle share one segmented-control recipe. Both are real
   <button>s (never divs) so they are keyboard-reachable and announce their
   pressed / selected state without extra wiring. */
.sm-pills,
.sm-ranges {
  display: inline-flex;
  gap: 2px;
  /* 2px, not 3px: the buttons grew to a real 44px, so trimming the container
     keeps the overall control the same height as before rather than letting
     it tower over the tiles beneath it. */
  padding: 2px;
  background: var(--glass-surface);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-lg);
}
.sm-pill,
.sm-range {
  appearance: none;
  border: 0;
  background: transparent;
  color: var(--text-muted);
  font-family: inherit;
  font-size: var(--text-sm);
  font-weight: 600;
  line-height: 1;
  padding: 0 var(--space-3);
  /* 44px, the platform touch floor, ON THE BUTTON ITSELF. The previous 40px
     was justified by a comment claiming the parent's 3px padding extended the
     hit target — that premise is FALSE: the padding belongs to .sm-pills, and
     a tap landing in it hits the container, where the delegated handler's
     closest('[data-sm-pill]') returns null and nothing happens. The hit
     target was 40px, under the floor. (Frontend agent finding 6b.) */
  min-height: 44px;
  border-radius: var(--radius-md);
  cursor: pointer;
  white-space: nowrap;
}
.sm-pill:hover,
.sm-range:hover { color: var(--text); }
.sm-pill.is-on,
.sm-range.is-on {
  background: var(--red);
  color: var(--white);
}
.sm-pill:focus-visible,
.sm-range:focus-visible {
  outline: 2px solid var(--red);
  outline-offset: 2px;
}
.sm-ranges .sm-range { font-variant-numeric: tabular-nums; }

/* Eight tiles. Four-up on desktop, two-up on tablet and phone (the existing
   .sm-kpis breakpoints already do this — no second media query needed). */
.sm-dash-tiles { margin-bottom: var(--space-5); }

/* A live streak with nothing logged today. Amber rather than red: this is a
   nudge, not an error, and the page already uses red for "this is the
   important number". The word in the tile's sub-line carries the meaning;
   the border only reinforces it. */
.sm-kpi-risk {
  border-color: var(--sm-risk-edge);
  background: linear-gradient(180deg, var(--sm-warn-wash), transparent 70%), var(--glass-surface);
}

/* ── Comparative footer ──
   One line, given real weight: it is the sentence most likely to be the
   reason someone keeps the streak going, so it is not a muted footnote. */
.sm-dash-foot {
  margin: var(--space-4) 0 0;
  padding: var(--space-3-5);
  background: var(--glass-surface);
  border: 1px solid var(--hairline);
  border-left: 3px solid var(--red);
  border-radius: var(--radius-md);
  color: var(--text);
  font-size: var(--text-md);
  line-height: 1.5;
}

/* ══════════════════════════════════════════════════════════════════════════
   ACHIEVEMENTS PANEL (C145-S9) — personal records, then badges by track.

   Replaces the C145-S6 stub behind the Achievements pill. It renders in the
   heat map's slot, so it shares that block's rhythm: .sm-subblock headings,
   the .sm-note footer, the same tile recipe as .sm-kpi.

   NO SIDEWAYS SCROLL, BY CONSTRUCTION. Both grids WRAP (auto-fill + minmax)
   rather than scrolling inside a container, which is a stronger guarantee
   than an overflow box: there is no horizontal overflow to scroll. The
   `minmax(min(Npx, 100%), 1fr)` keeps each track floor within its container;
   `min-width: 0` on each grid item closes the automatic-minimum blow-out;
   and `overflow-wrap: anywhere` handles long unbroken text inside that box.
   All three are required to keep the PAGE from scrolling sideways at 375px.
   ══════════════════════════════════════════════════════════════════════════ */

/* ── Personal records ──
   The same raised-tile recipe as .sm-kpi. They are not .sm-kpi tiles because
   they carry a fourth line (the caption) and a distinct empty state, and
   overloading the KPI class with a records-only modifier would make the
   dashboard tiles harder to reason about than duplicating four declarations. */
.sm-ach-recs {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(210px, 100%), 1fr));
  gap: var(--space-2-5);
  margin-top: var(--space-3);
}
.sm-ach-rec {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
  color: var(--text);
  background: var(--tier1-bg);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-float);
  padding: var(--space-3-5);
}
/* An UNSET record. Dashed and muted, matching .sm-kpi-soft's vocabulary for
   "this is not a real figure" — so a record Sean has not set yet can never be
   misread as one he has. */
.sm-ach-rec.is-empty {
  border-style: dashed;
  border-color: var(--border-strong);
  background: var(--glass-surface);
  box-shadow: none;
}
.sm-ach-rec-n {
  font-size: var(--text-2xl);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.sm-ach-rec.is-empty .sm-ach-rec-n { color: var(--text-muted); }
.sm-ach-rec-l {
  font-size: var(--text-sm);
  font-weight: 600;
  overflow-wrap: anywhere;
}
.sm-ach-rec-s {
  font-size: var(--text-xs);
  font-weight: 600;
  color: var(--text);
  overflow-wrap: anywhere;
}
.sm-ach-rec.is-empty .sm-ach-rec-s { color: var(--text-muted); font-weight: 400; }
.sm-ach-rec-c {
  font-size: var(--text-xs);
  color: var(--text-muted);
  line-height: 1.4;
  overflow-wrap: anywhere;
}

/* ── The zero state ──
   A BEGINNING, not a failure. Deliberately NOT .sm-subempty (a dashed
   "nothing here" box) and deliberately not .is-error: on day one an all-locked
   grid is the correct state, and the grid below it is full of things to aim
   at. Red left edge = "this is the important line", the page's existing
   convention. */
.sm-ach-start {
  margin: var(--space-3) 0 0;
  padding: var(--space-3) var(--space-3-5);
  border-left: 3px solid var(--red);
  border-radius: var(--radius-sm);
  background: var(--glass-surface);
  color: var(--text);
  font-size: var(--text-sm);
  line-height: 1.5;
  max-width: 60ch;
}

/* ── Tracks ──
   Each track is its own titled block with its own count. The separation is
   the point: the QUALITY track has to read as a distinct thing rather than as
   more dial counts, or the panel silently rewards volume alone. */
.sm-ach-track { margin-top: var(--space-5); }
.sm-ach-track-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-3);
}
.sm-ach-track-h {
  margin: 0;
  font-size: var(--text-sm);
  font-weight: 700;
  color: var(--text);
}
.sm-ach-track-n {
  font-size: var(--text-xs);
  font-weight: 600;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.sm-ach-track-sub {
  margin: 2px 0 0;
  font-size: var(--text-xs);
  color: var(--text-muted);
  line-height: 1.4;
  max-width: 60ch;
}

/* ── Badge grid ──
   Locked and unlocked TOGETHER. A grid of only-unlocked badges has no pull;
   the locked ones carrying "84 / 100" are the reason to open the panel. */
.sm-ach-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(190px, 100%), 1fr));
  gap: var(--space-2-5);
  margin-top: var(--space-3);
}
.sm-ach-badge {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 3px;
  min-width: 0;
  padding: var(--space-3);
  border: 1px solid var(--hairline);
  border-radius: var(--radius-lg);
  background: var(--glass-surface);
}
/* UNLOCKED reads as earned: red-lit edge and wash, the same vocabulary
   .sm-kpi-strong already uses for "this is the number that matters". */
.sm-ach-badge.is-on {
  border-color: var(--sm-strong-edge);
  background: linear-gradient(180deg, var(--red-wash), transparent 70%), var(--tier1-bg);
  box-shadow: var(--shadow-float);
}
/* LOCKED is dashed and dimmed, NOT hidden and NOT greyed into illegibility —
   the progress line on it has to stay readable, because that line is the
   whole reason locked badges are on screen. */
.sm-ach-badge.is-off {
  border-style: dashed;
  border-color: var(--border-strong);
}
.sm-ach-badge-l {
  font-size: var(--text-sm);
  font-weight: 700;
  color: var(--text);
  overflow-wrap: anywhere;
}
.sm-ach-badge.is-off .sm-ach-badge-l { color: var(--text-muted); }
.sm-ach-badge-c {
  font-size: var(--text-xs);
  color: var(--text-muted);
  line-height: 1.4;
  overflow-wrap: anywhere;
}
.sm-ach-badge-m {
  margin-top: 2px;
  font-size: var(--text-xs);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--text-muted);
  overflow-wrap: anywhere;
}
.sm-ach-badge.is-on .sm-ach-badge-m { color: var(--text); }

/* The NEW word is the primary marker; this ring reinforces it without making
   colour the only carrier of state. */
.sm-ach-badge.is-new {
  box-shadow: 0 0 0 2px var(--sm-strong-edge), var(--shadow-float);
}

/* ── NEW marker ──
   Carried by the WORD "NEW" first, with colour as reinforcement only — the
   .sm-sess-pill rule on this page, applied here. It sits in the flow rather
   than absolutely positioned so it can never overlap a long label. */
.sm-ach-new {
  align-self: flex-start;
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: 0.06em;
  line-height: 1.4;
  padding: 1px var(--space-2);
  border-radius: var(--radius-sm);
  background: var(--red);
  color: var(--white);
}

/* ── Progress bar on a locked badge ──
   Reinforces the "84 / 100" line above it; it never replaces it, because a
   bar alone cannot be read precisely and cannot be read at all by a screen
   reader. The span is empty, so it contributes no accessible name; the text
   immediately above it already carries the value. */
.sm-ach-bar {
  display: block;
  height: 4px;
  margin-top: var(--space-2);
  border-radius: var(--radius-pill);
  background: var(--sm-track-bg);
  overflow: hidden;
}
.sm-ach-bar-fill {
  display: block;
  height: 100%;
  border-radius: var(--radius-pill);
  background: var(--red);
}

/* ── Responsive — 375px is the design target for this page ── */
@media (max-width: 899px) {
  .sm-funnel { grid-template-columns: repeat(3, 1fr); }
  .sm-kpis   { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 560px) {
  .sm-app { padding: var(--space-4) var(--space-3-5) calc(var(--space-8) + env(safe-area-inset-bottom)); }
  .sm-funnel { grid-template-columns: repeat(2, 1fr); }
  /* The disposition labels are long ("Signed up on call ★"), so the fixed
     130px label column is dropped for a stacked label-over-bar row rather
     than truncating a label the reader needs. */
  .sm-bar-row {
    grid-template-columns: 1fr 44px;
    grid-template-areas: 'label n' 'track track';
    row-gap: 4px;
    min-height: 40px;
  }
  .sm-bar-label { grid-area: label; }
  .sm-bar-n     { grid-area: n; }
  .sm-bar-track { grid-area: track; }
  /* C145-S7 — tighten the session table's gutters so more of its six columns
     land inside the first viewport before the reader has to scroll it. The
     table still scrolls inside .sm-tablewrap; nothing is truncated. */
  .sm-table th,
  .sm-table td { padding: var(--space-2) var(--space-2-5); }

  /* C145-S6 — at 375px the controls stack rather than squeezing; the pill
     row keeps its full labels ("Achievements" must not truncate) and the
     range toggle sits under it. */
  .sm-dash-controls {
    flex-direction: column;
    align-items: stretch;
    gap: var(--space-2-5);
  }
  .sm-pills,
  .sm-ranges { justify-content: space-between; }
  .sm-pill,
  .sm-range { flex: 1 1 auto; padding: 0 var(--space-2); }
  .sm-dash-foot { font-size: var(--text-sm); }

  /* C145-S9 — at 375px both achievement grids go one-up. The minmax floors
     above are written as `min(NNNpx, 100%)` so a card can never demand more
     width than the viewport has, which is what would push the PAGE sideways;
     these rules just stop a 190px card from sitting two-up in a 343px content
     column where neither would be readable. */
  .sm-ach-recs,
  .sm-ach-grid { grid-template-columns: 1fr; }
  .sm-ach-track-head { flex-wrap: wrap; gap: var(--space-2); }
}
