/* ============================================================
   00-shell — dashboard chrome: top bar, page header, savings hero,
   KPI row. Every selector scoped to .dash-*.

   Every colour, space, radius, shadow, duration and font-size is a
   token. The only raw values are 1px hairlines (allowed) and
   typographic measures in ch/em, which are relative to the type
   itself and have no token equivalent.
   ============================================================ */

/* Scoped to this section's own two roots, NOT to .dash-main — .dash-main
   wraps every sibling dashboard section, and declaring custom properties
   there would make them a de-facto shared API nobody documented. */
.dash-topbar,
.dash-shell {
  /* Directional delta colours. Mixed down into navy so both clear
     4.5:1 on white at 13px — the tint tokens alone do not. */
  --dash-pos: color-mix(in srgb, var(--c-lime) 40%, var(--c-navy));
  --dash-neg: color-mix(in srgb, var(--c-magenta) 68%, var(--c-navy));
  /* Brand at small sizes. Raw --c-brand is 4.70:1 on white and only
     4.14:1 on --c-brand-tint; 12% navy lifts both (5.41 / 4.77) past
     4.5:1 while staying visually brand. Used everywhere brand ink
     carries text rather than decoration. */
  --dash-brand-ink: color-mix(in srgb, var(--c-brand) 88%, var(--c-navy));
}

/* ------------------------------------------------------------
   Top bar
   ------------------------------------------------------------ */

.dash-topbar {
  position: sticky;
  top: 0;
  z-index: var(--z-nav);
  background: var(--surface);
  border-bottom: 1px solid var(--border);
  transition: box-shadow var(--t-base) var(--ease-out);
}
.dash-topbar.is-scrolled { box-shadow: var(--sh-xs); }

.dash-topbar__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-4);
  min-height: var(--s-10);
}

.dash-topbar__lead {
  display: flex;
  align-items: center;
  gap: var(--s-4);
  min-width: 0;
}

/* Padding gives the link the 44px target the contract requires; the
   matching negative margin keeps the wordmark optically flush with
   the container gutter. */
.dash-topbar__brand {
  display: flex;
  align-items: center;
  min-height: calc(var(--s-8) + var(--s-1));   /* 44px touch target */
  padding-inline: var(--s-2);
  margin-inline-start: calc(var(--s-2) * -1);
  color: var(--c-navy);
  transition: opacity var(--t-fast) var(--ease-out);
}
.dash-topbar__brand:hover { opacity: .7; }

.dash-topbar__wordmark {
  height: var(--s-5);
  width: auto;
}

.dash-topbar__rule {
  width: 1px;
  height: var(--s-5);
  background: var(--border);
}

.dash-topbar__label {
  font-size: var(--fs-xs);
  font-weight: var(--fw-medium);
  letter-spacing: var(--tracking-snug);
  color: var(--text-body);
  white-space: nowrap;
}

.dash-topbar__actions {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  min-width: 0;
}

/* ---- sticky total: the hero figure, once it has scrolled away ----
   Hidden with visibility rather than opacity alone, so while the hero is
   on screen the link is out of the tab order and out of the a11y tree —
   the same number must not be announced twice. */

.dash-topbar__pin {
  display: inline-flex;
  align-items: baseline;
  gap: var(--s-2);
  min-height: calc(var(--s-8) + var(--s-1));   /* 44px touch target */
  padding-inline: var(--s-3);
  border-radius: var(--r-pill);
  background: var(--c-brand-tint);
  color: var(--dash-brand-ink);
  font-size: var(--fs-xs);
  letter-spacing: var(--tracking-snug);
  white-space: nowrap;
  visibility: hidden;
  opacity: 0;
  transform: translateY(calc(var(--s-1) * -1));
  transition: opacity var(--t-base) var(--ease-out),
              transform var(--t-base) var(--ease-out),
              visibility var(--t-base) var(--ease-out),
              background-color var(--t-fast) var(--ease-out);
}
.dash-topbar.is-pinned .dash-topbar__pin {
  visibility: visible;
  opacity: 1;
  transform: none;
}
.dash-topbar__pin:hover {
  background: color-mix(in srgb, var(--c-brand) 15%, var(--c-white));
}

/* 4.78:1 on the tint at 13px semibold — the same ink the avatar uses. */
.dash-topbar__pin-amt {
  font-weight: var(--fw-bold);
  font-variant-numeric: tabular-nums;
}
.dash-topbar__pin-what { color: var(--text-body); }

/* ---- account identity (a label, not a control) ---- */

