/* ============================================================
   10-costs — 12-month volume + cost chart, and the cost breakdown table
   Dashboard: the "understand your costs" half.

   Every colour, space, radius, shadow, duration and font-size is a
   token. Raw values are limited to: 1px hairlines and their matching
   outline offsets, SVG stroke widths and radii, chart aspect ratios,
   and typographic measures in ch — none of which have a token.

   Both blocks share one containment rule and one elevation: heading
   and prose sit on the page, the data surface sits in a .costs__card
   with a hairline and --sh-xs. No second shadow layer.

   Contrast: everything that carries a label for a money figure sits
   on --text-body (7.80:1 on --surface, 7.42:1 on --surface-alt, and
   5.2:1 over the share-bar fill). --text-muted is 4.26 / 4.03:1 and
   is not used anywhere in here.

   The section sits on --surface, not --surface-alt: the opportunities
   section immediately below is --surface-alt, and two adjacent tinted
   sections read as one continuous grey field.
   ============================================================ */

.costs {
  background: var(--surface);
  overflow: hidden;               /* belt-and-braces against 360px overflow */

  /* Share-bar ink. Mixed into white rather than using the flat brand
     tint so it survives the row-hover surface sitting under it, with a
     stronger edge so a 7.2% share is still a legible mark and not a smudge. */
  --costs-bar: color-mix(in srgb, var(--c-brand) 30%, var(--c-white));
  --costs-bar-edge: color-mix(in srgb, var(--c-brand) 52%, var(--c-white));
}

/* ---------------- Section header ---------------- */

.costs__eyebrow { margin-bottom: var(--s-4); }
.costs__eyebrow-icon { width: var(--s-4); height: var(--s-4); }

.costs__title { max-width: 20ch; }
.costs__lead { margin-top: var(--s-5); }

.costs__sample {
  max-width: 62ch;
  margin-top: var(--s-4);
  font-size: var(--fs-xs);
  line-height: var(--lh-relaxed);
  color: var(--text-body);
}

/* ---------------- Shared block furniture ---------------- */

.costs__chart,
.costs__ledger { margin: var(--s-10) 0 0; }

.costs__block-head { margin-bottom: var(--s-5); }

/* Chart head carries the series key, so it splits: title and meta left,
   legend right, stacking under the meta line when there is no room. */
.costs__block-head--split {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--s-2) var(--s-6);
}

.costs__block-title {
  font-size: var(--fs-h4);
  font-weight: var(--fw-semi);
  letter-spacing: var(--tracking-snug);
}
.costs__block-title--icon {
  display: flex;
  align-items: center;
  gap: var(--s-3);
}

.costs__block-meta {
  margin-top: var(--s-1);
  font-size: var(--fs-xs);
  line-height: var(--lh-normal);
  color: var(--text-body);
  font-variant-numeric: tabular-nums;
}

.costs__card {
  background: var(--surface);
  border: 1px solid var(--c-hairline);
  border-radius: var(--r-lg);
  box-shadow: var(--sh-xs);
}

/* Series key. Two curves that track each other need naming, and each
   swatch names its axis as well as its colour. */
.costs__legend {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2) var(--s-5);
  font-size: var(--fs-xs);
  line-height: var(--lh-normal);
  color: var(--text-body);
}
.costs__legend-item {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  white-space: nowrap;
}
.costs__swatch {
  width: var(--s-5);
  height: 2px;
  border-radius: var(--r-pill);
  flex: none;
}
.costs__legend-item--vol .costs__swatch { background: var(--c-brand); }
.costs__legend-item--cost .costs__swatch { background: var(--c-slate); }

/* ---------------- Block A — volume + cost chart ---------------- */

.costs__card--plot { padding: var(--s-4) var(--s-4) var(--s-3); }

@media (min-width: 640px) {
  .costs__card--plot { padding: var(--s-5) var(--s-6) var(--s-4); }
}

/* plot: the SVG is drawn at the container's real pixel size, so the
   aspect ratio here is the single source of truth for chart height. */
.costs__plot {
  position: relative;
  width: 100%;
  aspect-ratio: 4 / 3;
  touch-action: pan-y;
}
@media (min-width: 560px)  { .costs__plot { aspect-ratio: 16 / 9; } }
@media (min-width: 900px)  { .costs__plot { aspect-ratio: 21 / 8; } }
@media (min-width: 1200px) { .costs__plot { aspect-ratio: 24 / 7; } }

.costs__svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
}

.costs__hint {
  max-width: 78ch;
  margin-top: var(--s-3);
  font-size: var(--fs-xs);
  line-height: var(--lh-relaxed);
  color: var(--text-body);
}

