/* ===========================================================================
   Groots Rewards — styles.css
   ---------------------------------------------------------------------------
   Mobile first. The base rules below ARE the 390px layout; the two min-width
   blocks at the bottom add the tablet and desktop columns.

   There is not one hex, rgba, gradient, radius, font size or duration written
   in this file. Every value arrives from config.js through tokens.js as a CSS
   custom property. Changing the palette is a one-file edit by construction.
   =========================================================================== */

/* --------------------------------------------------------------------------
   Reset and page
   -------------------------------------------------------------------------- */

*, *::before, *::after { box-sizing: border-box; }

html, body { margin: 0; padding: 0; }

body {
  background: var(--color-page);
  color: var(--color-text);
  font-family: var(--font-body);
  font-size: var(--text-body);
  line-height: var(--lh-body);
  -webkit-font-smoothing: antialiased;
  -webkit-text-size-adjust: 100%;
}

::selection { background: var(--color-selection); }

h1, h2, h3, h4 { margin: 0; font-family: var(--font-heading); line-height: var(--lh-head); }
p { margin: 0; }
ul { margin: 0; padding: 0; list-style: none; }

a {
  color: var(--color-accent);
  text-decoration: none;
}
a:hover { text-decoration: underline; }

button { font: inherit; }

.icon { flex-shrink: 0; display: block; }

.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

:focus-visible {
  outline: 2px solid var(--color-focus-ring);
  outline-offset: 2px;
}

/* --------------------------------------------------------------------------
   Shell
   -------------------------------------------------------------------------- */

.shell {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
  max-width: var(--max-width);
  margin: 0 auto;
  padding: var(--shell-pad-mobile);
  /* room for the fixed dev bar so it never sits on top of content */
  padding-bottom: calc(var(--space-10) + var(--space-9));
}

.sidebar { display: none; }

.main {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: var(--card-gap);
}

/* --------------------------------------------------------------------------
   Navigation
   -------------------------------------------------------------------------- */

.nav {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  flex: 1 1 auto;
}

.nav-link {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-4);
  min-height: var(--tap-target);
  border: 0;
  border-radius: var(--radius-nav);
  background: transparent;
  color: var(--color-text-muted);
  font-family: var(--font-body);
  font-size: var(--text-body);
  font-weight: var(--weight-medium);
  text-align: left;
  cursor: pointer;
  overflow: hidden;
  transition: background var(--dur-base) var(--ease), color var(--dur-base) var(--ease);
}

.nav-link:hover {
  background: var(--color-fill-hover);
  color: var(--color-text);
  text-decoration: none;
}

.nav-link.is-active {
  background: var(--color-accent-fill);
  color: var(--color-text);
  font-weight: var(--weight-semi);
}

.nav-link.is-active .icon { color: var(--color-accent); }

/* The gradient's first of exactly two uses: the active rail. */
.nav-link__rail {
  position: absolute;
  left: 0;
  top: var(--space-2);
  bottom: var(--space-2);
  width: var(--rail-width);
  border-radius: var(--rail-width);
  background: var(--gradient-brand-vertical);
}

.nav-link__soon {
  margin-left: auto;
  font-size: var(--text-micro);
  color: var(--color-text-muted);
  font-weight: var(--weight-medium);
}

/* --------------------------------------------------------------------------
   Phone navigation — Ruling 6.

   A sticky header carrying one trigger, which opens a floating panel over the
   page. Replaces the horizontally scrolling strip, which was not readable as
   navigation: only three of twelve destinations were ever on screen and
   nothing indicated the rest existed.
   -------------------------------------------------------------------------- */

.mobile-header {
  position: sticky;
  top: 0;
  z-index: 40;
  display: flex;
  align-items: center;
  padding: var(--space-2) 0;
  background: var(--color-page);
}

.nav-trigger {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-height: var(--tap-target);
  padding: var(--space-2) var(--space-5);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-control);
  background: var(--color-panel);
  color: var(--color-text);
  font-family: var(--font-body);
  font-size: var(--text-body);
  font-weight: var(--weight-semi);
  cursor: pointer;
  transition: background var(--dur-base) var(--ease),
              border-color var(--dur-base) var(--ease);
}

.nav-trigger:hover { background: var(--color-fill-hover); }
.nav-trigger.is-open { border-color: var(--color-accent-border); }

