/* Component catalog (§7 DESIGN_SYSTEM.md). Each block anatomy matches the spec section number in comments. */

/* -- top bars ------------------------------------------------------ */
.demo-banner {
  background: var(--warn-bg);
  color: var(--warn-text);
  text-align: center;
  font-size: 13px;
  padding: var(--sp-1) var(--sp-2);
}
.operator-bar {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-3);
  background: var(--secondary-bg);
  font-size: 13px;
}
.operator-label { color: var(--hint); white-space: nowrap; }
#partner-switch {
  flex: 1;
  min-height: 32px;
  font-size: 14px;
  background: var(--bg);
  color: var(--text);
  border: 1px solid var(--section-separator);
  border-radius: var(--r-sm);
}
.viewing-as-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-3);
  background: var(--section-bg);
  color: var(--section-header-text);
  font-size: 13px;
  border-radius: var(--r-md);
  margin-bottom: var(--sp-2);
}
.viewing-as-bar button {
  background: none; border: none; color: var(--link); font-size: 13px; cursor: pointer; min-height: 32px;
}

/* -- 7.2 Card ------------------------------------------------------ */
/* CRITIQUE_c4.md #9 (cheapest fix, a): 7+ of 8 core screens read as
   unfinished/sparse rather than calm (55-75%+ empty viewport below the
   card). A few more px of internal padding + vertical rhythm between cards
   fills the frame more deliberately without restructuring any screen. */
.card {
  background: var(--secondary-bg);
  border-radius: var(--r-md);
  padding: 16px;
  margin-bottom: var(--sp-3);
}
.card-big { font-size: 22px; font-weight: 700; margin-bottom: 2px; }
.card-title { font-size: 20px; font-weight: 700; line-height: 1.2; margin-bottom: 2px; }
.card-small { font-size: 13px; color: var(--hint); }
.card-caption { font-size: 12px; color: var(--hint); margin-top: 6px; }

/* -- 7.3 HeroMoneyCard ---------------------------------------------- */
.hero-money {
  position: relative;
  background: var(--secondary-bg);
  border-radius: var(--r-md);
  padding: 16px 14px;
  margin-bottom: var(--sp-2);
  overflow: hidden;
}
.hero-money::before {
  content: "";
  position: absolute;
  inset: 0;
  /* CRITIQUE_c4.md #12: was a flat 10%, essentially invisible at normal
     viewing size — --hero-glow (tokens.css) is 16% light / 22% dark, and the
     radius is widened so it reads as a deliberate glow, not a rounding error. */
  background: radial-gradient(circle at 20% 20%, color-mix(in srgb, var(--brand-accent) var(--hero-glow), transparent), transparent 82%);
  pointer-events: none;
}
.hero-money.is-zero::before { display: none; }
/* CRITIQUE_c3.md P0 #2: the decorative glow implies "there's a real number
   here", which is misleading for the honest-unknown state. */
.hero-money.is-unknown::before { display: none; }
.hero-money.is-stale { background: var(--warn-bg); }
.hero-eyebrow {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--hint);
  margin-bottom: 4px;
}
.hero-row { display: flex; align-items: baseline; gap: var(--sp-2); position: relative; }
.hero-figure {
  font-size: 28px;
  font-weight: 700;
  line-height: 1.15;
  color: var(--brand-accent);
}
.hero-figure.is-zero { color: var(--text); }
.hero-sparkline { flex-shrink: 0; }
.hero-spark-wrap { margin-top: 6px; }
.hero-delta { font-size: 13px; font-weight: 600; }
.hero-delta.up { color: var(--st-ok); }
.hero-delta.down { color: var(--destructive-text); }
.hero-caption {
  font-size: 12px;
  color: var(--hint);
  margin-top: 6px;
  display: flex;
  align-items: center;
  gap: 4px;
  position: relative;
  cursor: pointer;
}
.hero-caption svg { flex-shrink: 0; }
/* CRITIQUE_c3.md P0 #2: the honest-unknown state's own figure/caption —
   distinct classes (not reusing .hero-figure/.hero-caption) so it never
   picks up .hero-caption's pointer cursor/click affordance, which would
   falsely imply this static line is tappable. */