.dash-topbar__account {
  display: flex;
  align-items: baseline;
  gap: var(--s-2);
  min-width: 0;
}

.dash-topbar__acct-name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 22ch;
  font-size: var(--fs-sm);
  font-weight: var(--fw-semi);
  letter-spacing: var(--tracking-snug);
  color: var(--text-strong);
}

.dash-topbar__acct-meta {
  flex: none;
  font-size: var(--fs-xs);
  color: var(--text-body);
  white-space: nowrap;
}

/* ---- avatar monogram ---- */

.dash-avatar {
  display: grid;
  place-items: center;
  flex: none;
  width: var(--s-7);
  height: var(--s-7);
  border-radius: var(--r-pill);
  background: var(--c-brand-tint);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--c-brand) 20%, transparent);
  color: var(--dash-brand-ink);
  font-size: var(--fs-xs);
  font-weight: var(--fw-bold);
  letter-spacing: var(--tracking-normal);
  line-height: 1;
}

/* ------------------------------------------------------------
   Page header
   ------------------------------------------------------------ */

.dash-head { padding-top: clamp(var(--s-9), 6vw, var(--s-11)); }

/* h2 scale, not h1 scale. The page title is not the loudest thing on this
   screen — the money is. At --fs-h1 the title ran 60px against the hero's
   81px and the hierarchy collapsed; at --fs-h2 the figure wins ~2×. */
.dash-head__title {
  max-width: 18ch;
  font-size: var(--fs-h2);
}

/* Two grey sizes on this screen, not four: --fs-lead for the two lines
   that carry meaning (subhead, the fee/revenue split) and --fs-sm for the
   two that qualify them (sample-data note, hero footnote). */
.dash-head__sub {
  margin-top: var(--s-4);
  font-size: var(--fs-lead);
  line-height: var(--lh-normal);
  color: var(--text-body);
  font-variant-numeric: tabular-nums;
}

.dash-head__note {
  margin-top: var(--s-3);
  max-width: 68ch;
  font-size: var(--fs-sm);
  line-height: var(--lh-normal);
  color: var(--text-body);
}

.dash-head__badge {
  display: inline-block;
  margin-right: var(--s-2);
  padding: 0 var(--s-2);
  border-radius: var(--r-xs);
  background: var(--surface-alt);
  box-shadow: inset 0 0 0 1px var(--border);
  font-weight: var(--fw-semi);
  letter-spacing: var(--tracking-snug);
  color: var(--text-strong);
}

/* ------------------------------------------------------------
   Hero number — a restrained brand-tinted panel. One surface, one
   hairline ring, no shadow and no bloom: the figure is the only
   loud thing on it.
   ------------------------------------------------------------ */

.dash-hero { margin-top: clamp(var(--s-8), 5vw, var(--s-11)); }

.dash-hero__panel {
  padding: clamp(var(--s-5), 4vw, var(--s-9));
  border-radius: var(--r-xl);
  background: var(--c-brand-tint);
  /* Inset so the ring cannot add a pixel to the layout box. */
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--c-brand) 16%, transparent);
}

.dash-hero__eyebrow {
  display: block;
  color: var(--dash-brand-ink);
}

/* Degradation. With JS off the <noscript> copy renders in place of the
   figure; with JS on but the engine missing the runtime unhides the
   [data-dash="fallback"] twin and marks the shell degraded, which takes
   the empty number surfaces out of the flow rather than leaving skeleton
   bars sitting there forever. */
.dash-hero__fallback {
  margin-top: var(--s-4);
  max-width: 62ch;
  font-size: var(--fs-lead);
  line-height: var(--lh-normal);
  color: var(--text-body);
}

.dash-shell.is-degraded .dash-hero__figure,
.dash-shell.is-degraded .dash-hero__split,
.dash-shell.is-degraded .dash-hero__actions,
.dash-shell.is-degraded .dash-head__sub,
.dash-shell.is-degraded .dash-kpis-sec { display: none; }

/* Scaled past --fs-display so the metric beats the page title by ~2×,
   but capped by the viewport so 360px keeps the plain token size and the
   figure never outgrows the panel's content box. */
.dash-hero__figure {
  margin-top: var(--s-4);
  font-size: clamp(var(--fs-display), 11vw, calc(var(--fs-display) * 1.18));
  font-weight: var(--fw-bold);
  line-height: var(--lh-tight);
  letter-spacing: var(--tracking-tight);
  color: var(--text-strong);
  /* tabular-nums alone. Do NOT add font-feature-settings here: it is a
     single replaced value, so declaring it would drop base.css's inherited
     cv05/cv09/ss03 and render these numerals from a different design than
     every other number on the site. */
  font-variant-numeric: tabular-nums;
}