.nav-trigger .icon { color: var(--color-accent); }

/* Two labels, one shown at a time — the trigger is also the close control. */
.nav-trigger__state {
  display: flex;
  align-items: center;
  gap: var(--space-3);
}
.nav-trigger__state--open { display: none; }
.nav-trigger.is-open .nav-trigger__state--closed { display: none; }
.nav-trigger.is-open .nav-trigger__state--open { display: flex; }

.nav-backdrop {
  position: fixed;
  inset: 0;
  z-index: 70;
  background: var(--color-scrim);
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--dur-slow) var(--ease),
              visibility 0s linear var(--dur-slow);
}

.nav-backdrop.is-open {
  opacity: 1;
  visibility: visible;
  transition: opacity var(--dur-slow) var(--ease),
              visibility 0s linear 0s;
}

/* Anchored under the trigger rather than filling the screen, so it reads as a
   sub-menu of this page and not as a new page. */
.nav-sheet {
  position: fixed;
  top: var(--nav-sheet-top);
  left: var(--shell-pad-mobile);
  right: var(--shell-pad-mobile);
  z-index: 80;
  max-height: calc(100vh - var(--nav-sheet-top) - var(--shell-pad-mobile));
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  background: var(--color-panel);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-panel);
  box-shadow: var(--shadow-sheet);
  /* Tight padding is deliberate: twelve 44px rows plus a header and the help
     card have to clear 390x844 without the list scrolling inside itself. The
     spacing gives way, never the tap targets. */
  padding: var(--space-2);

  opacity: 0;
  visibility: hidden;
  transform: translateY(calc(var(--space-2) * -1));
  /* visibility flips instantly on open and only after the fade on close. If it
     were interpolated like the others, the menu would still be computed hidden
     on the first frame — and a hidden element silently refuses focus, which
     leaves the keyboard stranded behind an open menu. */
  transition: opacity var(--dur-slow) var(--ease),
              transform var(--dur-slow) var(--ease),
              visibility 0s linear var(--dur-slow);
}

.nav-sheet.is-open {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
  transition: opacity var(--dur-slow) var(--ease),
              transform var(--dur-slow) var(--ease),
              visibility 0s linear 0s;
}

/* Identity and balance, mirroring the welcome card so the number is one tap
   away from any screen. */
.nav-sheet__head {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-3);
  border-bottom: var(--border-hairline) solid var(--color-border);
  margin-bottom: var(--space-1);
}

.nav-sheet__avatar {
  width: 40px;
  height: 40px;
  border-radius: var(--radius-pill);
  background: var(--color-accent-fill);
  border: var(--border-width) solid var(--color-accent-border);
  color: var(--color-accent);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

.nav-sheet__name {
  font-family: var(--font-heading);
  font-size: var(--text-body);
  font-weight: var(--weight-semi);
}

.nav-sheet__credit {
  font-size: var(--text-small);
  color: var(--color-money);
  font-weight: var(--weight-semi);
}

.nav-sheet__list {
  display: flex;
  flex-direction: column;
}

/* Compact rather than shorter: the tap target stays 44px and the spacing
   between rows goes, so twelve destinations fit without internal scrolling. */
.nav-sheet__list .nav-link {
  padding-top: 0;
  padding-bottom: 0;
}

.nav-sheet__help {
  margin-top: var(--space-1);
  padding: var(--space-3) var(--space-3) 0;
  border-top: var(--border-hairline) solid var(--color-border);
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  align-items: flex-start;
}

.nav-sheet__help-title {
  font-family: var(--font-heading);
  font-size: var(--text-small);
  font-weight: var(--weight-semi);
}

.help-card {
  margin-top: var(--space-5);
  background: var(--color-fill-card);
  border: var(--border-hairline) solid var(--color-border);
  border-radius: var(--radius-control);
  padding: var(--space-4);
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.help-card__title {
  font-family: var(--font-heading);
  font-size: var(--text-body);
  font-weight: var(--weight-semi);
}

/* --------------------------------------------------------------------------
   Cards
   -------------------------------------------------------------------------- */

.card {
  position: relative;
  overflow: hidden;
  background: var(--color-panel);
  border: var(--border-hairline) solid var(--color-border);
  border-radius: var(--radius-panel);
  padding: var(--space-8);
  min-width: 0;
}

/* The gradient's second and last use: a 3px strip on the one hero card. */
.card--hero { border-width: var(--border-width); }

.card__strip {
  position: absolute;
  top: 0; left: 0; right: 0;
  height: var(--rail-width);
  background: var(--gradient-brand);
}

.card--flow {
  display: flex;
  flex-direction: column;
}

.card__title {
  font-family: var(--font-heading);
  font-size: var(--text-card);
  font-weight: var(--weight-semi);
}

/* A card title that is the only thing in the header row still needs the same
   space beneath it as one sitting in a .card__head. */
.card__title--spaced    { margin-bottom: var(--space-4); }
.card__title--spaced-lg { margin-bottom: var(--space-5); }

.card__head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--space-3);
  margin-bottom: var(--space-4);
}