.hero-figure-unknown {
  font-size: 17px;
  font-weight: 600;
  line-height: 1.3;
  color: var(--text);
}
.hero-caption-static {
  font-size: 12px;
  color: var(--hint);
  margin-top: 6px;
}
/* CRITIQUE_c5.md P1 #9: money.js's no-data hero card gained a real CTA
   (open the next-step flow for payout setup) — needed its own top margin
   since button.secondary has none of its own. */
.hero-money-cta { margin-top: 12px; }

/* -- 7.4 GateBanner / AlertBanner ------------------------------------ */
.gate-banner, .alert-banner {
  background: var(--alert-bg);
  color: var(--alert-text);
  border-radius: var(--r-md);
  padding: 10px 14px;
  margin-bottom: var(--sp-2);
  font-size: 14px;
  min-height: 44px;
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  cursor: pointer;
}
.gate-banner svg, .alert-banner svg { flex-shrink: 0; }
.gate-banner-text { flex: 1; }
.warn-banner {
  background: var(--warn-bg);
  color: var(--warn-text);
  border-radius: var(--r-md);
  padding: 10px 14px;
  margin-bottom: var(--sp-2);
  font-size: 13px;
  display: flex;
  align-items: center;
  gap: var(--sp-2);
}

/* -- 7.16 DaysCounterChip -------------------------------------------- */
.days-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  border-radius: var(--r-lg);
  padding: 3px 9px;
  font-size: 12px;
  font-weight: 600;
  background: var(--section-bg);
  color: var(--hint);
  white-space: nowrap;
}
.days-chip.warn { background: var(--warn-bg); color: var(--warn-text); }
.days-chip.alert { background: var(--alert-bg); color: var(--alert-text); }

/* -- 7.5 ForecastBlock ------------------------------------------------ */
.forecast-block {
  background: var(--section-bg);
  color: var(--hint);
  border-left: 2px dashed var(--hint);
  border-radius: 0 var(--r-md) var(--r-md) 0;
  padding: 10px 14px;
  margin-bottom: var(--sp-2);
  font-size: 13px;
  display: flex;
  align-items: flex-start;
  gap: 6px;
}
.forecast-block svg { flex-shrink: 0; margin-top: 1px; }
.forecast-label { display: flex; align-items: center; gap: 5px; font-weight: 600; }
.forecast-figure { font-size: 16px; font-weight: 700; color: var(--text); margin-top: 2px; }
.forecast-note { margin-top: 2px; }
/* CRITIQUE_c1.md #4: label/figure/note were 3 flex-row children with no
   flex-basis control — at 390px each one wraps onto multiple lines next to
   the dashed border, reading as a broken 3-column layout. Stack vertically
   below ~420px so it reads as one sentence with a callout number instead. */
@media (max-width: 420px) {
  .forecast-block { flex-direction: column; align-items: flex-start; gap: 2px; }
}

/* -- 7.6 StatusChip / health chips ------------------------------------ */
/* CRITIQUE_c4.md #10: flex-wrap let an odd chip out (e.g. "Не опубликовано
   1") strand itself alone on a second row — reads as a layout accident.
   One scrollable row reads as a designed state at any chip count. */
.chips {
  display: flex;
  gap: var(--sp-2);
  flex-wrap: nowrap;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
  margin: 6px 0;
  padding-bottom: 2px;
}
.chips::-webkit-scrollbar { display: none; }
.status-chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  background: var(--secondary-bg);
  border-radius: var(--r-lg);
  padding: 6px 12px;
  font-size: 13px;
  min-height: 32px;
  cursor: pointer;
  border: none;
  color: var(--text);
  flex-shrink: 0;
}
.status-chip svg { flex-shrink: 0; }
.status-chip.st-ok { color: var(--st-ok); }
.status-chip.st-broken { color: var(--st-broken); }
.status-chip.st-repair { color: var(--st-repair); }
.status-chip.st-unpublished { color: var(--st-unpublished); }
.plain-chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  background: var(--section-bg);
  border-radius: var(--r-lg);
  padding: 3px 10px;
  font-size: 12px;
  color: var(--hint);
}

