@charset "UTF-8";

/* ==========================================================================
   Junwen Rao — résumé · charts & figures
   Loaded after style.css. Split out because the chart contract is the most
   opinionated part of the design system and benefits from living on its own.

   Every figure follows the same contract:
     · one hue, ordinal steps — never colour-as-identity
     · every value directly labelled, because adjacent ramp steps sit at only
       ~1.5–2:1 against each other and must never be the sole encoding
     · marks ≤ 24px thick, 4px rounded data-end, square at the baseline
     · a 2px surface gap separates touching fills — never a border
     · hairline solid axes, one step off the surface
     · animation reveals a value that is already in the DOM, so the text label
       is correct before, during and after — nothing is gated on motion
   ========================================================================== */

.figure {
  margin: 0;
}

.figure__caption {
  display: flex;
  align-items: baseline;
  gap: var(--s-3);
  margin-bottom: var(--s-4);
  font-size: var(--t-eyebrow);
  font-weight: 500;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--warm);
}

.figure__caption::after {
  content: '';
  flex: 1 1 auto;
  height: 1px;
  background: var(--rule-soft);
}

.figure__note {
  margin-top: var(--s-3);
  font-size: var(--t-micro);
  line-height: 1.6;
  color: var(--warm);
  max-width: 42ch;
}

/* --warm, not --rule: `--rule` is a 3.55:1 border tone and fails AA as text. */
.figure__source {
  display: inline-block;
  margin-top: var(--s-2);
  font-size: var(--t-eyebrow);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--warm);
}

/* --- Numeric values ---------------------------------------------------
   Proportional figures at display size (tabular makes "121" look loose);
   tabular only in aligned columns and axis ticks. */
.num {
  font-family: var(--font-body);
  font-weight: 600;
  font-variant-numeric: proportional-nums;
  letter-spacing: -0.02em;
  color: var(--deep);
  line-height: 1;
}

.num--figure {
  font-size: var(--t-figure);
}

.num__unit {
  font-size: 0.5em;
  font-weight: 500;
  margin-left: 0.08em;
  color: var(--blue);
  letter-spacing: 0;
}

/* ==========================================================================
   Stat tile grid — the "Selected Results" row
   ========================================================================== */

.stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15.5rem, 1fr));
  /* The hairline grid is drawn by the gap showing through, not by cell
     borders — that way interior rules never double up. */
  gap: 1px;
  background: var(--rule-soft);
  border: 1px solid var(--rule-soft);
}

.stat {
  display: flex;
  flex-direction: column;
  gap: var(--s-4);
  padding: clamp(var(--s-5), 3vw, var(--s-6));
  background: var(--cream);
}

.stat__label {
  font-size: var(--t-small);
  font-weight: 500;
  letter-spacing: 0.02em;
  color: var(--deep);
  line-height: 1.45;
}

.stat__plot {
  margin-top: auto;
}

.stat__note {
  font-size: var(--t-micro);
  line-height: 1.55;
  color: var(--warm);
}

/* --warm, not --rule: `--rule` is a 3.55:1 border tone and fails AA as text. */
.stat__source {
  font-size: var(--t-eyebrow);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--warm);
}

/* ==========================================================================
   Delta bars — before → after
   A paired column pair: two steps of one ramp, both directly labelled, with
   the lift stated as text so the comparison never depends on bar height.
   ========================================================================== */

.delta {
  display: flex;
  align-items: flex-end;
  gap: clamp(var(--s-4), 3vw, var(--s-6));
  flex-wrap: wrap;
}

.delta__plot {
  display: flex;
  flex-direction: column;
  gap: 0;
}

.delta__pair {
  display: flex;
  align-items: flex-end;
  gap: 2px; /* the surface gap between adjacent bars */
  height: 6.5rem;
}

.delta__col {
  width: 3rem; /* a 22px mark inside a 48px band leaves air */
  height: 100%;
}

/* The plot box is what bar heights are measured against.
   It must be a plain block with a resolved height — NOT a flex item — because
   a percentage height on a flex child is clamped by flex-shrink, which silently
   renders every bar the same size and destroys the encoding.
   `margin-top` reserves room for the value label that sits above the tallest bar. */
.delta__plotbox {
  position: relative;
  height: calc(100% - 1.5rem);
  margin-top: 1.5rem;
  display: flex;
  align-items: flex-end;
  justify-content: center;
}