.dash-hero__cur {
  font-size: .5em;
  vertical-align: .62em;
  letter-spacing: var(--tracking-normal);
  margin-right: .04em;
  color: var(--c-brand);
}

/* No width lock and no inline-block: the count-up starts at the target's
   own digit count, so tabular-nums holds the box on its own. */

.dash-hero__per {
  font-size: .26em;
  vertical-align: 1.85em;
  /* "/" carries almost no left sidebearing, so at display size it welds
     itself to the last digit. .35em of a .26em unit ≈ .09em of the
     figure — the standard optical gap before a raised unit. */
  margin-left: .35em;
  font-weight: var(--fw-semi);
  letter-spacing: var(--tracking-snug);
  color: var(--text-body);
}

.dash-hero__split {
  margin-top: var(--s-5);
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--s-2) var(--s-4);
  font-size: var(--fs-lead);
  line-height: var(--lh-normal);
  color: var(--text-body);
}

.dash-hero__part {
  display: inline-flex;
  align-items: baseline;
  gap: var(--s-2);
}
.dash-hero__part::before {
  content: "";
  flex: none;
  width: var(--s-2);
  height: var(--s-2);
  border-radius: var(--r-pill);
  background: var(--c-brand);
  transform: translateY(-1px);
}
.dash-hero__part--rev::before { background: var(--dash-pos); }

.dash-hero__amt {
  font-weight: var(--fw-semi);
  color: var(--text-strong);
  font-variant-numeric: tabular-nums;
}

.dash-hero__plus {
  font-weight: var(--fw-semi);
  color: var(--text-body);
}

.dash-hero__foot {
  margin-top: var(--s-5);
  max-width: 62ch;
  font-size: var(--fs-sm);
  line-height: var(--lh-relaxed);
  color: var(--text-body);
  font-variant-numeric: tabular-nums;
}

.dash-hero__actions {
  margin-top: var(--s-7);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-3);
}

/* Ghost button, panel variant — a modifier, not a descendant restyle of
   the .btn primitive. On --c-brand-tint the stock ghost is invisible
   (transparent on tint) and its brand label is 4.14:1, under the 4.5:1
   this 17px label needs. White fill and --dash-brand-ink (4.77:1 on the
   tint, 5.41:1 on the fill) fix both. */
.btn--dash-ghost {
  --btn-bg: var(--surface);
  --btn-fg: var(--dash-brand-ink);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--c-brand) 26%, transparent);
}
.btn--dash-ghost:hover {
  background: var(--surface);
  color: var(--dash-brand-ink);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--c-brand) 48%, transparent);
}
/* Confirmation is not tint-on-tint: it swaps to the positive ink used by
   the KPI row (4.52:1 on the panel, 5.14:1 on the fill). */
.btn--dash-ghost.is-done {
  color: var(--dash-pos);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--dash-pos) 48%, transparent);
}

/* ------------------------------------------------------------
   KPI row
   ------------------------------------------------------------ */

.dash-kpis-sec { margin-top: var(--s-9); }

/* Hairlines are the 1px grid gap showing through — no per-cell borders,
   so nothing doubles up when the row wraps. */
.dash-kpis {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1px;
  background: var(--border);
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
}

.dash-kpi {
  background: var(--surface);
  padding-block: var(--s-6);
}

.dash-kpi__label {
  font-size: var(--fs-xs);
  font-weight: var(--fw-medium);
  letter-spacing: var(--tracking-snug);
  color: var(--text-body);
}

.dash-kpi__value {
  margin-top: var(--s-2);
  font-size: var(--fs-h3);
  font-weight: var(--fw-bold);
  line-height: var(--lh-snug);
  letter-spacing: var(--tracking-snug);
  color: var(--text-strong);
  /* See .dash-hero__figure: tabular-nums only, no font-feature-settings. */
  font-variant-numeric: tabular-nums;
}

/* 12-month sparkline. The box is reserved at exactly the svg's viewBox
   height whether or not the engine ever draws into it, so the delta line
   below cannot move when the trend lands. Quiet brand ink: it is context
   behind the value, not a second headline. */
.dash-kpi__spark {
  margin-top: var(--s-3);
  height: var(--s-6);
  color: color-mix(in srgb, var(--c-brand) 45%, var(--c-hairline));
}
.dash-kpi__spark-line {
  display: block;
  width: 100%;
  height: 100%;
}