.card__head--tight { margin-bottom: var(--space-3); }

.card__link {
  font-size: var(--text-meta);
  white-space: nowrap;
}

.card__foot {
  margin-top: auto;
  padding-top: var(--space-3);
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--text-meta);
  color: var(--color-text-muted);
}

/* --------------------------------------------------------------------------
   Rows. Base is one column — this is the 390px layout.
   -------------------------------------------------------------------------- */

.row {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--card-gap);
}

/* --------------------------------------------------------------------------
   Panel headings for the non-dashboard views
   -------------------------------------------------------------------------- */

.panel-head {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

.panel-head__title {
  font-family: var(--font-heading);
  font-size: var(--text-h2);
  font-weight: var(--weight-semi);
}

.panel-head__sub {
  font-size: var(--text-small);
  color: var(--color-text-muted);
  line-height: var(--lh-roomy);
  max-width: 60ch;
}

/* --------------------------------------------------------------------------
   Text utilities
   -------------------------------------------------------------------------- */

.label {
  font-size: var(--text-label);
  text-transform: uppercase;
  letter-spacing: var(--ls-label);
  color: var(--color-text-muted);
  font-weight: var(--weight-semi);
}

.muted { color: var(--color-text-muted); }
.small { font-size: var(--text-small); }
.meta  { font-size: var(--text-meta); }
.micro { font-size: var(--text-micro); }
.roomy { line-height: var(--lh-roomy); }
.accent { color: var(--color-accent); }
.money  { color: var(--color-money); }
.strong { font-weight: var(--weight-semi); }

/* --------------------------------------------------------------------------
   Buttons and links
   -------------------------------------------------------------------------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-height: var(--tap-target);
  padding: var(--space-3) var(--space-6);
  border: 0;
  border-radius: var(--radius-control);
  background: var(--color-button);
  color: var(--color-button-text);
  font-family: var(--font-body);
  font-size: var(--text-body);
  font-weight: var(--weight-semi);
  cursor: pointer;
  transition: background var(--dur-base) var(--ease), transform var(--dur-fast) var(--ease);
}

.btn:hover { background: var(--color-button-hover); }
.btn:active { transform: scale(0.97); }

.btn[disabled] {
  background: var(--color-fill-hover);
  color: var(--color-text-muted);
  cursor: not-allowed;
  transform: none;
}

.btn--ghost {
  background: transparent;
  border: var(--border-width) solid var(--color-border);
  color: var(--color-text);
}
.btn--ghost:hover { background: var(--color-fill-hover); }

/* Smaller type and tighter padding, but it keeps the 44px minimum height on
   mobile — the redeem amount presets are real tap targets. The height drops to
   its natural size from tablet up, where a mouse is doing the pointing. */
.btn--small {
  padding: var(--space-2) var(--space-4);
  font-size: var(--text-small);
}

.btn--block { width: 100%; }

.btn-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
}

.link-button {
  position: relative;
  border: 0;
  background: none;
  padding: 0;
  color: var(--color-accent);
  font-family: var(--font-body);
  font-size: var(--text-meta);
  cursor: pointer;
}
.link-button:hover { text-decoration: underline; }

/* The small text links are 12px by design, which is a 17px hit area — under the
   44px minimum. This grows the tappable box vertically without moving anything:
   the pseudo-element is transparent, absolutely positioned, and takes no part in
   layout, so baseline alignment inside .card__head is untouched.

   The expansion reaches 13.5px above and below the text, which is why
   .credit__foot below uses a 14px gap — otherwise this would clip the bottom
   edge of the button sitting above it and steal its taps. */