.delta__bar {
  width: 22px;
  height: var(--h, 100%);
  flex: none; /* never let flex layout renegotiate a data-bearing height */
  /* Square at the baseline, 4px rounded at the data end. */
  border-radius: 4px 4px 0 0;
  transform: scaleY(0);
  transform-origin: 50% 100%;
  transition: transform var(--dur-chart) var(--ease-out);
  will-change: transform;
}

.delta__bar--from {
  background: var(--c-3);
}

.delta__bar--to {
  background: var(--c-1);
}

.is-revealed .delta__bar {
  transform: scaleY(1);
}

.is-revealed .delta__bar--to {
  transition-delay: 160ms;
}

/* The value rides just above its bar's data end, positioned from the bottom by
   the same percentage that sets the bar height — so label and mark cannot drift
   apart at any viewport size. */
.delta__value {
  position: absolute;
  bottom: var(--h, 100%);
  left: 50%;
  transform: translate(-50%, -0.35rem);
  font-size: var(--t-small);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--deep);
  white-space: nowrap;
}

.delta__baseline {
  height: 1px;
  background: var(--rule);
}

.delta__ticks {
  display: flex;
  gap: 2px;
  margin-top: var(--s-2);
}

.delta__tick {
  width: 3rem;
  text-align: center;
  font-size: var(--t-eyebrow);
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--warm);
}

.delta__lift {
  display: flex;
  flex-direction: column;
  gap: var(--s-1);
  padding-bottom: var(--s-6);
}

.delta__lift-value {
  display: flex;
  align-items: baseline;
  font-size: clamp(1.5rem, 1.2rem + 1vw, 2rem);
  font-weight: 600;
  color: var(--blue);
  letter-spacing: -0.02em;
  line-height: 1;
}

.delta__lift-label {
  font-size: var(--t-eyebrow);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--warm);
}

/* ==========================================================================
   Meter ring — a single ratio
   The unfilled track is a lighter step of the same ramp, so state reads
   across the whole ring. The value is centred as text, always present.
   ========================================================================== */

.ring {
  position: relative;
  width: 8.25rem;
  max-width: 100%;
  aspect-ratio: 1;
}

.ring svg {
  width: 100%;
  height: 100%;
  transform: rotate(-90deg); /* start the arc at 12 o'clock */
  overflow: visible;
}

.ring__track {
  fill: none;
  stroke: var(--c-track);
  stroke-width: 9;
}

.ring__value {
  fill: none;
  stroke: var(--c-1);
  stroke-width: 9;
  stroke-linecap: round;
  /* --dash (drawn length) and --circ (circumference) are set per instance. */
  stroke-dasharray: var(--dash) var(--circ);
  stroke-dashoffset: var(--dash);
  transition: stroke-dashoffset var(--dur-chart) var(--ease-out);
}

.is-revealed .ring__value {
  stroke-dashoffset: 0;
}

.ring__centre {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  text-align: center;
}

.ring__num {
  font-size: clamp(1.5rem, 1.3rem + 0.9vw, 2rem);
  font-weight: 600;
  color: var(--deep);
  letter-spacing: -0.02em;
  line-height: 1;
}

.ring__cap {
  font-size: var(--t-eyebrow);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--warm);
}

/* ==========================================================================
   Funnel — ordered stages
   Ordered stages take the ordinal ramp, so the sequence is visible in colour
   as well as in width. Both stages and the derived rate are labelled.
   ========================================================================== */

.funnel {
  display: flex;
  flex-direction: column;
  gap: 2px; /* the surface gap between stacked stages */
}

.funnel__row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--s-4);
}

.funnel__track {
  position: relative;
  height: 24px; /* mark thickness cap */
  background: color-mix(in srgb, var(--c-wash) 60%, transparent);
}

.funnel__fill {
  height: 100%;
  border-radius: 0 4px 4px 0; /* square at baseline, rounded data end */
  transform: scaleX(0);
  transform-origin: 0 50%;
  transition: transform var(--dur-chart) var(--ease-out);
  will-change: transform;
}

.funnel__row:nth-child(1) .funnel__fill {
  background: var(--c-1);
}

.funnel__row:nth-child(2) .funnel__fill {
  background: var(--c-3);
}

.is-revealed .funnel__fill {
  transform: scaleX(1);
}

.is-revealed .funnel__row:nth-child(2) .funnel__fill {
  transition-delay: 180ms;
}

.funnel__meta {
  display: flex;
  align-items: baseline;
  gap: var(--s-3);
  white-space: nowrap;
}

.funnel__label {
  font-size: var(--t-eyebrow);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--warm);
}

.funnel__value {
  font-size: var(--t-small);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--deep);
}