/* -- 7.7 ActorListRow / ActorTag -------------------------------------- */
.list-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 4px;
  min-height: 44px;
  border-bottom: 1px solid var(--section-separator);
  cursor: pointer;
}
.list-row:active { background: var(--section-bg); }
.status-dot { width: 10px; height: 10px; border-radius: var(--r-full); flex-shrink: 0; }
.status-dot.st-ok { background: var(--st-ok); }
.status-dot.st-broken { background: var(--st-broken); }
.status-dot.st-repair { background: var(--st-repair); }
.status-dot.st-unpublished { background: var(--st-unpublished); }

.row-main { flex: 1; min-width: 0; }
.row-title-line { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.row-title { font-size: 15px; }
.row-sub { font-size: 12px; color: var(--hint); margin-top: 2px; }
.chevron { flex-shrink: 0; color: var(--hint); }

.actor-tag {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  font-size: 11px;
  font-weight: 500;
  border-radius: var(--r-lg);
  padding: 2px 8px;
  white-space: nowrap;
}
.actor-tag.niche { border: 1px solid var(--brand-accent); color: var(--brand-accent); }
.actor-tag.fleet { border: 1px solid var(--hint); color: var(--hint); }

/* -- 7.8 ProgressRing --------------------------------------------------- */
.ring-wrap { display: inline-flex; align-items: center; justify-content: center; position: relative; }
.ring-center { position: absolute; text-align: center; }
.ring-num { font-size: 15px; font-weight: 700; line-height: 1.1; }
.ring-label { font-size: 10px; color: var(--hint); }
/* CRITIQUE_c3.md P1 #6: was --section-bg, the same color as the ring's own
   card background — at 0 points the track was effectively invisible. */
.ring-track { stroke: var(--ring-track); fill: none; }
.ring-arc { stroke: var(--brand-accent); fill: none; stroke-linecap: round; transition: stroke-dashoffset var(--m-chart) var(--ease-standard); }
.ring-dot { fill: var(--brand-accent); }

/* Signature Moment #1 (CRITIQUE_c4.md #4): the one "heavy haptic" moment in
   the app — a tier promotion — gets a spring pulse on the ring using the
   --m-cheer/--ease-spring pair the design system reserved and never used. */
@keyframes cheerPulse {
  0% { transform: scale(1); }
  45% { transform: scale(1.16); }
  100% { transform: scale(1); }
}
.ring-wrap.cheer { animation: cheerPulse var(--m-cheer) var(--ease-spring) both; }

/* -- 7.9 Sparkline / bar chart ------------------------------------------ */
.chart-wrap { margin: var(--sp-2) 0; }
.chart-legend { font-size: 12px; color: var(--hint); margin-top: 4px; }
/* CRITIQUE_c4.md #2 / Signature Moment #3: staggered scaleY entrance, using
   the already-declared --m-chart token end to end (charts.js sets the
   per-bar animation-delay). transform-box:fill-box is needed for an SVG
   <rect> to scale from its own bottom edge instead of the viewport origin. */
@keyframes barEnter {
  from { transform: scaleY(0); }
  to { transform: scaleY(1); }
}
.bar-fact {
  fill: var(--brand-accent);
  transform-box: fill-box;
  transform-origin: bottom;
  animation: barEnter var(--m-chart) var(--ease-standard) both;
}
.bar-label { font-size: 9px; fill: var(--hint); }
.forecast-line { stroke: var(--hint); stroke-dasharray: 4,3; fill: none; }
.spark-line { stroke: color-mix(in srgb, var(--text) 60%, transparent); stroke-width: 2; fill: none; }

/* -- 7.11 JournalRow ----------------------------------------------------- */
.journal-row { display: flex; gap: 10px; padding: 10px 4px; border-bottom: 1px solid var(--section-separator); }
.journal-row svg { flex-shrink: 0; color: var(--hint); margin-top: 2px; }
.journal-time { font-size: 11px; color: var(--hint); margin-bottom: 2px; }
.journal-text { font-size: 14px; }

/* -- 7.12 Accordion / lesson row ------------------------------------------ */
.accordion-track { border-bottom: 1px solid var(--section-separator); }
.accordion-head {
  padding: 10px 4px;
  font-size: 15px;
  min-height: 44px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  cursor: pointer;
}
.accordion-head svg { transition: transform var(--m-swap) var(--ease-standard); color: var(--hint); }
.accordion-track.open .accordion-head svg { transform: rotate(180deg); }
.accordion-track.locked .accordion-head { color: var(--hint); cursor: default; }
/* CRITIQUE_c4.md #8: display:none/block snapped the body open/shut instantly
   while the chevron above it eased over --m-swap — a chevron visibly easing
   into position while pointing at content that already instant-snapped
   reads as unfinished. Standard CSS-grid accordion trick: 0fr -> 1fr,
   same duration as the chevron, no JS timing needed. */
.accordion-body {
  display: grid;
  grid-template-rows: 0fr;
  overflow: hidden;
  transition: grid-template-rows var(--m-swap) var(--ease-standard);
}
.accordion-body-inner { min-height: 0; overflow: hidden; padding: 0 4px 8px; }
.accordion-track.open .accordion-body { grid-template-rows: 1fr; }
.lesson-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 8px 0;
  min-height: 44px;
  gap: 8px;
}
.lesson-row-title { display: flex; align-items: center; gap: 8px; }
.lesson-points { font-weight: 700; color: var(--brand-accent); font-size: 13px; }

