/**
 * blackjack.global — the statistics surface.
 *
 * Every colour, space, radius and duration comes from design/tokens.css. There
 * is not one raw hex value below except inside the heat ramp, which declares the
 * same base channels the semantic tokens use at a set of increasing alphas, per
 * theme, so each band sits on a background that keeps --text-1 far above AA.
 *
 * SOLVED rules honoured here:
 *   - --radius-cell is the atomic shape. The heatmap cell and the stat cell both
 *     use it. No pill anywhere: --radius-chip is scoped to .chip only.
 *   - Gold means exactly three things, none of them a statistic, so --brand does
 *     not appear in this file.
 *   - Engine numbers are mono with tabular figures. Human text is the sans face.
 *   - --tap-min is never overridden.
 *
 * Mobile first from 360px. Every label wraps, no figure is pinned to one line,
 * and the surface is laid out to survive 40 percent text expansion, which is
 * --expand-factor in the token file.
 */

/* ------------------------------------------------------------ the heat ramp */

.statspanel {
  /* Ordered bands. Colour is never the only signal: the cell also carries its
     attempt count as text, a border weight that rises with the band, and an
     aria-label naming errors over attempts. */
  /* ONE hue for every error band, at rising alpha, and deliberately NOT gold.
     Gold is --brand and the design system reserves it for exactly three things:
     the Stand action, a win state and a real-money action. An error rate is a
     statistic, so it never borrows the brand channel. --warn resolves to the same
     base as --gold-500, which is why it is absent from the ramp too.
     Four steps of one hue are weak on their own, so each band also carries a
     rising rule on its top edge and the attempt count as text. */
  --heat-untried: var(--surface-inset);
  --heat-clean: rgba(62, 208, 138, 0.16);
  --heat-low: rgba(255, 107, 107, 0.10);
  --heat-mid: rgba(255, 107, 107, 0.22);
  --heat-high: rgba(255, 107, 107, 0.34);
  --heat-severe: rgba(255, 107, 107, 0.50);
  --heat-ink: var(--text-1);
  --heat-cell: 26px;
}

[data-theme='light'] .statspanel {
  --heat-clean: rgba(10, 107, 65, 0.13);
  --heat-low: rgba(163, 32, 32, 0.09);
  --heat-mid: rgba(163, 32, 32, 0.18);
  --heat-high: rgba(163, 32, 32, 0.28);
  --heat-severe: rgba(163, 32, 32, 0.40);
}

/* -------------------------------------------------------------- the headline */

/**
 * Accuracy at headline size. It is the largest number on the surface because it
 * is the metric that converges, and the bankroll figure further down is not.
 */
.headline {
  display: grid;
  gap: var(--space-1);
  padding: var(--space-4);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-cell);
  background: var(--surface-2);
}

.headline__k {
  margin: 0;
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
  letter-spacing: var(--track-caps);
  text-transform: uppercase;
  color: var(--text-3);
}

.headline__v {
  margin: 0;
  font-size: var(--text-num-lg);
  font-weight: var(--weight-bold);
  line-height: var(--leading-none);
  font-variant-numeric: tabular-nums;
  color: var(--text-1);
}

.headline__sub {
  margin: 0;
  font-size: var(--text-xs);
  line-height: var(--leading-snug);
  color: var(--text-2);
  text-wrap: pretty;
}

/* ------------------------------------------------------------- figure cells */

.statgrid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-2);
}

/* A grid whose cell count varies with what was measured. The renderer sets
   data-cells, so the track count never exceeds the number of cells and no dead
   cell is ever drawn. Two columns is the floor at 360px. */
.statgrid--flow[data-cells='1'] { grid-template-columns: minmax(0, 1fr); }
.statgrid--flow[data-cells='2'] { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.statgrid--flow[data-cells='3'] { grid-template-columns: repeat(2, minmax(0, 1fr)); }

.stat {
  display: grid;
  gap: var(--space-px);
  align-content: start;
  min-width: 0;
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-cell);
  background: var(--surface-2);
}