.funnel__rate {
  margin-top: var(--s-3);
  padding-top: var(--s-3);
  border-top: 1px solid var(--rule-soft);
  font-size: var(--t-micro);
  color: var(--warm);
}

.funnel__rate strong {
  font-weight: 600;
  color: var(--blue);
  font-variant-numeric: tabular-nums;
}

/* ==========================================================================
   Proportion bar — a single share
   ========================================================================== */

.propbar {
  display: flex;
  flex-direction: column;
  gap: var(--s-3);
}

.propbar__track {
  height: 10px;
  background: color-mix(in srgb, var(--c-track) 45%, transparent);
}

.propbar__fill {
  height: 100%;
  background: var(--c-1);
  border-radius: 0 4px 4px 0;
  transform: scaleX(0);
  transform-origin: 0 50%;
  transition: transform var(--dur-chart) var(--ease-out);
  will-change: transform;
}

.is-revealed .propbar__fill {
  transform: scaleX(1);
}

/* ==========================================================================
   Pills — secondary metrics beside a chart
   ========================================================================== */

.pills {
  display: flex;
  flex-wrap: wrap;
  gap: clamp(var(--s-4), 3vw, var(--s-6));
  margin-top: var(--s-5);
  padding-top: var(--s-4);
  border-top: 1px solid var(--rule-soft);
}

.pill {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.pill__value {
  font-size: var(--t-h3);
  font-weight: 600;
  color: var(--deep);
  letter-spacing: -0.02em;
  line-height: 1;
  font-variant-numeric: proportional-nums;
}

.pill__label {
  font-size: var(--t-eyebrow);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--warm);
}

/* ==========================================================================
   Tag matrix — qualitative coverage, deliberately not a chart
   Research coverage has no magnitude, so it gets labels rather than invented
   proficiency scores.
   ========================================================================== */

.tagmatrix {
  display: flex;
  flex-direction: column;
  gap: var(--s-4);
}

.tagmatrix__group {
  display: grid;
  grid-template-columns: minmax(0, 7rem) minmax(0, 1fr);
  gap: var(--s-3) var(--s-4);
  align-items: baseline;
}

.tagmatrix__label {
  font-size: var(--t-eyebrow);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--warm);
}

.tagmatrix__items {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2);
}

.tag {
  padding: 0.28rem 0.6rem;
  border: 1px solid var(--rule-soft);
  border-radius: 999px;
  font-size: var(--t-micro);
  letter-spacing: 0.02em;
  color: var(--deep);
  background: var(--paper);
  transition:
    border-color var(--dur-fast) var(--ease-out),
    background var(--dur-fast) var(--ease-out);
}

.tag:hover {
  border-color: var(--blue);
  background: var(--cream);
}

/* ==========================================================================
   Data-table twin
   Every figure has a table equivalent, so no value is reachable only through
   a rendered mark. Collapsed by default, opened by a <details> toggle.
   ========================================================================== */

.datatable {
  margin-top: var(--s-5);
  font-size: var(--t-micro);
}

.datatable > summary {
  cursor: pointer;
  color: var(--warm);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  font-size: var(--t-eyebrow);
  padding: var(--s-2) 0;
  list-style: none;
}

.datatable > summary::-webkit-details-marker {
  display: none;
}

.datatable > summary::before {
  content: '+';
  display: inline-block;
  width: 1.1em;
  color: var(--blue);
}

.datatable[open] > summary::before {
  content: '–';
}

/* The open panel is its own scroll container. Without this, a long English
   row label pushes the table past the viewport and the whole page scrolls
   sideways — the table must absorb its own overflow. */
.datatable__scroll {
  margin-top: var(--s-3);
  max-width: 100%;
  overflow-x: auto;
  /* A focusable scroll region needs a visible boundary for keyboard users. */
  overscroll-behavior-x: contain;
}

.datatable table {
  width: 100%;
  min-width: 0;
  border-collapse: collapse;
  table-layout: fixed;
}

/* Long labels wrap instead of forcing the table wide. */
.datatable th {
  width: 60%;
  overflow-wrap: break-word;
  word-break: normal;
}

.datatable caption {
  text-align: left;
  padding-bottom: var(--s-2);
  color: var(--warm);
}

.datatable th,
.datatable td {
  text-align: left;
  padding: var(--s-2) var(--s-3);
  border-bottom: 1px solid var(--rule-soft);
  vertical-align: top;
}

.datatable th {
  font-weight: 500;
  color: var(--deep);
}

.datatable td {
  text-align: right;
  white-space: nowrap;
}

.datatable td {
  font-variant-numeric: tabular-nums;
  color: var(--ink);
}