/* -- 7.13 LadderRow ---------------------------------------------------------- */
.ladder-row {
  padding: 10px 4px 10px 12px;
  border-left: 3px solid transparent;
  border-bottom: 1px solid var(--section-separator);
}
.ladder-row.current { border-left-color: var(--brand-accent); font-weight: 700; }
.ladder-name { font-size: 15px; }
.ladder-meta { font-size: 12px; color: var(--hint); margin-top: 2px; }

/* -- 7.14 StatementBlock ------------------------------------------------------ */
.money-block { margin-bottom: 14px; }
.money-line { padding: 4px 0; font-size: 14px; display: flex; justify-content: space-between; gap: 8px; }
.money-line-held { font-style: italic; color: var(--hint); font-size: 12px; padding-left: 8px; }
.money-total { font-size: 20px; font-weight: 700; margin: 10px 0; }
.money-total.to-bond { color: var(--text); }
.money-total.from-bond { color: var(--brand-accent); }
.money-direction { font-size: 13px; color: var(--hint); }

/* -- 7.15 Empty / Error ------------------------------------------------------- */
.error-card {
  background: var(--alert-bg);
  color: var(--alert-text);
  border-radius: var(--r-md);
  padding: 14px;
  text-align: center;
}
.empty-card { color: var(--hint); font-size: 14px; padding: 24px 8px; text-align: center; }
.empty-card svg { display: block; margin: 0 auto 8px; color: var(--hint); opacity: 0.6; }

/* -- 7.17 ContinuationPlate ---------------------------------------------------- */
.continuation-plate {
  background: var(--section-bg);
  border-radius: var(--r-md);
  padding: 14px;
  margin-bottom: var(--sp-2);
  display: flex;
  gap: 10px;
}
.continuation-plate svg { flex-shrink: 0; color: var(--brand-accent); }

/* -- 7.18 HowItWorksStep -------------------------------------------------------- */
.how-step { display: flex; gap: 12px; margin-bottom: var(--sp-4); align-items: flex-start; }
.how-step-num {
  width: 28px; height: 28px; border-radius: var(--r-full);
  background: var(--section-bg);
  border: 1.5px solid var(--brand-accent);
  color: var(--brand-accent);
  display: flex; align-items: center; justify-content: center;
  font-weight: 700; font-size: 13px; flex-shrink: 0;
}
.how-step-text { font-size: 15px; line-height: 1.4; padding-top: 3px; }

/* -- 7.19 InviteChecklist -------------------------------------------------------- */
.gate-check { display: flex; gap: 8px; padding: 7px 0; align-items: center; font-size: 14px; }
.gate-check svg { flex-shrink: 0; }
.gate-check.done svg { color: var(--st-ok); }
.gate-check.pending svg { color: var(--hint); }