.link-button::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  height: var(--tap-target);
  transform: translateY(-50%);
}

.pill {
  display: inline-block;
  border: var(--border-width) solid var(--color-accent-border);
  color: var(--color-accent);
  border-radius: var(--radius-pill);
  padding: var(--space-1) var(--space-3);
  font-size: var(--text-micro);
  font-weight: var(--weight-semi);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  white-space: nowrap;
}

.chip {
  background: var(--color-accent-fill-strong);
  color: var(--color-accent);
  border-radius: var(--radius-pill);
  padding: var(--space-1) var(--space-3);
  font-size: var(--text-micro);
  font-weight: var(--weight-semi);
  white-space: nowrap;
}

/* --------------------------------------------------------------------------
   Welcome card
   -------------------------------------------------------------------------- */

.welcome {
  display: flex;
  flex-direction: column;
  gap: var(--space-6);
}

.welcome__top {
  display: flex;
  align-items: center;
  gap: var(--space-5);
  flex-wrap: wrap;
}

.avatar {
  width: 72px;
  height: 72px;
  border-radius: var(--radius-pill);
  background: var(--color-accent-fill);
  border: var(--border-width) solid var(--color-accent-border);
  color: var(--color-accent);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

.welcome__ident {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  min-width: 0;
}

.welcome__name-row {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  flex-wrap: wrap;
}

.welcome__name {
  font-size: var(--text-h1);
  font-weight: var(--weight-bold);
}

/* --------------------------------------------------------------------------
   Progress bars
   -------------------------------------------------------------------------- */

.progress { display: flex; flex-direction: column; gap: var(--space-2); }

.progress__row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--space-3);
  flex-wrap: wrap;
}

.progress__value {
  font-size: var(--text-body);
  font-weight: var(--weight-semi);
  color: var(--color-accent);
}

.progress__bar {
  height: var(--bar-height);
  border-radius: var(--radius-pill);
  background: var(--color-track);
  overflow: hidden;
}

.progress__fill {
  height: 100%;
  border-radius: var(--radius-pill);
  background: var(--color-accent);
}

/* The tier track's fill is MONEY, not XP — green, never cyan (Ruling 9). */
.progress__fill--money {
  background: var(--color-money);
}

/* The tier track's "your rate now" line. */
.tier-now {
  display: flex;
  align-items: baseline;
  gap: var(--space-3);
  flex-wrap: wrap;
}
.tier-now .money.strong {
  font-family: var(--font-heading);
  font-size: var(--text-stat);
  font-weight: var(--weight-bold);
  line-height: var(--lh-tight);
}

/* --------------------------------------------------------------------------
   Store credit card
   -------------------------------------------------------------------------- */

.credit__value {
  font-family: var(--font-heading);
  font-size: var(--text-hero);
  font-weight: var(--weight-bold);
  color: var(--color-money);
  line-height: var(--lh-tight);
}

.credit__sub {
  font-size: var(--text-small);
  color: var(--color-text-muted);
  line-height: var(--lh-roomy);
  margin-top: var(--space-2);
}

.credit__foot {
  margin-top: auto;
  padding-top: var(--space-6);
  display: flex;
  flex-direction: column;
  /* 14px, so the expanded hit area of the "How it works" link below cannot
     overlap the button above it. See .link-button::after. */
  gap: var(--space-4);
  align-items: flex-start;
}

/* --------------------------------------------------------------------------
   2x2 snapshot tiles
   -------------------------------------------------------------------------- */

.tiles {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-2);
}

.tile {
  background: var(--color-fill-tile);
  border: var(--border-hairline) solid var(--color-border);
  border-radius: var(--radius-tile);
  padding: var(--space-3);
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  min-width: 0;
}

.tile__icon { color: var(--color-text); }
.tile__icon--money  { color: var(--color-money); }
.tile__icon--accent { color: var(--color-accent); }

.tile__value {
  font-family: var(--font-heading);
  font-size: var(--text-stat);
  font-weight: var(--weight-bold);
  margin-top: var(--space-1);
}

.tile__value--money  { color: var(--color-money); }
.tile__value--accent { color: var(--color-accent); }

.tile__label {
  font-size: var(--text-micro);
  color: var(--color-text-muted);
  line-height: var(--lh-body);
}

