/* ============================================================================
   charts.css — B4 · the analytics surface on the doll page.
   Owned by B4. Consumed only by charts.js. Uses style.css tokens where they
   exist and NEVER redefines them; every chart-local value is prefixed --sc-.

   COLOR PROVENANCE (do not hand-edit these hexes — they are validated output)
   ---------------------------------------------------------------------------
   Every categorical set below was run through the dataviz validator against the
   REAL card surface this page renders on (#ffffff), not the skill's default
   #fcfcfb. Commands and results, so the next person can re-run them:

     mood, in the SLOT ORDER USED BY BOTH MOOD CHARTS
       node scripts/validate_palette.js \
         "#C8452F,#6250B8,#1E8F57,#3D6FA8,#A87A0E,#0089A3" \
         --mode light --surface "#ffffff"
       -> ALL CHECKS PASS.  worst adjacent CVD dE 16.0 (deutan), worst adjacent
          normal-vision dE 18.2, all six >= 3:1 contrast.

     provenance ribbon (aws vs third-party)
       "#0E8AB1,#B62F2F" --pairs all      -> PASS (CVD dE 18.3, normal 28.9)

     rapport diverging poles
       "#0E8AB1,#C8452F" --pairs all      -> PASS (CVD dE 19.1, normal 28.1)

     latency ramp (ordinal, one hue)
       "#63B6D0,#0E8AB1" --ordinal        -> PASS (monotone L, hue spread 7deg)

   TWO BINDING CONSTRAINTS, both measured, both load-bearing:

   1. The mood six pass on the ADJACENT pairlist ONLY. Under --pairs all they
      FAIL (excitement #C8452F vs anxiety #A87A0E, deutan dE 3.9; boredom
      #0089A3 vs sadness #3D6FA8, normal-vision dE 8.0). Therefore the mood
      palette is legal ONLY in stacked / diverging forms rendered in the fixed
      slot order below, with a 2px surface gap between segments and direct
      labels. A 6-series mood line chart, a mood scatter, or mood small
      multiples is FORBIDDEN — in those forms any two moods can end up side by
      side and the pairs above collapse.

   2. The slot order is NOT the one in the mission brief, and not the one in
      the DESIGN doc either. The brief's order (joy, interest, anxiety,
      sadness, excitement, boredom) is validated for a single six-segment bar,
      but the diverging chart splits the six into two three-segment stacks,
      which changes which pairs actually touch — and both sub-stacks FAIL
      (joy/excitement deutan 5.8; sadness/boredom normal 8.0). The order below
      is the sentiment chain excitement -> interest -> joy | sadness ->
      anxiety -> boredom, which IS the adjacency the diverging column
      produces reading top to bottom, and it passes. Reordering these is a
      revalidation, not a style tweak.

   The mission's ORIGINAL seven hexes are not used anywhere: they fail the
   chroma floor (#5B8FB9 C=0.085, #8ca3b2 C=0.034 — they read as gray and stop
   doing identity work) and the contrast relief rule (#2EAE6D 2.84:1,
   #D4A843 2.21:1, #8ca3b2 2.63:1). Re-stepped in hue, same families.

   Severity is STATUS, not categorical: reserved meaning, never reused for
   "series 4", and it FAILS the categorical CVD gate on purpose (#A16908 vs
   #B62F2F deutan 3.9). That is why every severity mark on this page ships
   with the severity WORD and a shape glyph. Never color alone.

   The page is light-only, matching the rest of the doll page. If a dark
   surface is ever added, every set above must be re-stepped and re-run with
   --mode dark against that surface. Do NOT auto-flip.
   ========================================================================= */

/* Tokens live on BOTH roots: `.sc` is the standalone panel this file builds
   when the page has no analytics markup, and `.sc-root` is stamped on each of
   B3's `.an-mount` slots when it does. Without the second selector every
   var() below would resolve to nothing in the hosted layout. */