/* -- 7.20/7.21 OperatorTableRow / HealthScoreBadge -------------------------------- */
.op-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 4px;
  border-bottom: 1px solid var(--section-separator);
  cursor: pointer;
}
.op-row-main { flex: 1; min-width: 0; }
.op-row-name-line { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.op-row-name { font-weight: 600; font-size: 15px; }
.op-row-action { font-size: 12px; color: var(--hint); margin-top: 2px; }
.op-dup-flag { color: var(--st-broken); display: inline-flex; align-items: center; gap: 3px; font-size: 11px; }
.health-badge {
  flex-shrink: 0; border-radius: var(--r-lg); padding: 3px 9px; font-size: 12px; font-weight: 700;
  background: var(--section-bg); color: var(--hint);
}
.health-badge.tone-ok { background: color-mix(in srgb, var(--st-ok) 16%, transparent); color: var(--st-ok); }
.health-badge.tone-warn { background: var(--warn-bg); color: var(--warn-text); }
.health-badge.tone-alert { background: var(--alert-bg); color: var(--alert-text); }
/* CRITIQUE_c5.md rework #3: .op-checkbox used to be a bare <button> with no
   reset at all — the browser's own default button chrome (background +
   border) rendered underneath the SVG square icon, looking like two
   overlapping squares (white + black). Renamed to .op-select-btn to match
   the new labelled markup (icon + "связался?" text), fully reset. */
.op-select-btn {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  background: none;
  border: none;
  margin: 0;
  padding: 5px 7px;
  border-radius: var(--r-sm);
  color: var(--hint);
  font-size: 12px;
  font-family: inherit;
  cursor: pointer;
  white-space: nowrap;
}
.op-select-btn.selected { color: var(--accent-text); background: var(--secondary-bg); }
.op-contacted-chip {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 12px;
  color: var(--st-ok);
  white-space: nowrap;
}
/* CRITIQUE_c5.md rework #3: this chip is days_stuck (time in current gate
   status) — a completely different fact from contact recency, but sat
   right next to the contact control with zero label, easy to misread as
   "last contacted today". */
.op-days-wrap { flex-shrink: 0; display: inline-flex; align-items: center; gap: 4px; }
.op-days-label { font-size: 10px; color: var(--hint); white-space: nowrap; }
button.secondary.op-confirm-payout {
  flex-shrink: 0; width: auto; min-height: 32px; padding: 6px 10px; font-size: 12px;
}
/* CRITIQUE_c5.md rework #1: the console's own duplicate-decision block —
   native <details>/<summary>, no JS needed to expand/collapse. */
.op-dup-groups { margin-bottom: var(--sp-2); }
.op-dup-groups summary { font-weight: 600; cursor: pointer; }
.op-dup-group-row { padding: 8px 0; border-top: 1px solid var(--section-separator); }
.op-dup-group-row .row-sub { color: var(--hint); font-size: 12px; }
.op-bulk-bar {
  position: sticky; top: 0; z-index: 5;
  display: flex; align-items: center; justify-content: space-between;
  background: var(--section-bg); border-radius: var(--r-md);
  padding: 8px 12px; margin-bottom: var(--sp-2); font-size: 13px;
}

/* -- sections / lists --------------------------------------------------------------- */
.section-title { font-size: 13px; color: var(--hint); margin: 14px 0 6px; font-weight: 600; }

/* -- buttons ---------------------------------------------------------------------- */
button.primary {
  background: var(--button);
  color: var(--button-text);
  border: none;
  border-radius: var(--r-sm);
  padding: 12px 16px;
  font-size: 15px;
  font-weight: 600;
  min-height: 44px;
  width: 100%;
  cursor: pointer;
  transition: transform var(--m-tap) var(--ease-standard);
}
button.primary:active { transform: scale(0.98); }
button.primary:disabled { opacity: 0.5; cursor: default; transform: none; }
button.secondary {
  background: transparent;
  color: var(--link);
  border: 1.5px solid var(--section-separator);
  border-radius: var(--r-sm);
  padding: 10px 14px;
  min-height: 44px;
  width: 100%;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  transition: transform var(--m-tap) var(--ease-standard);
}
button.secondary:active { transform: scale(0.98); }
.btn-row { display: flex; flex-direction: column; gap: 8px; margin-top: 10px; }

/* CRITIQUE_c1.md #7: the HTML fallback for MainButton/SecondaryButton only
   ever renders inside .fallback-btn-holder (telegram.js's fallbackHtmlBtn) —
   when opened outside a real Telegram client, --button/--button-text still
   mirror Telegram's own theme color (#2a7fff-ish blue), which clashes with
   this app's own brand accent everywhere else on the same screen. Scoped to
   just these two holders so the native MainButton/SecondaryButton inside a
   real Telegram client is untouched. */
.fallback-btn-holder button.primary { background: var(--brand-accent); color: #ffffff; }
.fallback-btn-holder button.secondary { color: var(--brand-accent); border-color: var(--brand-accent); }

.back-btn-fallback {
  background: none;
  border: none;
  color: var(--link);
  font-size: 15px;
  display: flex;
  align-items: center;
  gap: 4px;
  padding: 8px 0;
  min-height: 44px;
  cursor: pointer;
}

/* -- top header ---------------------------------------------------------------------- */
.screen-header {
  display: flex; align-items: center; justify-content: space-between;
  margin-bottom: var(--sp-2);
}
.screen-header h1 { font-size: 20px; font-weight: 700; margin: 0; }
.header-actions { display: flex; gap: 6px; }
.icon-btn {
  background: var(--secondary-bg);
  border: none;
  border-radius: var(--r-sm);
  width: 36px; height: 36px;
  display: flex; align-items: center; justify-content: center;
  color: var(--text);
  cursor: pointer;
}
/* CRITIQUE_c1.md #6/F: an icon with zero visible text is a control nobody
   can name — this variant adds a short visible label next to the icon so
   every header control says what it does, not just aria-label for screen
   readers. */
.icon-btn.labeled {
  width: auto;
  padding: 0 10px 0 8px;
  gap: 6px;
  font-size: 13px;
  font-weight: 600;
}
.card-stack > * + * { margin-top: var(--sp-3); }

/* Signature Moment #1 (CRITIQUE_c4.md #4) — one-line toast for the level-up
   moment. No stacking (only one at a time), fixed above the tab bar. */
.app-toast {
  position: fixed;
  left: 50%;
  bottom: calc(80px + env(safe-area-inset-bottom));
  transform: translate(-50%, 8px);
  background: var(--text);
  color: var(--bg);
  padding: 10px 16px;
  border-radius: var(--r-lg);
  font-size: 13px;
  font-weight: 600;
  opacity: 0;
  z-index: 20;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.18);
  transition: opacity var(--m-swap) var(--ease-standard), transform var(--m-swap) var(--ease-standard);
  pointer-events: none;
  max-width: calc(100vw - 32px);
  text-align: center;
}
.app-toast.show { opacity: 1; transform: translate(-50%, 0); }
.section-title-row { display: flex; align-items: center; justify-content: space-between; margin: 4px 0 8px; }
.link-btn {
  background: none; border: none; color: var(--link); font-size: 13px; font-weight: 600;
  cursor: pointer; min-height: 32px; padding: 4px 6px;
}

/* -- period switch --------------------------------------------------------------------- */
.period-switch { display: flex; gap: 6px; margin-bottom: var(--sp-2); }
.period-btn {
  border: none; background: var(--secondary-bg); color: var(--hint);
  border-radius: var(--r-lg); padding: 6px 12px; font-size: 13px; cursor: pointer;
  min-height: 32px;
}
.period-btn.active { background: var(--brand-accent); color: #fff; font-weight: 600; }

/* -- onboarding -------------------------------------------------------------------------- */
/* CRITIQUE_c4.md #9: curious_onboarding was the single most extreme dead-
   space case (75%+ empty) — title + 2 buttons pinned to the top of an
   otherwise-empty screen. Centering the content in a tall box reads as a
   deliberate welcome layout instead of an unfinished one; 62vh is a robust
   viewport fraction that doesn't need to know the exact header/tabbar px. */
.onboard-card {
  padding: var(--sp-2) 0 var(--sp-3);
  min-height: 62vh;
  display: flex;
  flex-direction: column;
  justify-content: center;
}
.onboard-title { font-size: 22px; font-weight: 700; margin-bottom: 8px; line-height: 1.25; }
.onboard-text { font-size: 15px; color: var(--text); line-height: 1.45; margin-bottom: var(--sp-4); }
.segment-q { font-size: 17px; font-weight: 700; margin-bottom: var(--sp-3); }
.segment-opt {
  display: block; width: 100%; text-align: left;
  background: var(--secondary-bg); border: none; border-radius: var(--r-md);
  padding: 14px; margin-bottom: 8px; font-size: 15px; color: var(--text);
  cursor: pointer; min-height: 44px;
}
.segment-opt:active { transform: scale(0.99); }

/* Home's compact gate hero card (CRITIQUE_c1.md #2/E) — condensed variant
   of .nextstep-hero: icon + title/why side by side instead of centered, so
   it reads at a glance without pushing the money card off screen. */
.home-gate-hero { cursor: pointer; text-align: left; }
.home-gate-hero-top { display: flex; align-items: flex-start; gap: 10px; }
.home-gate-hero .nextstep-days { justify-content: flex-start; margin-top: 8px; }

/* -- next-step hero icon --------------------------------------------------------------- */
.nextstep-hero { text-align: center; padding: var(--sp-5) 0 var(--sp-3); }
.nextstep-icon {
  width: 56px; height: 56px; border-radius: var(--r-full);
  background: var(--section-bg); color: var(--brand-accent);
  display: flex; align-items: center; justify-content: center;
  margin: 0 auto var(--sp-3);
}
.nextstep-title { font-size: 20px; font-weight: 700; margin-bottom: var(--sp-1); }
/* CRITIQUE_c3.md P0 #3: explicit font-size (belt-and-suspenders) — this
   class used to have none, so a bare use of it inside a large-text
   ancestor (.card-big, see home.js's home-gate-hero) silently inherited
   22px/700 instead of its intended small meta-line size. home.js's own fix
   also pairs this class with .hint-text; this rule guards any future
   reuse that doesn't. */
.nextstep-days { display: flex; align-items: center; justify-content: center; gap: 5px; color: var(--hint); font-size: 13px; }
.nextstep-why { font-size: 14px; color: var(--hint); text-align: left; margin: 0 0 var(--sp-3); }
.nextstep-steps {
  text-align: left; margin: 0 0 var(--sp-4); padding-left: 22px;
  font-size: 14px; line-height: 1.5; color: var(--text);
}
.nextstep-steps li { margin-bottom: 6px; }
.nextstep-cta { width: 100%; display: flex; align-items: center; justify-content: center; gap: 6px; margin-bottom: var(--sp-2); }
.nextstep-contact { width: 100%; margin-top: var(--sp-2); }

/* -- SWIFT -> Wise collapsible fallback (payout step only) --------------------------- */
.swift-fallback {
  text-align: left; background: var(--section-bg); border-radius: var(--r-md);
  padding: 10px 14px; margin-bottom: var(--sp-2); font-size: 13px;
}
.swift-fallback summary {
  cursor: pointer; font-weight: 600; color: var(--text); list-style: none;
  display: flex; align-items: center; justify-content: space-between; min-height: 24px;
}
.swift-fallback summary::-webkit-details-marker { display: none; }
.swift-fallback summary::after { content: "▾"; color: var(--hint); transform: rotate(-90deg); transition: transform var(--m-tap) var(--ease-standard); }
.swift-fallback[open] summary::after { transform: rotate(0deg); }
.swift-fallback p { margin: 8px 0 0; color: var(--hint); line-height: 1.45; }

/* -- offline banner ------------------------------------------------------------------- */
.offline-banner {
  background: var(--warn-bg); color: var(--warn-text);
  border-radius: var(--r-md); padding: 10px 14px; margin-bottom: var(--sp-2);
  font-size: 13px; display: flex; align-items: center; gap: 8px;
}

/* -- tabbar ------------------------------------------------------------------------------ */
.tabbar {
  position: fixed;
  bottom: 0; left: 0; right: 0;
  display: flex;
  background: var(--bottom-bar-bg);
  padding-bottom: env(safe-area-inset-bottom);
  border-top: 1px solid var(--section-separator);
  z-index: 10;
}
.tab {
  flex: 1;
  background: none;
  border: none;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  padding: 8px 4px;
  min-height: 56px;
  font-size: 11px;
  color: var(--hint);
  cursor: pointer;
}
.tab.active { color: var(--brand-accent); }
.tab svg { transition: transform var(--m-tap) var(--ease-standard); }
.tab:active svg { transform: scale(0.9); }

/* -- misc ------------------------------------------------------------------------------- */
.hint-text { color: var(--hint); font-size: 13px; }
.mb-2 { margin-bottom: 8px; }
.info-popover-trigger { cursor: pointer; }