/* --------------------------------------------------------------------------
   Level track — five bands. Phone gets the segment strip; the five-across
   grid appears from tablet up, where five columns are actually legible.
   -------------------------------------------------------------------------- */

.bands { display: none; }

.bands-compact {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.seg-track { display: flex; gap: var(--space-1); }

.seg {
  flex: 1 1 0;
  height: var(--seg-height);
  border-radius: var(--radius-pill);
  background: var(--color-track-empty);
}
.seg--done    { background: var(--color-accent-done); }
.seg--current { background: var(--color-accent); }

.bands-compact__now {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--text-small);
  font-weight: var(--weight-semi);
}
.bands-compact__now .icon { color: var(--color-accent); }

.band {
  min-width: 0;
  background: var(--color-fill-tile);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-tile);
  padding: var(--space-3);
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  opacity: 0.45;
}

.band--done {
  background: var(--color-accent-wash);
  border-color: var(--color-accent-border-soft);
  opacity: 1;
}

.band--current {
  background: var(--color-accent-fill-strong);
  border-color: var(--color-accent-border-loud);
  opacity: 1;
}

.band__badge {
  height: var(--space-6);
  display: flex;
  align-items: center;
  color: var(--color-accent);
}

.band__name {
  font-size: var(--text-small);
  font-weight: var(--weight-semi);
  color: var(--color-text-muted);
}
.band--done .band__name,
.band--current .band__name { color: var(--color-text); }

.band__range {
  font-size: var(--text-micro);
  color: var(--color-text-muted);
}

.band__tag {
  font-size: var(--text-micro);
  font-weight: var(--weight-semi);
  color: var(--color-accent);
  min-height: var(--space-5);
}

/* Provisional-data notice. Game doc 15 forbids presenting an unapproved level
   curve as promised progress, so wherever a level threshold is shown, this
   says so out loud. */
.notice {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
  margin-top: var(--space-4);
  padding-top: var(--space-3);
  border-top: var(--border-hairline) solid var(--color-border);
  font-size: var(--text-micro);
  color: var(--color-text-muted);
  line-height: var(--lh-body);
}
.notice .icon { margin-top: 1px; }

/* Pins the notice to the bottom of a flow card, so a short card in a tall row
   does not leave a hole between its content and its footnote. */
.notice--foot { margin-top: auto; }

/* --------------------------------------------------------------------------
   Next level reward
   -------------------------------------------------------------------------- */

.reward {
  display: flex;
  align-items: center;
  gap: var(--space-4);
}

.reward__icon {
  width: 64px;
  height: 64px;
  border-radius: var(--radius-tile);
  background: var(--color-accent-fill);
  border: var(--border-width) solid var(--color-accent-border);
  color: var(--color-accent);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

.reward__name {
  font-size: var(--text-body);
  font-weight: var(--weight-semi);
}

/* --------------------------------------------------------------------------
   Achievements grid
   -------------------------------------------------------------------------- */

.ach-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-3);
}

.ach {
  background: var(--color-fill-tile);
  border: var(--border-hairline) solid var(--color-border);
  border-radius: var(--radius-tile);
  padding: var(--space-3);
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  min-width: 0;
}

.ach__icon {
  width: 38px;
  height: 38px;
  border-radius: var(--radius-nav);
  background: var(--color-accent-fill);
  border: var(--border-width) solid var(--color-accent-border-soft);
  color: var(--color-accent);
  display: flex;
  align-items: center;
  justify-content: center;
}

.ach__name {
  font-size: var(--text-small);
  font-weight: var(--weight-semi);
}

.ach__desc {
  font-size: var(--text-micro);
  color: var(--color-text-muted);
  line-height: var(--lh-body);
}

.ach__tag {
  font-size: var(--text-micro);
  font-weight: var(--weight-semi);
  color: var(--color-text-muted);
  margin-top: auto;
}
.ach__tag--accent { color: var(--color-accent); }

/* --------------------------------------------------------------------------
   Simple row lists (challenges, activity, steps)
   -------------------------------------------------------------------------- */

.rows { display: flex; flex-direction: column; }

.rows__item {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-2) 0;
  border-bottom: var(--border-hairline) solid var(--color-border);
}
.rows__item:last-child { border-bottom: 0; }

.rows__item--top { align-items: flex-start; }

.rows__icon { color: var(--color-text-muted); padding-top: var(--space-1); }