/* gradient stops — the fill reaches zero opacity at the baseline, so a
   floored axis never reads as an area measured from zero. */
.costs__fill-top { stop-color: var(--c-brand); stop-opacity: .20; }
.costs__fill-mid { stop-color: var(--c-brand); stop-opacity: .07; }
.costs__fill-bot { stop-color: var(--c-brand); stop-opacity: 0; }

.costs__grid {
  stroke: var(--c-hairline-soft);
  stroke-width: 1;
  shape-rendering: crispEdges;
}
.costs__grid--base { stroke: var(--c-hairline); }

/* Axis labels are load-bearing labels for money figures, so they take
   body ink rather than a muted tone. */
.costs__axis {
  font-family: var(--font-sans);
  font-size: var(--fs-xs);
  font-weight: var(--fw-medium);
  font-variant-numeric: tabular-nums;
  fill: var(--text-body);
}
.costs__axis--x { font-weight: var(--fw-regular); }

.costs__line { stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }
.costs__line--vol  { stroke: var(--c-brand); }
.costs__line--cost { stroke: var(--c-slate); }

.costs__focus { transition: opacity var(--t-fast) var(--ease-out); }
.costs__focus-rule {
  stroke: var(--c-hairline);
  stroke-width: 1;
  shape-rendering: crispEdges;
}
.costs__focus-dot {
  stroke: var(--surface);
  stroke-width: 2;
}
.costs__focus-dot--vol  { fill: var(--c-brand); }
.costs__focus-dot--cost { fill: var(--c-slate); }

/* tooltip — shown and hidden with the `hidden` attribute, so it has no
   transition to suppress under reduced motion. Fixed width, not
   min-width: a card whose size cannot change with the month can be
   measured once per layout instead of on every pointermove. */
.costs__tip {
  position: absolute;
  z-index: var(--z-raised);
  display: grid;
  gap: var(--s-1);
  width: 26ch;
  padding: var(--s-3);
  transform: translate(-50%, calc(-100% - var(--s-3)));
  background: var(--surface);
  border: 1px solid var(--c-hairline);
  border-radius: var(--r-md);
  box-shadow: var(--sh-md);
  font-size: var(--fs-xs);
  line-height: var(--lh-normal);
  pointer-events: none;
}
.costs__tip[hidden] { display: none; }
.costs__tip--below { transform: translate(-50%, var(--s-3)); }

.costs__tip-month {
  font-weight: var(--fw-semi);
  color: var(--text-strong);
  letter-spacing: var(--tracking-snug);
}
.costs__tip-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s-5);
}
.costs__tip-row--sub {
  margin-top: var(--s-1);
  padding-top: var(--s-2);
  border-top: 1px solid var(--c-hairline-soft);
}
.costs__tip-key { color: var(--text-body); }
.costs__tip-val {
  font-weight: var(--fw-semi);
  color: var(--text-strong);
  font-variant-numeric: tabular-nums;
}

/* ---------------- Block B — ledger ---------------- */

.costs__ledger-icon {
  width: var(--s-4); height: var(--s-4);
  flex: none;
  color: var(--c-brand);
}

.costs__verdict {
  max-width: 78ch;
  margin-top: var(--s-3);
  font-size: var(--fs-sm);
  line-height: var(--lh-relaxed);
  color: var(--text-body);
}

/* scroll shell + edge fade */
.costs__scroll-wrap { position: relative; }
/* The fade is only visible by what it eats. A 12% stop over white ate
   almost nothing; holding full surface across the first third of the
   band cuts the last column off mid-figure, which is the whole point. */
.costs__scroll-wrap::after {
  content: "";
  position: absolute;
  top: 1px; right: 1px; bottom: 1px;
  width: var(--s-10);
  border-radius: 0 var(--r-lg) var(--r-lg) 0;
  background: linear-gradient(270deg, var(--surface) 0%, var(--surface) 34%, transparent 100%);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--t-base) var(--ease-out);
}
.costs__scroll-wrap.is-scrollable::after { opacity: 1; }
.costs__scroll-wrap.is-scrollable.is-end::after { opacity: 0; }

.costs__scroll {
  overflow-x: auto;
  overscroll-behavior-x: contain;
  border-radius: var(--r-lg);
}

/* table — every data cell is nowrap, so the table's own content width is
   the scroll threshold. No invented min-width. */
.costs__table {
  width: 100%;
  border-collapse: collapse;
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}

/* Numeric cells are padded to --s-3, not --s-4: eight columns at 16px a
   side spent 256px on whitespace and pushed the effective-rate column
   past the 1240px container. The label column keeps the wider gutter so
   the table still starts on the card's optical edge. */
