/* =====================================================================
   Behavioral Pulse — chart primitives.

   Four, and they are the ONLY chart vocabulary in the product:
     1. scoreBar + interval   — the workhorse
     2. wide interval          — same primitive, thinner mark, wider CI
     3. no reading             — hatched track, no mark, score renders "—"
     4. nonresponse floor      — worst-case band, report caveats only

   The load-bearing idea: a score alone is close to meaningless, so the bar
   never shows one. It shows a reading, the uncertainty around it, and where
   the last round sat. MARK WEIGHT ENCODES CONFIDENCE — 3px firm, 2px soft —
   and the interval width encodes it again, so the same score with a wider
   stretch reads as a rough sketch rather than a photograph.
   ===================================================================== */

/* ---------------------------------------------------------------- track --- */
.sb {
  position:relative;
  /* Room above the track for the prior-round notch and its label. Without the
     reserved space the notch would overlap the row above it. */
  padding-top:15px;
}
.sb__track {
  position:relative; height:19px; border-radius:var(--pulse-r-xs);
  background:var(--pulse-tint); overflow:visible;
}

/* Band gridlines at the two thresholds the reader is implicitly asking about:
   the risk->watch line and the watch->healthy line.

   These are NOT fixed at 40 and 70. Every instrument carries its own
   referenceRange {watchMin, healthyMin} — the admin editor defaults watchMin to
   55 — and the band badge beside the bar is computed from THOSE. Drawing a line
   at 40 for a signal whose risk line is 55 put a score of 50 to the right of
   the threshold while the badge next to it read "a real soft spot", so the bar
   argued with the badge on the one comparison it exists to make. The caller
   passes the area's own lines; --sb-g is set inline per line. */
.sb__grid { position:absolute; top:0; bottom:0; width:1px; background:var(--pulse-ink-a14); left:var(--sb-g); }

/* ------------------------------------------------------------- interval --- */
/* The confidence interval, as a band tint. Set --sb-l and --sb-w inline. */
.sb__ci {
  position:absolute; top:0; bottom:0; border-radius:5px;
  left:var(--sb-l); width:var(--sb-w);
}
.sb__ci--healthy  { background:rgba(46,125,50,.20); }
.sb__ci--watch    { background:rgba(164,116,10,.20); }
.sb__ci--risk     { background:rgba(200,8,21,.20); }
.sb__ci--progress { background:rgba(37,99,235,.20); }

/* ----------------------------------------------------------------- mark --- */
/* The reading itself. Width is the confidence tell, not decoration. */
.sb__mark {
  position:absolute; top:2px; bottom:2px; width:3px; border-radius:2px;
  left:var(--sb-x); transform:translateX(-50%);
}
.sb__mark--soft { width:2px; }
.sb__mark--healthy  { background:var(--pulse-healthy); }
.sb__mark--watch    { background:var(--pulse-watch); }
.sb__mark--risk     { background:var(--pulse-risk); }
.sb__mark--progress { background:var(--pulse-progress); }

/* --------------------------------------------------------- prior notch ---
   FIX APPLIED (design review, carried in the handoff as a known issue not yet
   in the mocks): the prior-round mark used to sit INSIDE the track as a
   1.5px line. Whenever it landed at or near a CI boundary it read as the
   shading's own edge rather than as a separate reference point — the one
   comparison the dashboard is built to support, lost to a coincidence of
   geometry.

   It now sits ABOVE the track as a notch with a short month label, so it can
   never be confused with the interval however the two align. */
.sb__prior {
  position:absolute; top:0; left:var(--sb-x); transform:translateX(-50%);
  display:flex; flex-direction:column; align-items:center; gap:1px;
}
.sb__prior-label {
  font:400 9px/1 var(--pulse-mono); letter-spacing:.04em;
  color:var(--pulse-ink-faint); white-space:nowrap;
}
.sb__prior-notch { width:1.5px; height:6px; background:var(--pulse-ink-a32); border-radius:1px; }

/* ------------------------------------------------------------- compact ---
   The dashboard's per-area strip lists every signal at once, where a 19px
   track turns a scannable column into a page of its own. Same bar, same lines,
   same notch — a denser row. It is a size, not a second chart language: the
   moment the strip drew its own kind of bar, the same score was being argued
   two different ways on one screen. */
.sb--sm { padding-top:12px; }
.sb--sm .sb__track { height:10px; }
.sb--sm .sb__mark { top:1px; bottom:1px; }
.sb--sm .sb__prior-label { font-size:8px; }
.sb--sm .sb__prior-notch { height:5px; }

/* ------------------------------------------------------------ no reading ---
   PRODUCT ADDITION. The row stays in place, dimmed, with a hatched track and
   no mark at all. Never a zero — a zero is a reading, and this is the absence
   of one. Never an omitted row either: a missing row reads as "fine".        */