.stat--wide {
  grid-column: 1 / -1;
}

.stat__k {
  font-size: var(--text-2xs);
  font-weight: var(--weight-medium);
  letter-spacing: var(--track-caps);
  text-transform: uppercase;
  color: var(--text-3);
  /* Wraps rather than truncating: a clipped label in German or Turkish is a
     mistranslation the reader cannot recover from. */
  overflow-wrap: break-word;
}

.stat__v {
  font-size: var(--text-num-sm);
  font-weight: var(--weight-bold);
  line-height: var(--leading-tight);
  font-variant-numeric: tabular-nums;
  color: var(--text-1);
  overflow-wrap: break-word;
}

.stat__v[data-sign='pos'] { color: var(--pos); }
.stat__v[data-sign='neg'] { color: var(--neg); }

.stat__sub {
  font-size: var(--text-2xs);
  line-height: var(--leading-snug);
  color: var(--text-3);
  text-wrap: pretty;
}

/* --------------------------------------------------- categories and leaks */

.panel__sub {
  margin: var(--space-4) 0 var(--space-2);
  font-size: var(--text-xs);
  font-weight: var(--weight-bold);
  letter-spacing: var(--track-caps);
  text-transform: uppercase;
  color: var(--text-3);
}

.panel__sub:first-child { margin-top: 0; }

/* Category, count and cost sit on one line at every width. The label track is
   the only flexible one, so a 40 percent longer label wraps inside its own
   column instead of pushing the figures onto a second line.
   Scoped to .statspanel on purpose: game.css owns `.mistakes li`, which is
   0,1,1 and would otherwise win. Thread 8 owns that file, so this file raises
   its own specificity rather than editing theirs. */
.statspanel .mrow {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  gap: var(--space-1) var(--space-2);
  align-items: baseline;
  padding: var(--space-2) 0;
  border-bottom: 1px solid var(--border-subtle);
  font-size: var(--text-sm);
}

.leak {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: var(--space-1) var(--space-2);
  align-items: baseline;
  padding: var(--space-2) 0;
  border-bottom: 1px solid var(--border-subtle);
  font-size: var(--text-sm);
}

.mrow:last-child,
.leak:last-child { border-bottom: 0; }

.mrow__k { color: var(--text-2); min-width: 0; overflow-wrap: break-word; }
.mrow__n,
.mrow__c,
.leak__c {
  font-variant-numeric: tabular-nums;
  text-align: end;
  white-space: nowrap;
}
.mrow__n { color: var(--text-2); }
.mrow__c[data-sign='neg'],
.leak__c[data-sign='neg'] { color: var(--neg); }

.leak__hand {
  color: var(--text-1);
  font-weight: var(--weight-medium);
  min-width: 0;
  overflow-wrap: break-word;
}

.leak__n {
  grid-column: 1;
  font-size: var(--text-2xs);
  color: var(--text-3);
}

/* Severity as a leading rule, so the ranking is legible without colour. */
.leak {
  padding-inline-start: var(--space-3);
  border-inline-start: 3px solid var(--border-subtle);
}
/* One hue, rising weight. --warn resolves to the brand gold base, and gold is
   never a statistic on this site, so the rule width carries the ranking. */
.leak[data-severity='minor'] { border-inline-start-color: var(--neg-quiet); }
.leak[data-severity='significant'] { border-inline-start-color: var(--neg); }
.leak[data-severity='severe'] { border-inline-start-color: var(--neg); border-inline-start-width: 5px; }

/* ----------------------------------------------------------------- heatmap */

.heatwrap {
  /* A last-resort scroll rather than an overflow. The grid is built to fit at
     360px, and the wrapper exists for 40 percent text expansion on the row
     headings in German and Turkish. */
  overflow-x: auto;
  overscroll-behavior-x: contain;
}