.costs__th,
.costs__td,
.costs__rowhead {
  padding: var(--s-3);
  border-bottom: 1px solid var(--c-hairline-soft);
  white-space: nowrap;
}
.costs__th:last-child,
.costs__td:last-child { padding-right: var(--s-4); }

/* Headers wrap, cells do not. Each column can then shrink to its longest
   header word when space is tight and sit on one line when it is not —
   no <br>, so no "Cross-border& FX" in the accessible name. */
.costs__th {
  font-size: var(--fs-xs);
  font-weight: var(--fw-semi);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--text-body);
  text-align: right;
  vertical-align: bottom;
  white-space: normal;
  line-height: var(--lh-snug);
  border-bottom-color: var(--c-hairline);
}
.costs__th--label { text-align: left; }

/* z-index is not optional on a sticky column: without it the row head and
   the later share cell both land in the "positioned, auto z-index" paint
   step, and the share cell's track and bar paint straight over the pinned
   label as soon as the table scrolls. */
.costs__rowhead {
  position: sticky;
  left: 0;
  z-index: var(--z-base);
  background: var(--surface);
  text-align: left;
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  color: var(--text-strong);
}
.costs__rowhead,
.costs__th--label { padding-left: var(--s-4); }
.costs__th--label {
  position: sticky;
  left: 0;
  z-index: var(--z-base);
  background: var(--surface);
}

/* Seam under the sticky column, only once figures are actually sliding
   beneath it — otherwise it would read as a vertical rule. */
.costs__scroll-wrap.is-scrolled .costs__rowhead,
.costs__scroll-wrap.is-scrolled .costs__th--label {
  box-shadow: 1px 0 0 var(--c-hairline),
              var(--s-2) 0 var(--s-2) calc(var(--s-2) * -1) var(--c-hairline);
}

.costs__td {
  text-align: right;
  font-size: var(--fs-sm);
  color: var(--text-body);
}
.costs__td--rate {
  font-weight: var(--fw-semi);
  color: var(--text-strong);
}

.costs__tr:hover .costs__td,
.costs__tr:hover .costs__rowhead { background: var(--surface-alt); }

/* Share cell. Every fill starts at the same left edge of a common track,
   so seven bars of different length are comparable at a glance; the
   right-aligned numeral sits past the end of all but the total row's
   fill, so the figure is read on the surface, not on the ink. 10ch is
   the whole budget the column gets. */
.costs__th--share,
.costs__td--share { min-width: 10ch; }

.costs__td--share { position: relative; }
.costs__td--share::before,
.costs__bar {
  position: absolute;
  top: 50%;
  height: var(--s-5);
  transform: translateY(-50%);
  left: var(--s-3);
  border-radius: var(--r-xs);
  pointer-events: none;
}
.costs__td--share::before {
  content: "";
  right: var(--s-3);
  background: var(--c-hairline-soft);
}
.costs__bar {
  width: calc((100% - var(--s-6)) * var(--share-frac, 0));
  background: var(--costs-bar);
  box-shadow: inset 0 0 0 1px var(--costs-bar-edge);
}
.costs__bar-num { position: relative; }

.costs__tr--total .costs__td,
.costs__tr--total .costs__rowhead {
  border-bottom: 0;
  border-top: 1px solid var(--c-hairline);
  font-weight: var(--fw-semi);
  color: var(--text-strong);
}

/* Phone: the first two columns were taking three quarters of the viewport
   and no money column was on screen. The sticky label wraps instead of
   reserving ~200px for "Corporate / commercial", and the share column
   drops its bar and its 10ch reservation — a bare "21.2%" needs six
   characters, and share is the least decision-relevant number here.
   Volume then lands inside the first screenful. */
@media (max-width: 559px) {
  .costs__rowhead,
  .costs__th--label {
    white-space: normal;
    max-width: 13ch;          /* wide enough to keep "Corporate /" on one line */
    padding-right: var(--s-3);
  }
  .costs__rowhead { line-height: var(--lh-snug); text-wrap: balance; }

  .costs__th--share,
  .costs__td--share { min-width: 0; }
  .costs__td--share::before,
  .costs__bar { display: none; }
}

.costs__note {
  max-width: 78ch;
  margin-top: var(--s-4);
  font-size: var(--fs-xs);
  line-height: var(--lh-relaxed);
  color: var(--text-body);
}

@media (prefers-reduced-motion: reduce) {
  .costs__focus,
  .costs__scroll-wrap::after { transition: none; }
}