.rows__body {
  flex: 1 1 auto;
  min-width: 0;
  font-size: var(--text-small);
  line-height: var(--lh-body);
}

.rows__title {
  font-size: var(--text-small);
  font-weight: var(--weight-semi);
}

.rows__sub {
  font-size: var(--text-meta);
  color: var(--color-text-muted);
  line-height: var(--lh-roomy);
  margin-top: var(--space-1);
}

.rows__meta {
  font-size: var(--text-meta);
  color: var(--color-text-muted);
  white-space: nowrap;
}

.rows__amount {
  font-weight: var(--weight-semi);
  white-space: nowrap;
}

.amount--earn  { color: var(--color-money); }
.amount--spend { color: var(--color-spend); }
.amount--xp    { color: var(--color-accent); }

/* --------------------------------------------------------------------------
   Empty states
   -------------------------------------------------------------------------- */

.empty {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  gap: var(--space-2);
  padding: var(--space-8) var(--space-3);
}

.empty__icon { color: var(--color-text-muted); }

.empty__title {
  font-size: var(--text-body);
  font-weight: var(--weight-semi);
}

.empty__body {
  font-size: var(--text-meta);
  color: var(--color-text-muted);
  line-height: var(--lh-roomy);
  max-width: 38ch;
}

/* --------------------------------------------------------------------------
   Ledger. Below 640px it is stacked cards; the table only appears above.
   -------------------------------------------------------------------------- */

.ledger { display: flex; flex-direction: column; gap: var(--space-3); }

.ledger-card {
  background: var(--color-fill-tile);
  border: var(--border-hairline) solid var(--color-border);
  border-radius: var(--radius-tile);
  padding: var(--space-4);
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.ledger-card__top {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-3);
}

.ledger-card__amount {
  font-family: var(--font-heading);
  font-size: var(--text-stat);
  font-weight: var(--weight-bold);
  white-space: nowrap;
}

.ledger-card__label {
  font-size: var(--text-small);
  font-weight: var(--weight-semi);
  line-height: var(--lh-body);
}

.ledger-card__row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-4);
  font-size: var(--text-meta);
  color: var(--color-text-muted);
}

.ledger-table { display: none; }

/* --------------------------------------------------------------------------
   Redeem flow
   -------------------------------------------------------------------------- */

.field {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.field__label {
  font-size: var(--text-small);
  font-weight: var(--weight-semi);
}

.input-wrap {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  background: var(--color-fill-tile);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-control);
  padding: 0 var(--space-4);
  transition: border-color var(--dur-base) var(--ease);
}

.input-wrap:focus-within { border-color: var(--color-accent-border); }

.input-wrap__prefix {
  font-family: var(--font-heading);
  font-size: var(--text-h1);
  font-weight: var(--weight-bold);
  color: var(--color-text-muted);
}

.input {
  flex: 1 1 auto;
  min-width: 0;
  min-height: var(--tap-target);
  border: 0;
  background: none;
  color: var(--color-text);
  font-family: var(--font-heading);
  font-size: var(--text-h1);
  font-weight: var(--weight-bold);
}
.input:focus { outline: none; }

/* Chrome's number spinners fight a large type size; the amount is typed. */
.input::-webkit-outer-spin-button,
.input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.input[type="number"] { -moz-appearance: textfield; }

.field__help {
  font-size: var(--text-meta);
  color: var(--color-text-muted);
  line-height: var(--lh-roomy);
}

.field__error {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
  font-size: var(--text-meta);
  color: var(--color-text);
  line-height: var(--lh-roomy);
  background: var(--color-accent-fill);
  border: var(--border-hairline) solid var(--color-accent-border-soft);
  border-radius: var(--radius-tile);
  padding: var(--space-3);
}
.field__error .icon { color: var(--color-accent); margin-top: 1px; }

.amount-presets {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.rule-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.rule-list__item {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-4);
  padding-bottom: var(--space-3);
  border-bottom: var(--border-hairline) solid var(--color-border);
}
.rule-list__item:last-child { border-bottom: 0; padding-bottom: 0; }

/* Every limit is disclosed at the same type size as the rate — CLAUDE.md
   section 5. That is what these two rules are for. */