/* Two lines are reserved on every tile so a wrapping delta on one cell
   cannot drop the row's baseline grid on the others. */
.dash-kpi__delta {
  margin-top: var(--s-2);
  min-height: calc(var(--fs-xs) * var(--lh-normal) * 2);
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--s-1) var(--s-2);
  font-size: var(--fs-xs);
  line-height: var(--lh-normal);
  color: var(--text-body);
  font-variant-numeric: tabular-nums;
}
.dash-kpi__delta.is-good { color: var(--dash-pos); }
.dash-kpi__delta.is-bad  { color: var(--dash-neg); }
.dash-kpi__delta.is-flat { color: var(--text-body); }

.dash-kpi__arrow {
  width: var(--s-3);
  height: var(--s-3);
  flex: none;
}

.dash-kpi__mag { font-weight: var(--fw-semi); }
.dash-kpi__vs { color: var(--text-body); font-weight: var(--fw-regular); }

@media (min-width: 640px) {
  .dash-kpis { grid-template-columns: repeat(2, 1fr); }
  .dash-kpi { padding-inline: var(--s-6); }
}
@media (min-width: 640px) and (max-width: 1023.98px) {
  .dash-kpi:nth-child(odd)  { padding-inline-start: 0; }
  .dash-kpi:nth-child(even) { padding-inline-end: 0; }
}
@media (min-width: 1024px) {
  .dash-kpis { grid-template-columns: repeat(4, 1fr); }
  .dash-kpi:first-child { padding-inline-start: 0; }
  .dash-kpi:last-child  { padding-inline-end: 0; }
}

/* ------------------------------------------------------------
   Skeletons — reserve the box a value will occupy before the engine
   writes into it, so nothing reflows when values land. The hero
   number keeps its box during the count-up too (see the runtime).
   ------------------------------------------------------------ */

.dash-skel:empty::after {
  content: "";
  display: inline-block;
  vertical-align: middle;
  height: .7em;
  border-radius: var(--r-xs);
  background: var(--c-hairline-soft);
}
/* Measured against the values that actually land, in tabular figures:
   a digit is 1ch, a comma ~.45ch, and "$" ~1.35ch (it is figure-width in
   this face, plus its sidebearings). Rounded UP, because a skeleton one
   notch too wide settles inward invisibly and one notch too narrow shoves
   the line.
     hero  "110,462"  → 6 + .45          = 6.45ch  (no "$": it is its own span)
     amt   "$96,561"  → 1.35 + 5 + .45   = 6.8ch
     kpi   "$269,269" → 1.35 + 6 + .45   = 7.8ch  (widest of the four tiles) */
.dash-skel--sub:empty::after  { width: 34ch; max-width: 100%; }
.dash-skel--hero:empty::after { width: 6.45ch; }
.dash-skel--amt:empty::after  { width: 6.8ch; }
.dash-skel--kpi:empty::after  { width: 7.8ch; }

/* ------------------------------------------------------------
   Small screens
   ------------------------------------------------------------ */

@media (max-width: 639.98px) {
  /* The h1 immediately below says the same thing; drop the label
     rather than truncate the business name. */
  .dash-topbar__rule,
  .dash-topbar__label { display: none; }

  /* The business type is in the popover-free label now; at 360px the name
     alone is all that fits beside the avatar, and the page header repeats
     both one line down. */
  .dash-topbar__acct-name { font-size: var(--fs-xs); max-width: 16ch; }
  .dash-topbar__acct-meta { display: none; }

  /* At 360px the bar fits the wordmark, one payload and the avatar. Once
     the total is pinned it IS the payload — the account name is repeated
     in the page header a line below, the total is not repeated anywhere
     on screen at that scroll position. */
  .dash-topbar__pin-what { display: none; }
  .dash-topbar.is-pinned .dash-topbar__account { display: none; }

  /* One line per kind of money. The wrapped description hangs flush with
     the amount above it rather than drifting under the bullet. */
  .dash-hero__split {
    display: grid;
    justify-items: start;
    gap: var(--s-3);
  }
  .dash-hero__part {
    display: grid;
    grid-template-columns: var(--s-2) 1fr;
    column-gap: var(--s-2);
    align-items: baseline;
  }
  .dash-hero__amt,
  .dash-hero__what { grid-column: 2; }
  /* Stacked, the "+" has nothing to join; the sr-only "plus" carries it. */
  .dash-hero__plus { display: none; }

  /* Grid rather than a width override on .btn — grid items stretch, so
     the buttons go full-bleed without restyling the base primitive. */
  .dash-hero__actions { display: grid; }
}