.heat {
  border-collapse: separate;
  border-spacing: var(--space-px);
  font-family: var(--font-mono);
  font-size: var(--text-2xs);
  font-variant-numeric: tabular-nums;
  letter-spacing: var(--track-code);
}

.heat caption {
  margin-bottom: var(--space-2);
  font-family: var(--font-sans);
  font-size: var(--text-2xs);
  text-align: start;
  color: var(--text-3);
  text-wrap: pretty;
}

.heat th {
  padding: 0 var(--space-1);
  font-weight: var(--weight-medium);
  color: var(--text-3);
  text-align: center;
  white-space: nowrap;
}

.heat th[scope='row'] { text-align: end; min-width: 2.5em; }

.heat th[scope='rowgroup'] {
  padding-top: var(--space-2);
  font-family: var(--font-sans);
  font-size: var(--text-2xs);
  letter-spacing: var(--track-caps);
  text-transform: uppercase;
  text-align: start;
  color: var(--text-3);
}

.hcell {
  width: var(--heat-cell);
  height: var(--heat-cell);
  padding: 0;
  text-align: center;
  vertical-align: middle;
  border-radius: var(--radius-cell);
  border-top: 1px solid transparent;
  background: var(--heat-untried);
  color: var(--heat-ink);
}

.hcell[data-band='untried'] { background: var(--heat-untried); color: transparent; }
.hcell[data-band='clean'] { background: var(--heat-clean); }
.hcell[data-band='low'] { background: var(--heat-low); border-top-color: var(--border-subtle); }
.hcell[data-band='mid'] { background: var(--heat-mid); border-top-color: var(--neg); }
.hcell[data-band='high'] { background: var(--heat-high); border-top-width: 2px; border-top-color: var(--neg); }
.hcell[data-band='severe'] { background: var(--heat-severe); border-top-width: 3px; border-top-color: var(--neg); }

.heatlegend {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1) var(--space-3);
  align-items: center;
  margin: var(--space-3) 0 0;
  font-size: var(--text-2xs);
  color: var(--text-3);
}

.heatlegend__h {
  font-weight: var(--weight-bold);
  letter-spacing: var(--track-caps);
  text-transform: uppercase;
}

.heatkey { display: inline-flex; gap: var(--space-1); align-items: center; }

.heatkey i {
  width: 0.85rem;
  height: 0.85rem;
  border-radius: var(--radius-xs);
  border: 1px solid var(--border-subtle);
}

.heatkey i[data-band='untried'] { background: var(--heat-untried); }
.heatkey i[data-band='clean'] { background: var(--heat-clean); }
.heatkey i[data-band='low'] { background: var(--heat-low); }
.heatkey i[data-band='mid'] { background: var(--heat-mid); }
.heatkey i[data-band='high'] { background: var(--heat-high); }
.heatkey i[data-band='severe'] { background: var(--heat-severe); }

/* ---------------------------------------------------- verdict and the notes */

/**
 * The verdict line. It is deliberately not styled as a win or a loss: a result
 * inside the range luck explains is neither, and colouring it green would undo
 * the entire point of the block above it.
 */
.verdict {
  margin: var(--space-3) 0 0;
  padding: var(--space-2) var(--space-3);
  border-inline-start: 3px solid var(--border-strong);
  border-radius: var(--radius-xs);
  background: var(--surface-inset);
  font-size: var(--text-sm);
  line-height: var(--leading-snug);
  color: var(--text-2);
  text-wrap: pretty;
}

.verdict[data-verdict='above'],
.verdict[data-verdict='below'] { border-inline-start-color: var(--info); }

.muted {
  margin: var(--space-2) 0 0;
  font-size: var(--text-2xs);
  line-height: var(--leading-snug);
  color: var(--text-3);
  max-width: var(--measure-prose);
  text-wrap: pretty;
}