.rule-list__name,
.rule-list__value {
  font-size: var(--text-body);
}
.rule-list__name { color: var(--color-text-muted); }
.rule-list__value { font-weight: var(--weight-semi); text-align: right; }

.code-box {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  background: var(--color-money-fill);
  border: var(--border-width) solid var(--color-money);
  border-radius: var(--radius-tile);
  padding: var(--space-5);
}

.code-value {
  font-family: var(--font-mono);
  font-size: var(--text-h2);
  font-weight: var(--weight-bold);
  letter-spacing: var(--ls-label);
  word-break: break-all;
}

.code-path {
  font-family: var(--font-mono);
  font-size: var(--text-micro);
  color: var(--color-text-muted);
  word-break: break-all;
}

.toast {
  position: fixed;
  left: 50%;
  bottom: calc(var(--space-10) + var(--space-10));
  transform: translateX(-50%);
  z-index: 60;
  background: var(--color-panel);
  border: var(--border-width) solid var(--color-accent-border);
  border-radius: var(--radius-control);
  box-shadow: var(--shadow-float);
  padding: var(--space-3) var(--space-5);
  font-size: var(--text-small);
  font-weight: var(--weight-semi);
  display: flex;
  align-items: center;
  gap: var(--space-2);
}
.toast .icon { color: var(--color-money); }
.toast[hidden] { display: none; }

/* --------------------------------------------------------------------------
   Coming-soon placeholders. Final size and position, no fake numbers and no
   controls that do nothing (decisions-log section 7).
   -------------------------------------------------------------------------- */