.sb--noread .sb__track { background:var(--pulse-noread-hatch); }
.sb--noread { opacity:.72; }

/* ------------------------------------------------- nonresponse floor -------
   The worst case if every silent person felt worse than the worst answer
   received. Report caveats only — it is a bound, not a finding.             */
.sb__floor { position:absolute; top:0; bottom:0; background:var(--pulse-ink-a14); border-radius:5px;
  left:var(--sb-fl); width:var(--sb-fw); }
.sb__floor-mark { position:absolute; top:2px; bottom:2px; width:2px; background:var(--pulse-ink-soft);
  left:var(--sb-fx); transform:translateX(-50%); border-radius:1px; }

/* ------------------------------------------------------------------ key ---
   One line beneath the FIRST bar on each page — the other half of the fix
   above. A notch and a mark are only self-explanatory once. */
.sb-key {
  display:flex; align-items:center; gap:14px; flex-wrap:wrap;
  margin-top:7px; font:400 10px/1.4 var(--pulse-sans); color:var(--pulse-ink-faint);
}
.sb-key span { display:inline-flex; align-items:center; gap:5px; }
.sb-key i { display:inline-block; font-style:normal; }
.sb-key .k-mark  { width:3px; height:11px; border-radius:2px; background:var(--pulse-ink-soft); }
.sb-key .k-notch { width:1.5px; height:7px; border-radius:1px; background:var(--pulse-ink-a32); }
.sb-key .k-ci    { width:16px; height:9px; border-radius:3px; background:var(--pulse-ink-a14); }

/* =====================================================================
   BANDED TREND CHART (dashboard)

   Three zone fills at 6% alpha, edges at 30% and 60%, polyline coloured by
   the LATEST reading. A round where the area was not asked renders as a GAP,
   bridged by a faint dashed segment — bridging it solidly would invent a
   measurement that was never taken.
   ===================================================================== */
.tc { position:relative; }
.tc__zone { position:absolute; left:0; right:0; }
.tc__zone--healthy { top:0;   height:30%; background:rgba(46,125,50,.06); }
.tc__zone--watch   { top:30%; height:30%; background:rgba(164,116,10,.06); }
.tc__zone--risk    { top:60%; height:40%; background:rgba(200,8,21,.06); }
.tc__edge { position:absolute; left:0; right:0; height:1px; background:var(--pulse-ink-a14); }
.tc__label { position:absolute; right:6px; font:400 9.5px/1 var(--pulse-mono); letter-spacing:.08em;
  color:var(--pulse-ink-faint); }
.tc__line { fill:none; stroke-width:2; stroke-linejoin:round; stroke-linecap:round; }
.tc__line--gap { stroke-dasharray:4 5; opacity:.35; }

/* =====================================================================
   HEATMAP (dashboard)

   A team under the reporting floor gets a HATCHED EMPTY CELL, never a zero.
   Small teams are shrunk toward the company mean before display, which is a
   server-side concern — the client only renders what it is given.
   ===================================================================== */
.hm { display:grid; grid-template-columns:100px repeat(4, 1fr); gap:6px; }
.hm__cell {
  height:32px; border-radius:7px; display:flex; align-items:center; justify-content:center;
  font:600 12px/1 var(--pulse-mono); font-variant-numeric:tabular-nums;
}
.hm__cell--healthy { background:var(--pulse-healthy-tint); border:1px solid rgba(46,125,50,.28); color:var(--pulse-healthy-sm); }
.hm__cell--watch   { background:var(--pulse-watch-tint);   border:1px solid rgba(164,116,10,.28); color:var(--pulse-watch-sm); }
.hm__cell--risk    { background:var(--pulse-risk-tint);    border:1px solid rgba(200,8,21,.26);  color:var(--pulse-risk-sm); }
.hm__cell--floor   { background:var(--pulse-noread-hatch); border:1px solid var(--pulse-hairline); }
.hm__rowlabel { display:flex; align-items:center; font:500 11.5px/1.3 var(--pulse-sans); color:var(--pulse-ink-soft); }

/* =====================================================================
   SUPPRESSED vs ABSENT

   These must not look alike, and the difference is the whole promise: a
   suppressed finding says something IS there and is being held back; an
   absent one says nothing was raised. We never print how many — that number
   is the leak the floor exists to prevent.
   ===================================================================== */
.pulse-suppressed {
  border-radius:var(--pulse-r); padding:16px 18px; border:1px solid var(--pulse-hairline);
  background:repeating-linear-gradient(45deg,
    var(--pulse-surface), var(--pulse-surface) 7px, var(--pulse-tint) 7px, var(--pulse-tint) 14px);
}
.pulse-absent {
  border-radius:var(--pulse-r); padding:16px 18px;
  border:1px dashed var(--pulse-ink-a14); background:transparent;
}