/**
 * The ungraded state on a variant table. Not a dead panel and not a zero: it
 * says what is missing, why no substitute chart is used, that the table is still
 * playable, and what changes when the solver catches up (decisions log D3).
 */
.statnote {
  padding: var(--space-3);
  border: 1px dashed var(--border-strong);
  border-radius: var(--radius-cell);
  background: var(--surface-inset);
}

.statnote p {
  margin: 0 0 var(--space-2);
  font-size: var(--text-xs);
  line-height: var(--leading-snug);
  color: var(--text-2);
  text-wrap: pretty;
}

.statnote p:last-child { margin-bottom: 0; }

.statnote__h {
  font-weight: var(--weight-bold);
  color: var(--text-1) !important;
}

/* -------------------------------------------------------------- scope switch */

.scopeswitch {
  display: flex;
  gap: var(--space-px);
  padding: var(--space-px);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius-cell);
  background: var(--surface-inset);
}

.scopeswitch button {
  flex: 1 1 0;
  min-height: var(--tap-min);
  padding: var(--space-1) var(--space-2);
  border: 0;
  border-radius: var(--radius-xs);
  background: transparent;
  color: var(--text-3);
  font: inherit;
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease-standard),
    color var(--dur-fast) var(--ease-standard);
}

.scopeswitch button[aria-pressed='true'] {
  background: var(--surface-3);
  color: var(--text-1);
}

/* M13. This was `outline: var(--focus)`, a colour token passed to the outline
   shorthand, which resets outline-style to none and painted no ring at all on
   the two scope buttons. Same 2px solid ring as base.css. */
.scopeswitch button:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }

/* --------------------------------------------------- end-of-session summary */

.summary {
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-lg);
  background: var(--surface-1);
  box-shadow: var(--shadow-e3);
  padding: var(--space-4);
  max-width: var(--container-sm);
  width: calc(100vw - var(--space-6));
}

.summary::backdrop { background: rgba(0, 0, 0, 0.55); }

.summary__h {
  margin: 0 0 var(--space-3);
  font-size: var(--text-lg);
  font-weight: var(--weight-bold);
  color: var(--text-1);
  text-wrap: balance;
}

.summary__close {
  display: block;
  width: 100%;
  min-height: var(--tap-min);
  margin-top: var(--space-4);
  padding: var(--btn-pad-y) var(--btn-pad-x);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-md);
  background: var(--surface-3);
  color: var(--text-1);
  font: inherit;
  font-weight: var(--weight-medium);
  cursor: pointer;
}

/* M13. Same shorthand misuse as the scope switch above: a colour token in the
   outline shorthand paints nothing. */
.summary__close:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }

/* The dialog is narrower than the panel, so the figures take the full width at
   360px and pair up only once there is room. */
.summary .statgrid { grid-template-columns: minmax(0, 1fr); }

/* ----------------------------------------------------------------- 480px up */

@media (min-width: 30rem) {
  .statspanel { --heat-cell: 30px; }
  .summary .statgrid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .statgrid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .statgrid--flow[data-cells='3'] { grid-template-columns: repeat(3, minmax(0, 1fr)); }

  .statspanel .mrow__n { min-width: 3rem; }
  .statspanel .mrow__c { min-width: 4.5rem; }
}

/* ---------------------------------------------------------------- 1024px up */

@media (min-width: 64rem) {
  /* The rail is narrow at desktop widths, so the figure grid goes back to two
     columns rather than squeezing three into it. */
  .gameshell__rail .statgrid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .gameshell__wide .statgrid { grid-template-columns: repeat(4, minmax(0, 1fr)); }

  /* The grid is a fixed-aspect artefact, so the cells grow with the viewport
     rather than the grid stretching into an empty field. Set on the wrapper
     because the wrapper is the closest ancestor of a cell that can carry it. */
  .heatwrap { --heat-cell: 40px; }
}

/* ------------------------------------------------------------ reduced motion */