.soon {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

.soon__head {
  display: flex;
  align-items: center;
  gap: var(--space-4);
}

.soon__icon {
  width: 52px;
  height: 52px;
  border-radius: var(--radius-tile);
  background: var(--color-fill-tile);
  border: var(--border-hairline) solid var(--color-border);
  color: var(--color-text-muted);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}

.soon__title {
  font-family: var(--font-heading);
  font-size: var(--text-card);
  font-weight: var(--weight-semi);
}

.soon__stage {
  font-size: var(--text-micro);
  color: var(--color-text-muted);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  font-weight: var(--weight-semi);
  margin-top: var(--space-1);
}

.soon__body {
  font-size: var(--text-small);
  color: var(--color-text-muted);
  line-height: var(--lh-roomy);
  max-width: 60ch;
}

.soon__list {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.soon__list li {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
  font-size: var(--text-small);
  color: var(--color-text-muted);
  line-height: var(--lh-body);
}
.soon__list .icon { color: var(--color-accent); margin-top: 2px; }

/* --------------------------------------------------------------------------
   Referrals
   -------------------------------------------------------------------------- */

.share-box {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  background: var(--color-fill-tile);
  border: var(--border-hairline) solid var(--color-border);
  border-radius: var(--radius-tile);
  padding: var(--space-5);
}

.share-code {
  font-family: var(--font-mono);
  font-size: var(--text-h2);
  font-weight: var(--weight-bold);
  letter-spacing: var(--ls-label);
  word-break: break-all;
}

/* 130px is chosen so four tiles land as 2x2 at 390px rather than a 1x4 stack,
   and spread out to a single row once there is width for it. */
.stat-strip {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
  gap: var(--space-3);
}

/* --------------------------------------------------------------------------
   Dev profile switcher. Deliberately looks like a dev tool, not a feature:
   mono label, hard-edged, pinned, and the word DEV is the first thing on it.
   -------------------------------------------------------------------------- */

.dev-bar {
  position: fixed;
  left: var(--space-5);
  right: var(--space-5);
  bottom: var(--space-5);
  z-index: 50;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-3);
  background: var(--color-panel);
  border: var(--border-width) dashed var(--color-accent-border);
  border-radius: var(--radius-control);
  box-shadow: var(--shadow-float);
}

.dev-bar__label {
  font-family: var(--font-mono);
  font-size: var(--text-micro);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  color: var(--color-text-muted);
}

.dev-bar__buttons {
  display: flex;
  gap: var(--space-1);
}

.dev-btn {
  flex: 1 1 0;
  min-height: var(--tap-target);
  padding: var(--space-2) var(--space-3);
  border: 0;
  border-radius: var(--radius-nav);
  background: transparent;
  color: var(--color-text-muted);
  font-family: var(--font-mono);
  font-size: var(--text-micro);
  font-weight: var(--weight-semi);
  cursor: pointer;
  transition: background var(--dur-base) var(--ease), color var(--dur-base) var(--ease);
}

.dev-btn:hover { background: var(--color-fill-hover); color: var(--color-text); }

.dev-btn.is-active {
  background: var(--color-button);
  color: var(--color-button-text);
}

.dev-bar__hint {
  font-size: var(--text-micro);
  color: var(--color-text-muted);
  line-height: var(--lh-body);
}

/* ==========================================================================
   TABLET AND UP — 901px. The sidebar returns and rows go two-up.
   ========================================================================== */

@media (min-width: 901px) {
  .shell {
    flex-direction: row;
    align-items: stretch;
    gap: var(--shell-gap);
    padding: var(--shell-pad);
    padding-bottom: var(--shell-pad);
  }

  .sidebar {
    display: block;
    width: var(--sidebar-width);
    flex-shrink: 0;
  }

  .sidebar__inner {
    position: sticky;
    top: var(--shell-pad);
    background: var(--color-panel);
    border: var(--border-hairline) solid var(--color-border);
    border-radius: var(--radius-panel);
    padding: var(--space-6) var(--space-3) var(--space-3);
    display: flex;
    flex-direction: column;
  }

  /* The whole phone navigation goes away; the sidebar is untouched by Ruling 6. */
  .mobile-header,
  .nav-sheet,
  .nav-backdrop { display: none; }

  .nav-link { min-height: auto; padding: var(--space-2) var(--space-4); }
  .btn--small { min-height: auto; }

  /* Five bands across, which is the approved desktop treatment. */
  .bands {
    display: grid;
    grid-template-columns: repeat(5, minmax(0, 1fr));
    gap: var(--space-2);
  }
  .bands-compact { display: none; }

  /* Row 1: hero spans the full width, the other two sit beneath it.
     Row 3: the same shape. */
  .row--1, .row--3 { grid-template-columns: 1fr 1fr; }
  .row--1 > :first-child,
  .row--3 > :first-child { grid-column: 1 / -1; }

  /* Bottom left on desktop: that corner is the empty space under the sidebar,
     so the switcher never sits on top of a card. */
  .dev-bar {
    right: auto;
    left: var(--space-8);
    bottom: var(--space-8);
    width: var(--sidebar-width);
  }

  .dev-btn { min-height: auto; }
}

/* ==========================================================================
   LEDGER TABLE — 641px and up. Below this it stays stacked cards, never a
   horizontally scrolling table (CLAUDE.md section 7).
   ========================================================================== */

@media (min-width: 641px) {
  .ledger { display: none; }

  .ledger-table {
    display: table;
    width: 100%;
    border-collapse: collapse;
  }

  .ledger-table th {
    text-align: left;
    font-size: var(--text-label);
    text-transform: uppercase;
    letter-spacing: var(--ls-label);
    color: var(--color-text-muted);
    font-weight: var(--weight-semi);
    padding: 0 var(--space-3) var(--space-3) 0;
    border-bottom: var(--border-hairline) solid var(--color-border);
    white-space: nowrap;
  }

  .ledger-table td {
    padding: var(--space-4) var(--space-3) var(--space-4) 0;
    border-bottom: var(--border-hairline) solid var(--color-border);
    font-size: var(--text-small);
    vertical-align: top;
  }

  .ledger-table tr:last-child td { border-bottom: 0; }

  .ledger-table th:last-child,
  .ledger-table td:last-child { text-align: right; padding-right: 0; }

  .ledger-table .cell-date { white-space: nowrap; color: var(--color-text-muted); }
  .ledger-table .cell-amount { font-weight: var(--weight-semi); white-space: nowrap; }
}

/* ==========================================================================
   DESKTOP — 1251px and up. The full approved three-up and two-up rows.
   ========================================================================== */

@media (min-width: 1251px) {
  .row--1 { grid-template-columns: 1.5fr 1fr 1.1fr; }
  .row--2 { grid-template-columns: 1.6fr 1fr; }
  .row--3 { grid-template-columns: 1.15fr 1fr 1fr; }

  .row--1 > :first-child,
  .row--3 > :first-child { grid-column: auto; }
}

/* ==========================================================================
   Reduced motion
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    transition-duration: 0ms !important;
    animation-duration: 0ms !important;
  }
  .btn:active { transform: none; }
}