.sc, .sc-root {
  /* ---- ink & chrome (inherit the page, fall back if style.css is absent) -- */
  --sc-surface:    var(--card, #ffffff);
  --sc-surface-2:  var(--card-alt, #f4fbff);
  --sc-ink:        var(--ink, #112536);
  --sc-ink-2:      var(--muted, #4d6575);
  --sc-ink-3:      var(--faint, #8ca3b2);
  --sc-line:       var(--line-light, #dde7ed);
  --sc-grid:       #e6eef4;   /* hairline, one step off surface, SOLID */
  --sc-axis:       #cfdbe4;

  /* ---- one-hue ramp: latency (emphasis form, 2 steps) ------------------- */
  --sc-brand:      var(--brand, #0e8ab1);
  --sc-brand-dark: var(--brand-dark, #0a6f90);
  --sc-recessive:  #63b6d0;

  /* ---- de-emphasis / diverging midpoint. NEVER a categorical slot. ------ */
  --sc-neutral:    #b0bec5;

  /* ---- provenance (2 classes, not a series) ----------------------------- */
  --sc-aws:        #0e8ab1;
  --sc-third:      #b62f2f;

  /* ---- status: severity. Reserved. Always icon + word. ------------------ */
  --sev-high:      #b62f2f;
  --sev-medium:    #a16908;
  --sev-low:       #0e8ab1;

  /* ---- mood, in validated slot order (see header) ----------------------- */
  --mood-excitement: #c8452f;
  --mood-interest:   #6250b8;
  --mood-joy:        #1e8f57;
  --mood-sadness:    #3d6fa8;
  --mood-anxiety:    #a87a0e;
  --mood-boredom:    #0089a3;
  --mood-neutral:    #b0bec5;

  --sc-gap: 2px;              /* THE surface gap. One width, everywhere. */
}

/* ============================ shell ============================ */
.sc {
  border: 1px solid var(--sc-line);
  border-radius: 16px;
  background: var(--sc-surface);
  box-shadow: var(--shadow-sm, 0 1px 3px rgba(13, 59, 82, .06));
  overflow: hidden;
  font-family: var(--font-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif);
  color: var(--sc-ink);
}
.sc > summary {
  cursor: pointer; list-style: none;
  padding: 13px 18px;
  font-weight: 700; font-size: .86rem; color: var(--sc-ink-2);
  display: flex; align-items: center; gap: 10px;
  -webkit-tap-highlight-color: transparent; touch-action: manipulation;
  min-height: 44px;
}
.sc > summary::-webkit-details-marker { display: none; }
.sc > summary::before { content: "▸"; color: var(--sc-ink-3); transition: transform .2s; }
.sc[open] > summary::before { transform: rotate(90deg); }
.sc > summary:focus-visible { outline: 2px solid var(--sc-brand); outline-offset: -2px; }
.sc-count {
  margin-left: auto; font-size: .72rem; font-weight: 700; color: var(--sc-ink-3);
  font-variant-numeric: tabular-nums;
}

.sc-body { padding: 2px 14px 18px; display: flex; flex-direction: column; gap: 18px; min-width: 0; }
@media (min-width: 560px) { .sc-body { padding: 2px 18px 20px; } }
/* A flex item's min-width defaults to auto == min-content, so a wide SVG
   refuses to shrink and pushes the whole page sideways no matter how many
   overflow:auto wrappers it sits in. This one line is what keeps the page
   body from scrolling horizontally on a phone. */
.sc-body > *, .sc-card > * { min-width: 0; }

/* ============================ filter row ============================
   ONE row, above everything it scopes. Never inside a card, never per-chart.
   Every chart below re-renders against the same slice, so the numbers agree. */
.sc-filters {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 10px 0 2px;
  border-bottom: 1px solid var(--sc-line);
  padding-bottom: 12px;
}
.sc-filters .sc-flab {
  font-size: .68rem; font-weight: 800; letter-spacing: .06em;
  text-transform: uppercase; color: var(--sc-ink-3);
}
.sc-seg { display: inline-flex; border: 1px solid var(--sc-line); border-radius: 999px; overflow: hidden; background: var(--sc-surface); }
.sc-seg button {
  font: inherit; font-size: .76rem; font-weight: 700;
  border: 0; background: transparent; color: var(--sc-ink-2);
  padding: 0 14px; min-height: 34px; cursor: pointer;
  -webkit-tap-highlight-color: transparent; touch-action: manipulation;
}
.sc-seg button + button { border-left: 1px solid var(--sc-line); }
.sc-seg button[aria-pressed="true"] { background: var(--brand-light, #e8f5fa); color: var(--sc-brand); }
.sc-seg button:focus-visible { outline: 2px solid var(--sc-brand); outline-offset: -2px; }

/* ============================ card ============================ */
.sc-card {
  border: 1px solid var(--sc-line); border-radius: 14px;
  background: var(--sc-surface); padding: 14px 14px 12px;
  display: flex; flex-direction: column; gap: 10px;
  /* height GROWS with content — never fixed, so an x-axis band can never be
     cut off into a nested scrollbar. */
}
.sc-head { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.sc-head h3 {
  margin: 0; font-family: var(--font-display, inherit);
  font-size: .92rem; font-weight: 700; letter-spacing: -.01em; color: var(--sc-ink);
}
.sc-sub { font-size: .72rem; color: var(--sc-ink-3); line-height: 1.45; margin: 0; }
/* Only the deck directly under a card title tucks up under it. Elsewhere the
   negative margin pulled a footnote into the legend above it. */
.sc-head + .sc-sub { margin-top: -4px; }
.sc-tbtn {
  margin-left: auto; font: inherit; font-size: .68rem; font-weight: 700;
  color: var(--sc-ink-2); background: transparent;
  border: 1px solid var(--sc-line); border-radius: 999px;
  padding: 5px 11px; cursor: pointer; min-height: 30px;
}
.sc-tbtn:hover { border-color: var(--sc-brand); color: var(--sc-brand); }
.sc-tbtn:focus-visible { outline: 2px solid var(--sc-brand); outline-offset: 1px; }

/* Charts scroll INSIDE their own wrapper. The page body never scrolls sideways. */
.sc-scroll { overflow-x: auto; overflow-y: hidden; -webkit-overflow-scrolling: touch; min-width: 0; max-width: 100%; }
.sc-scroll svg { display: block; }

/* Refetch keeps the frame: hold the old render at reduced opacity. */
.sc-card.is-stale .sc-scroll { opacity: .55; transition: opacity .18s; }

/* ============================ empty state ============================
   Honest: says WHY there is nothing, never a zero and never a fake shape. */
.sc-empty {
  display: flex; flex-direction: column; gap: 4px;
  padding: 18px 14px; border: 1px dashed var(--sc-line); border-radius: 12px;
  background: var(--sc-surface-2);
}
.sc-empty b { font-size: .8rem; font-weight: 700; color: var(--sc-ink-2); }
.sc-empty span { font-size: .72rem; color: var(--sc-ink-3); line-height: 1.5; }

/* ============================ C1 · KPI row ============================ */
.sc-hero {
  display: flex; flex-direction: column; gap: 2px;
  padding: 4px 2px 10px;
}
.sc-hero .sc-hlab { font-size: .68rem; font-weight: 800; letter-spacing: .06em; text-transform: uppercase; color: var(--sc-ink-3); }
.sc-hero .sc-hval {
  /* Hero figure: the page's UI sans (Manrope), never the display face.
     PROPORTIONAL figures — tabular-nums makes 121 look loose at 48px. */
  font-family: var(--font-ui, inherit);
  font-size: clamp(2.6rem, 11vw, 3.2rem); line-height: 1;
  font-weight: 800; letter-spacing: -.03em; color: var(--sc-ink);
}
.sc-hero .sc-hval u { text-decoration: none; font-size: .34em; font-weight: 700; color: var(--sc-ink-3); margin-left: 4px; letter-spacing: 0; }
/* An em-dash at 48px reads as a horizontal rule, not as "no data". Shrink it. */
.sc-hero .sc-hval.is-empty { font-size: 1.6rem; color: var(--sc-ink-3); letter-spacing: 0; }
.sc-hero .sc-hsub { font-size: .74rem; color: var(--sc-ink-2); line-height: 1.45; }

.sc-tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(108px, 1fr)); gap: 8px; }
.sc-tile {
  background: var(--sc-surface-2); border: 1px solid var(--sc-line);
  border-radius: 12px; padding: 10px 12px;
  display: flex; flex-direction: column; gap: 3px;
}
.sc-tile .t-lab { font-size: .6rem; text-transform: uppercase; letter-spacing: .05em; color: var(--sc-ink-3); font-weight: 800; }
.sc-tile .t-val { font-family: var(--font-ui, inherit); font-size: 1.18rem; font-weight: 800; letter-spacing: -.02em; color: var(--sc-ink); }
.sc-tile .t-val.is-empty { color: var(--sc-ink-3); font-weight: 700; }
.sc-tile .t-sub { font-size: .64rem; color: var(--sc-ink-3); }

/* ============================ C2 · provenance ============================ */
.sc-badge {
  display: flex; align-items: flex-start; gap: 9px;
  border-radius: 12px; padding: 11px 13px;
  border: 1px solid var(--sc-line); background: var(--sc-surface-2);
  font-size: .78rem; font-weight: 700; line-height: 1.45; color: var(--sc-ink-2);
}
.sc-badge .b-ico { font-size: .95rem; line-height: 1.25; }
.sc-badge b { display: block; color: var(--sc-ink); }
.sc-badge span { display: block; font-weight: 600; font-size: .72rem; color: var(--sc-ink-3); margin-top: 2px; }
.sc-badge.is-ok   { background: var(--ok-light, #e8f7ee);  border-color: #c6e9d4; }
.sc-badge.is-ok b { color: var(--ok, #1f8a4d); }
.sc-badge.is-bad  { background: var(--err-light, #fdecec); border-color: #f2cfcf; }
.sc-badge.is-bad b { color: var(--sc-third); }

.sc-stages { display: flex; flex-direction: column; gap: 6px; }
.sc-stage {
  display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap;
  font-size: .76rem; padding: 7px 10px;
  border: 1px solid var(--sc-line); border-radius: 10px; background: var(--sc-surface);
}
.sc-stage .s-key { font-size: .6rem; font-weight: 800; letter-spacing: .07em; text-transform: uppercase; color: var(--sc-ink-3); width: 30px; flex: none; }
.sc-stage .s-win { font-weight: 800; color: var(--sc-ink); overflow-wrap: anywhere; }
.sc-stage .s-where { font-size: .7rem; color: var(--sc-ink-2); font-weight: 600; flex: 1 1 100%; min-width: 0; }
/* the dot is the color-carrier; the WORD beside it is the real channel */
.sc-dot { width: 9px; height: 9px; border-radius: 50%; flex: none; align-self: center; }
.sc-dot.is-aws   { background: var(--sc-aws); }
.sc-dot.is-third { background: var(--sc-third); }
.sc-tag {
  margin-left: auto; font-size: .62rem; font-weight: 800; letter-spacing: .04em;
  text-transform: uppercase; padding: 3px 7px; border-radius: 6px;
  background: var(--brand-light, #e8f5fa); color: var(--sc-brand); white-space: nowrap;
}
.sc-tag.is-third { background: var(--err-light, #fdecec); color: var(--sc-third); }

/* ============================ legend ============================
   Present for EVERY chart with >= 2 series. Swatch mirrors the mark
   (rect for bars/areas). Text wears ink tokens — never the series color. */
.sc-legend { display: flex; flex-wrap: wrap; gap: 5px 14px; padding-top: 6px; }
.sc-legend .lg {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: .7rem; font-weight: 600; color: var(--sc-ink-2);
}
.sc-legend .lg i { width: 11px; height: 11px; border-radius: 3px; flex: none; }
.sc-legend .lg.is-line i { height: 3px; border-radius: 2px; width: 14px; }

/* ============================ tooltip ============================ */
.sc-tip {
  position: fixed; z-index: 60; pointer-events: none;
  max-width: 260px; padding: 8px 10px; border-radius: 10px;
  background: #0d2231f2; color: #fff;
  font-size: .72rem; line-height: 1.45;
  box-shadow: 0 8px 24px rgba(13, 59, 82, .28);
  opacity: 0; transform: translateY(3px); transition: opacity .1s, transform .1s;
}
.sc-tip.show { opacity: 1; transform: none; }
.sc-tip .tt-h { font-weight: 800; font-size: .68rem; letter-spacing: .04em; text-transform: uppercase; color: #9fc6d8; margin-bottom: 3px; }
.sc-tip .tt-r { display: flex; align-items: center; gap: 7px; }
/* Values LEAD, labels follow — the reader already has the series. */
.sc-tip .tt-v { font-weight: 800; font-variant-numeric: tabular-nums; min-width: 3.2em; }
.sc-tip .tt-n { color: #cfe2ec; font-weight: 600; }
/* line keys, not boxes, at tooltip density */
.sc-tip .tt-k { width: 12px; height: 3px; border-radius: 2px; flex: none; }

/* ============================ table view ============================
   Every chart has one. It is the relief channel for any sub-3:1 fill and the
   non-color path to every value a tooltip shows. */
.sc-table { overflow-x: auto; min-width: 0; max-width: 100%; }
.sc-table table { border-collapse: collapse; width: 100%; font-size: .74rem; }
.sc-table caption { text-align: left; font-size: .68rem; color: var(--sc-ink-3); padding-bottom: 6px; }
.sc-table th, .sc-table td { text-align: left; padding: 6px 10px 6px 0; border-bottom: 1px solid var(--sc-grid); white-space: nowrap; }
.sc-table th { font-size: .62rem; text-transform: uppercase; letter-spacing: .05em; color: var(--sc-ink-3); font-weight: 800; }
.sc-table td { color: var(--sc-ink-2); font-variant-numeric: tabular-nums; }
.sc-table td:first-child { color: var(--sc-ink); font-weight: 700; }

/* ============================ SVG chrome ============================ */
.sc svg text, .sc-root svg text { font-family: var(--font-ui, inherit); }
:where(.sc, .sc-root) .ax-grid { stroke: var(--sc-grid); stroke-width: 1; shape-rendering: crispEdges; }  /* SOLID hairline, never dashed */
:where(.sc, .sc-root) .ax-line { stroke: var(--sc-axis); stroke-width: 1; shape-rendering: crispEdges; }
:where(.sc, .sc-root) .ax-txt  { fill: var(--sc-ink-3); font-size: 10px; font-variant-numeric: tabular-nums; }
:where(.sc, .sc-root) .lb-cat  { fill: var(--sc-ink-2); font-size: 11px; font-weight: 700; }
:where(.sc, .sc-root) .lb-val  { fill: var(--sc-ink); font-size: 11px; font-weight: 800; font-variant-numeric: tabular-nums; }
:where(.sc, .sc-root) .lb-in   { font-size: 10px; font-weight: 800; }   /* label INSIDE a fill */
:where(.sc, .sc-root) .hit     { fill: transparent; cursor: default; }
:where(.sc, .sc-root) .mark:focus-visible,
:where(.sc, .sc-root) .hit:focus-visible { outline: 2px solid var(--sc-brand); outline-offset: 1px; }
:where(.sc, .sc-root) .mark.lift { filter: brightness(1.12); }

/* ============================ C5a · rapport meter ============================ */
.sc-meter { display: flex; flex-direction: column; gap: 6px; }
.sc-meter .m-top { display: flex; align-items: baseline; gap: 8px; }
.sc-meter .m-word { font-family: var(--font-display, inherit); font-size: 1.05rem; font-weight: 700; color: var(--sc-ink); }
.sc-meter .m-num  { font-family: var(--font-ui, inherit); font-size: 1.4rem; font-weight: 800; letter-spacing: -.02em; color: var(--sc-ink); margin-left: auto; }
.sc-meter .m-ends { display: flex; justify-content: space-between; font-size: .64rem; font-weight: 700; color: var(--sc-ink-3); }

/* ============================ texture (opt-in backup channel) ============
   45deg / 135deg only — never horizontal or vertical, those read as grid.
   Off by default; carried by print and forced-colors, where hue is gone. */
@media print, (forced-colors: active) {
  :where(.sc, .sc-root) .tx-third { fill: url(#sc-tx-45); }
}
@media (forced-colors: active) {
  .sc-card, .sc-tile, .sc-stage, .sc-empty { border-color: CanvasText; }
  :where(.sc, .sc-root) .mark { forced-color-adjust: none; }
}

@media (prefers-reduced-motion: reduce) {
  .sc-tip { transition: none; }
  .sc-card.is-stale .sc-scroll { transition: none; }
}