@media (prefers-reduced-motion: reduce) {
  .scopeswitch button { transition: none; }
}

/* --------------------------------------------------------- forced colours */

@media (forced-colors: active) {
  /* The heat ramp is a colour signal, and it is discarded here. The attempt
     count, the border weight and the aria-label carry the information instead. */
  .hcell { background: Canvas; color: CanvasText; border: 1px solid CanvasText; }
  .hcell[data-band='mid'] { border-top-width: 3px; }
  .hcell[data-band='high'] { border-top-width: 4px; }
  .hcell[data-band='severe'] { border-top-width: 6px; }
}

/* ------------------------------------------- the self-explanation disclosure */

/**
 * Every figure on the surface carries one of these, and the coach strip carries
 * one for the cost figure it prints during play (brief 3, 30 August 2026).
 *
 * A disclosure rather than a tooltip. A tooltip does not open on a touch screen,
 * and the surface is mobile first from 360px, so the note has to be reachable by
 * tap and by keyboard. `title` on the figure covers the pointer case, and this
 * block covers everyone else.
 *
 * Collapsed by default and quiet when collapsed: the summary sits at --text-3
 * with no border, so a grid of six cells does not turn into a grid of six
 * paragraphs. Opened, the note is left-ruled so a reader can see where one
 * figure's explanation ends.
 */
.statdef {
  margin-top: var(--space-2);
  font-size: var(--text-2xs);
  line-height: var(--leading-snug);
}

.statdef__s {
  display: flex;
  align-items: center;
  gap: var(--space-1);
  /* The row is the tap target, and it holds --tap-min without stretching a
     collapsed cell: the padding is on the row, not on the disclosure. */
  min-height: var(--tap-min);
  padding: var(--space-1) 0;
  color: var(--text-3);
  cursor: pointer;
  /* The marker is drawn below, so the native triangle is dropped in every
     engine. list-style covers Firefox, ::-webkit-details-marker covers Safari. */
  list-style: none;
  text-wrap: pretty;
}

.statdef__s::-webkit-details-marker { display: none; }

/* A chevron built from a border, so it inherits currentColor and needs no glyph
   that a locale font might not carry. */
.statdef__s::before {
  content: '';
  flex: 0 0 auto;
  width: 0.4em;
  height: 0.4em;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: rotate(-45deg);
  transition: transform var(--dur-fast) var(--ease-standard);
}

.statdef[open] > .statdef__s::before { transform: rotate(45deg); }

.statdef__s:hover { color: var(--text-2); }

.statdef__s:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
  border-radius: var(--radius-cell);
}

/* The opened note. Ruled on the inline start edge, which flips with direction,
   so a right-to-left locale rules the correct side. */
.statdef > p {
  margin: 0 0 var(--space-2);
  padding-inline-start: var(--space-2);
  border-inline-start: 1px solid var(--border-subtle);
  max-width: var(--measure-prose);
  color: var(--text-3);
  text-wrap: pretty;
}

/* The definition itself reads one step brighter than the qualifications under
   it, because it is the sentence a reader came for. */
.statdef__d { color: var(--text-2) !important; }

.statdef > :last-child { margin-bottom: 0; }

.statdef__a {
  display: inline-block;
  min-height: var(--tap-min);
  padding: var(--space-1) 0;
  color: var(--info);
  text-decoration: underline;
  text-underline-offset: 2px;
}

.statdef__a:hover { color: var(--text-1); }

.statdef__a:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
  border-radius: var(--radius-cell);
}

/* The coach strip is not part of the statistics panel, so the note inside it
   takes its measure from the strip rather than from a stat cell. */
[data-coach-note] { margin-top: var(--space-1); }

@media (prefers-reduced-motion: reduce) {
  .statdef__s::before { transition: none; }
}

@media (forced-colors: active) {
  .statdef__s::before { border-color: CanvasText; }
  .statdef > p { border-inline-start-color: CanvasText; }
}
