/* Genie — Gemini-style design system. Dark by default, light via [data-theme].
   No external assets: the Google Sans stack is progressive (falls back to
   system-ui where the font isn't installed; nothing is fetched). */

:root {
  /* ---- dark palette (default) — Gemini's warm near-black ---- */
  --bg: #131314;
  --bg-elev: #1e1f20;
  --bg-elev-1: #232425;
  --bg-elev-2: #2a2b2d;
  --bg-elev-3: #333537;
  --border: #3a3b3d;
  --border-strong: #5f6063;
  --text: #e3e3e3;
  --text-dim: #c4c7c5;
  --text-faint: #9aa0a6;

  /* Mono accent — white on dark (black on light, see the light palette).
     --on-accent flips the text drawn on accent fills so it stays legible.
     The composed --grad/--grad-h below also flatten to this accent. */
  --accent: #ffffff;
  --accent-2: #ffffff;
  --on-accent: #131314;
  /* Tonal accent wash for selected/active surfaces (e.g. active pill tabs).
     Derived from --accent so it follows the theme (a faint white tint on dark,
     a faint black tint on light) — never a hardcoded hue. */
  --accent-dim: color-mix(in srgb, var(--accent) 14%, transparent);
  --grad-a: #4285f4;
  --grad-b: #9b72cb;
  --grad-c: #d96570;
  /* Functional accents (gradient text, progress bars, buttons) flatten to the mono
     accent — white on dark, black on light, theme-aware via var(--accent). The raw
     --grad-a/b/c stops above stay multi-color for the hero card + the two-color
     earn/team charts (which need distinguishable segments). */
  --grad: var(--accent);
  --grad-h: var(--accent);

  /* Text selection — a soft Gemini-blue wash. --grad-a is the same #4285f4 in
     both themes while --bg flips, so this single value stays a medium blue on
     dark and a light periwinkle on light; pairing it with --text keeps the
     selected copy legible. (Before, no ::selection rule existed and the OS
     default rendered the dim hint text dark-on-dark in the light theme.) */
  --selection-bg: color-mix(in srgb, var(--grad-a) 38%, var(--bg));
  --selection-fg: var(--text);

  --user-bubble: #2a3441;
  --user-bubble-border: #38465c;
  --ok: #6dd58c;
  --warn: #f3c969;
  --err: #f28b82;

  /* Destructive actions (delete / revert / failed). */
  --danger: #f28b82;
  --danger-text: #ffb4ab;
  --danger-bg: #3a1a1d;
  --danger-border: #6e2b2f;

  /* Banner tints. */
  --banner-info-bg: #1b2740;
  --banner-info-fg: #cdddff;
  --banner-info-bd: #2c4170;
  --banner-warn-bg: #3a3015;
  --banner-warn-fg: #f2dca0;
  --banner-warn-bd: #5e4d1f;
  --banner-error-bg: #3a1a1d;
  --banner-error-fg: #ffc9c9;
  --banner-error-bd: #6e2b2f;

  --shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.4);
  --shadow-md: 0 8px 28px rgba(0, 0, 0, 0.5);
  --shadow-lg: 0 18px 50px rgba(0, 0, 0, 0.6);

  /* Rounded-geometry scale. --radius-hero/-lg cover the larger Gemini-generous
     surfaces (heroes, modals, big cards) that previously hardcoded 20–28px. */
  --radius-hero: 28px;
  --radius-lg: 20px;
  --radius: 16px;
  --radius-md: 14px;
  --radius-sm: 12px;
  /* Small squircle for icon tiles / badge squares (was a sprawl of 8–11px). */
  --radius-tile: 10px;
  --gap: 16px;
  /* Material 3 "emphasized" easing. */
  --ease: cubic-bezier(0.2, 0, 0, 1);

  /* Type — Gemini's families. Text for body/UI, Flex for display/brand.
     Loaded from Google Fonts in index.html; falls back to the system font. */
  --font-ui: "Google Sans Text", "Google Sans Flex", "Google Sans", Roboto, system-ui, -apple-system, "Segoe UI", Helvetica, Arial, sans-serif;
  --font-display: "Google Sans Flex", "Google Sans Text", "Google Sans", Roboto, system-ui, sans-serif;
  --font-mono: "Google Sans Code", var(--font-mono);
}

/* ---- light palette — Gemini's soft blue-grey on white ---- */
:root[data-theme="light"] {
  --bg: #f0f4f9;
  --bg-elev: #ffffff;
  --bg-elev-1: #f0f4f9;
  --bg-elev-2: #e9eef6;
  --bg-elev-3: #dde3ea;
  --border: #dadce0;
  --border-strong: #c4c7c5;
  --text: #1f1f1f;
  --text-dim: #444746;
  --text-faint: #80868b;

  --accent: #000000;
  --accent-2: #000000;
  --on-accent: #ffffff;

  --user-bubble: #d3e3fd;
  --user-bubble-border: #a8c7fa;
  --ok: #1a7f37;
  --warn: #b06000;
  --err: #d93025;

  --danger: #d93025;
  --danger-text: #b3261e;
  --danger-bg: #fce8e6;
  --danger-border: #f3b4ad;

  --banner-info-bg: #e8f0fe;
  --banner-info-fg: #1967d2;
  --banner-info-bd: #aecbfa;
  --banner-warn-bg: #fef7e0;
  --banner-warn-fg: #b06000;
  --banner-warn-bd: #fde293;
  --banner-error-bg: #fce8e6;
  --banner-error-fg: #c5221f;
  --banner-error-bd: #f3b4ad;

  --shadow-sm: 0 1px 2px rgba(60, 64, 67, 0.16);
  --shadow-md: 0 4px 18px rgba(60, 64, 67, 0.18);
  --shadow-lg: 0 12px 42px rgba(60, 64, 67, 0.24);
}

* { box-sizing: border-box; }

/* Themed text selection (must follow :root so the tokens resolve). ::selection
   and ::-moz-selection are kept as separate rules — an unknown pseudo in a
   shared selector list drops the whole rule in some engines. */
::selection { background: var(--selection-bg); color: var(--selection-fg); }
::-moz-selection { background: var(--selection-bg); color: var(--selection-fg); }

/* Material Symbols Rounded (Gemini-style menu icons). The Google Fonts link ships
   the base .material-symbols-rounded class; here we set the outline weight, size,
   and optical axes so the glyphs read as thin Gemini-style icons. */
.material-symbols-rounded {
  font-size: 20px;
  line-height: 1;
  font-variation-settings: "FILL" 0, "wght" 300, "GRAD" 0, "opsz" 24;
  vertical-align: middle;
  user-select: none;
}
.nav-drawer-icon.material-symbols-rounded { font-size: 22px; }

/* App-wide currency convention: an icon + the number (Power = bolt ⚡, Credits = toll ◉),
   never the spelled-out word. The icon inherits the surrounding color so it reads on any
   surface; it sits slightly larger than the digits and optically aligned. */
.cur { display: inline-flex; align-items: center; gap: 3px; font-variant-numeric: tabular-nums; white-space: nowrap; }
.cur .cur-icon { font-size: 1.1em; line-height: 1; }
.cur .cur-val { line-height: 1; }
/* Match the sizes of the bespoke number styles these chips replaced. */
.store-bal-cur .cur { font-size: 17px; font-weight: 700; color: var(--text); }
.store-card-amount .cur { font-size: 26px; font-weight: 700; color: var(--text); }
.store-card-cost .cur { font-size: 15px; font-weight: 700; }
.agentset-stat-cur .cur { font-family: var(--font-display); font-size: 30px; font-weight: 700; color: var(--text); }

html, body {
  margin: 0;
  height: 100%;
}

body {
  background: var(--bg);
  color: var(--text);
  /* Gemini's reading scale: 16px body / 1.5 line-height. */
  font: 16px/1.5 var(--font-ui);
  display: flex;
  flex-direction: column;
  height: 100dvh;
  overflow: hidden;
  -webkit-font-smoothing: antialiased;
  transition: background 0.3s var(--ease), color 0.3s var(--ease);
}

/* ---------------- system notification (Gemini dropdown) ----------------
   A compact, rounded alert that slides down from the top — NOT a full-width
   bar. Centered, capped width, with a kind icon + a dismiss button. */
.banner {
  position: fixed; top: 12px; left: 50%; z-index: 50;
  display: none; align-items: flex-start; gap: 10px;
  width: max-content; max-width: min(460px, calc(100vw - 28px));
  padding: 11px 10px 11px 14px;
  font-size: 13.5px; font-weight: 500; line-height: 1.42; text-align: left;
  border-radius: var(--radius); border: 1px solid transparent;
  box-shadow: var(--shadow-md);
  transform: translate(-50%, -12px); opacity: 0;
  transition: opacity 200ms var(--ease), transform 200ms var(--ease);
}
.banner.show { display: flex; }
.banner.is-in { transform: translate(-50%, 0); opacity: 1; }
.banner-icon { flex: none; font-size: 20px; margin-top: -1px; opacity: 0.95; }
.banner-msg { flex: 1 1 auto; min-width: 0; padding-top: 1px; }
.banner-close {
  flex: none; display: inline-flex; align-items: center; justify-content: center;
  width: 24px; height: 24px; margin: -2px 0 0 2px; padding: 0;
  background: none; border: none; cursor: pointer; border-radius: 999px;
  color: inherit; opacity: 0.6; font-size: 18px; transition: opacity 0.15s var(--ease), background 0.15s var(--ease);
}
.banner-close:hover { opacity: 1; background: color-mix(in srgb, currentColor 16%, transparent); }
.banner-info { background: var(--banner-info-bg); color: var(--banner-info-fg); border-color: var(--banner-info-bd); }
.banner-warn { background: var(--banner-warn-bg); color: var(--banner-warn-fg); border-color: var(--banner-warn-bd); }
.banner-error { background: var(--banner-error-bg); color: var(--banner-error-fg); border-color: var(--banner-error-bd); }
@media (prefers-reduced-motion: reduce) { .banner { transition: opacity 120ms linear; transform: translate(-50%, 0); } }

/* ---------------- floating menu button (no top bar) ---------------- */

/* The hamburger floats over the content, top-left (Gemini sidebar pattern).
   Sits below the session overlay (z 80) so a full-screen mobile session covers
   it; on the home view and desktop split-view it's visible over empty space. */
.nav-fab {
  position: fixed;
  top: 12px;
  left: 12px;
  z-index: 40;
  width: 48px;
  height: 48px;
  display: grid;
  place-items: center;
  background: transparent;
  color: var(--text-dim);
  border: none;
  border-radius: 50%;
  font-size: 24px;
  line-height: 1;
  cursor: pointer;
  transition: background 0.15s var(--ease), color 0.15s var(--ease);
}
.nav-fab:hover { background: var(--bg-elev-2); color: var(--text); }
.nav-fab .material-symbols-rounded { font-size: 24px; }

/* Home loop strip — explicit "you can act now" rows under the earnings widget: a free-pull CTA
   with the exact count, and a card-progress bar that flips to a bold Ready-to-upgrade CTA. */
/* Home hub — a fixed top-right corner cluster on the tasks screen (mirrors the top-left
   hamburger): the star-up progress/CTA + a free-gacha count. Sits in the viewport corner,
   never in the composer's flow. Collapses when there's nothing to act on. */
.home-hub-slot:empty { display: none; }
.home-hub {
  position: fixed;
  top: 12px;
  right: 12px;
  z-index: 40;
  /* Match the hamburger's 48px box at the same top so the pills' centers line up with it
     (they're only 40px tall) — stays aligned across breakpoints since both share `top`. */
  height: 48px;
  display: flex;
  align-items: center;
  gap: 8px;
}
/* Hidden while a task is open (home chrome collapses to the task list) — matches the
   earn/mascot slots. Every other screen hides it via the .tasks-view display cascade. */
.layout.session-active .home-hub { display: none; }

.hub-pill {
  display: inline-flex; align-items: center; gap: 7px;
  height: 40px; padding: 0 13px 0 11px;
  border: 1px solid var(--border); border-radius: 999px;
  background: color-mix(in srgb, var(--bg-elev-1) 86%, transparent);
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
  color: var(--text); cursor: pointer; font: inherit;
  transition: transform 0.12s var(--ease), filter 0.12s var(--ease), background 0.12s var(--ease);
}
.hub-pill:hover { background: var(--bg-elev-2); }
.hub-pill:active { transform: translateY(1px); }
.hub-pill .material-symbols-rounded { font-size: 22px; }
.hub-count { font-size: 13px; font-weight: 800; font-variant-numeric: tabular-nums; letter-spacing: 0.2px; }

/* Free-gacha gift pill — brand gradient so it reads as a reward waiting to be opened. */
.hub-gift {
  border-color: transparent; color: #fff;
  background: linear-gradient(135deg, #0036ff, #c600ff);
  box-shadow: 0 8px 20px -12px rgba(120, 40, 255, 0.9);
  animation: hub-gift-pulse 2.4s var(--ease) infinite;
}
.hub-gift:hover { filter: brightness(1.06); background: linear-gradient(135deg, #0036ff, #c600ff); }
@keyframes hub-gift-pulse {
  0%, 100% { box-shadow: 0 8px 20px -12px rgba(120, 40, 255, 0.9); }
  50%      { box-shadow: 0 8px 26px -10px rgba(160, 60, 255, 1); }
}

/* Star-up in-progress — a compact progress bar toward the next star + the exact fraction, so
   "2/5 towards ★N" reads at a glance. */
.hub-up:not(.is-ready) .hub-up-star { color: #a78bfa; }
.hub-bar {
  flex: none; width: 46px; height: 6px; border-radius: 999px; overflow: hidden;
  background: color-mix(in srgb, var(--text) 15%, transparent);
}
.hub-bar-fill {
  display: block; height: 100%; border-radius: 999px;
  background: linear-gradient(90deg, #0036ff, #c600ff); transition: width 0.5s var(--ease);
}

/* Star-up ready — a glowing brand pill that periodically WIGGLES to invite the upgrade tap
   (it's a live CTA: tapping stars the agent up). Rest for most of the cycle, then a quick
   left-right shake with a tiny pop — attention without a constant distraction. */
.hub-up.is-ready {
  border-color: transparent; color: #fff;
  background: linear-gradient(135deg, #6d28d9, #c600ff);
  box-shadow: 0 10px 26px -10px rgba(170, 70, 255, 1);
  transform-origin: center;
  animation: hub-up-wiggle 2.4s var(--ease) infinite;
}
.hub-up.is-ready:hover { filter: brightness(1.07); background: linear-gradient(135deg, #6d28d9, #c600ff); }
.hub-up.is-ready .material-symbols-rounded { color: #fff; }
.hub-up-star { font-size: 13px; font-weight: 800; letter-spacing: 0.2px; }
@keyframes hub-up-wiggle {
  0%, 58%, 100% { transform: rotate(0) scale(1); }
  64% { transform: rotate(-9deg) scale(1.06); }
  70% { transform: rotate(7deg)  scale(1.06); }
  76% { transform: rotate(-6deg) scale(1.04); }
  82% { transform: rotate(4deg)  scale(1.03); }
  88% { transform: rotate(-2deg) scale(1.02); }
  94% { transform: rotate(1deg)  scale(1.01); }
}
@media (prefers-reduced-motion: reduce) {
  .hub-gift, .hub-up.is-ready { animation: none; }
  .hub-bar-fill { transition: none; }
}

/* Mobile: align the hub's top edge with the hamburger (both drop under the safe-area inset). */
@media (max-width: 720px) { .home-hub { top: calc(env(safe-area-inset-top) + 4px); } }

/* Agent chooser dropdown — now the head of the nav drawer (full width). */
.agent-switch { position: relative; }
.agent-switch-btn {
  display: flex;
  align-items: center;
  gap: 9px;
  width: 100%;
  background: transparent;
  color: var(--text);
  border: none;
  border-radius: 999px;
  padding: 10px 14px;
  font-size: 15px;
  font-weight: 600;
  cursor: pointer;
  transition: background 0.15s var(--ease);
}
.agent-switch-btn:hover { background: var(--bg-elev-2); }
/* Push the caret to the far right so the pill reads as a full-width selector. */
.agent-switch-btn .agent-switch-caret { margin-left: auto; }
.agent-switch-btn .agent-switch-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.agent-switch-btn .agent-switch-mark {
  font-size: 18px;
  font-variation-settings: "FILL" 1, "wght" 500, "GRAD" 0, "opsz" 24;
  background: var(--grad);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
.agent-switch-btn .agent-switch-caret { color: var(--text-faint); font-size: 20px; }

/* Shared dropdown menu surface (hamburger menu + agent list). */
.nav-menu {
  position: absolute;
  top: calc(100% + 8px);
  min-width: 220px;
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-md);
  padding: 6px;
  z-index: 50;
  display: flex;
  flex-direction: column;
  gap: 1px;
}
/* Agent menu drops down under the full-width switcher at the drawer head. A long agent list
   must scroll INSIDE the menu instead of running off the bottom of the viewport — cap to the
   viewport height and scroll; keep the "Your agents" head pinned so it stays visible. */
.nav-menu.from-agent {
  left: 0; right: 0;
  max-height: calc(100vh - 84px);
  max-height: calc(100dvh - 84px);
  overflow-y: auto;
  overscroll-behavior: contain;
}
.nav-menu.from-agent .nav-menu-head {
  position: sticky;
  top: 0;
  z-index: 1;
  background: var(--bg-elev);
}
.nav-menu.from-right { right: 0; }
/* Account menu sits at the drawer foot, so it opens upward. */
.nav-menu.from-user { left: 0; right: 0; bottom: calc(100% + 8px); top: auto; }

/* Agent card in the chooser dropdown: name + power/credits/expiry, with a settings
   button. Tall enough to host the stats comfortably. Main area switches agents. */
.agent-card { display: flex; align-items: stretch; gap: 2px; }
.agent-card-main {
  flex: 1 1 auto;
  display: flex;
  align-items: center;
  gap: 11px;
  min-width: 0;
  text-align: left;
  background: transparent;
  border: none;
  cursor: pointer;
  border-radius: var(--radius-sm);
  padding: 11px 8px 11px 12px;
  color: var(--text);
  transition: background 0.15s var(--ease);
}
.agent-card-main:hover { background: var(--bg-elev-2); }
.agent-card.is-current .agent-card-main { background: color-mix(in srgb, var(--accent) 12%, transparent); }
.agent-card-radio { flex: none; font-size: 18px; color: var(--text-dim); }
.agent-card.is-current .agent-card-radio { color: var(--accent); }
.agent-card-info { min-width: 0; flex: 1 1 auto; display: flex; flex-direction: column; gap: 6px; }
.agent-card-name-row { display: flex; align-items: center; gap: 6px; min-width: 0; }
.agent-card-name {
  /* No flex-grow: the star badge should hug the name, not float to the far edge. */
  flex: 0 1 auto; min-width: 0;
  font-size: 14px; font-weight: 600; color: var(--text);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* Admin-suspended mark — same "bad" red used for a suspended USER elsewhere in admin. */
.agent-card-suspended {
  flex: none; font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.03em;
  padding: 2px 7px; border-radius: 999px;
  color: var(--err); background: color-mix(in srgb, var(--err) 16%, transparent);
}
/* Stats stack on two lines (credits, then days left) — a single row truncates or
   wraps unpredictably as numbers and translations grow. */
.agent-card-stats { display: flex; flex-direction: column; align-items: flex-start; gap: 3px; min-width: 0; }
.agent-card-stat {
  display: inline-flex; align-items: center; gap: 4px;
  font-size: 12px; color: var(--text-dim); font-variant-numeric: tabular-nums;
}
.agent-card-stat .material-symbols-rounded { font-size: 15px; color: var(--accent); }
.agent-card-divider { color: var(--text-faint); font-size: 12px; opacity: 0.6; }
.agent-card-sub { font-size: 12px; color: var(--text-faint); white-space: nowrap; }
.agent-card-sub.is-warn { color: var(--warn); }
.agent-card-sub.is-danger { color: var(--danger-text); }
.agent-card-gear {
  flex: none; width: 40px; height: 40px; align-self: center;
  display: grid; place-items: center;
  background: transparent; border: none; cursor: pointer;
  color: var(--text-dim); border-radius: 999px;
  transition: background 0.15s var(--ease), color 0.15s var(--ease);
}
.agent-card-gear:hover { background: var(--bg-elev-2); color: var(--text); }
.agent-card-gear .material-symbols-rounded { font-size: 19px; }

/* Star tier pill — a tier-colored "★ N" badge shared across every agent surface
   (picker, dropdown, settings, Earn card) so a high-star agent reads as different at
   a glance. Tint escalates with tier; the buy-agent card uses its own frosted badge.
   See src/web/star.ts. */
.star-pill {
  flex: none; display: inline-flex; align-items: center; gap: 3px;
  padding: 3px 9px; border-radius: 999px;
  font-size: 11.5px; font-weight: 700; line-height: 1;
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
.star-pill-ic { font-size: 13px; font-variation-settings: "FILL" 1, "wght" 500, "GRAD" 0, "opsz" 20; }
.star-pill--md { font-size: 13px; padding: 4px 11px; }
.star-pill--md .star-pill-ic { font-size: 15px; }
.star-pill--low { color: var(--text-dim); background: var(--bg-elev-3); }
.star-pill--mid { color: var(--warn); background: color-mix(in srgb, var(--warn) 18%, transparent); }
.star-pill--high { color: #fff; background: linear-gradient(135deg, var(--grad-a), var(--grad-b) 55%, var(--grad-c)); }

.user-avatar {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  font-size: 14px;
  font-weight: 600;
  color: var(--on-accent);
  background: var(--grad);
}

/* Account profile row at the bottom of the drawer. */
.nav-drawer-foot {
  margin-top: auto;
  position: relative;
  display: flex;
  align-items: center;
  gap: 4px;
  padding-top: 8px;
}
.nav-foot-gear { flex: 0 0 auto; }
.user-profile-btn {
  display: flex;
  align-items: center;
  gap: 11px;
  flex: 1 1 auto;
  min-width: 0;
  background: transparent;
  border: none;
  border-radius: 999px;
  padding: 8px 10px;
  cursor: pointer;
  color: var(--text);
  text-align: left;
  transition: background 0.15s var(--ease);
}
.user-profile-btn:hover { background: var(--bg-elev-2); }
.user-profile-meta { display: flex; flex-direction: column; min-width: 0; }
.user-profile-name { font-size: 14px; font-weight: 600; }
.user-profile-email {
  font-size: 12px;
  color: var(--text-faint);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 100%;
}
.user-profile-email:empty { display: none; }

.nav-menu[hidden] { display: none; }
.nav-menu-head {
  padding: 8px 10px 6px;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: var(--text-faint);
}
.nav-menu-item {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  text-align: left;
  background: transparent;
  border: none;
  color: var(--text);
  font-size: 13.5px;
  padding: 9px 10px;
  border-radius: var(--radius-sm);
  cursor: pointer;
}
.nav-menu-item:hover { background: var(--bg-elev-2); }
.nav-menu-item .nav-menu-icon { width: 20px; text-align: center; color: var(--text-dim); }
.nav-menu-item.is-current { color: var(--accent); }
.nav-menu-item .nav-menu-sub { margin-left: auto; font-size: 11px; color: var(--text-faint); }
.nav-menu-sep { height: 1px; background: var(--border); margin: 10px 2px; }

/* Hamburger menu — left slide-in drawer overlaying the chat. */
.nav-drawer-overlay {
  position: fixed;
  inset: 0;
  z-index: 100;
  background: rgba(0, 0, 0, 0);
  transition: background 0.25s ease;
}
.nav-drawer-overlay.open { background: rgba(0, 0, 0, 0.45); }
.nav-drawer-overlay[hidden] { display: none; }
.nav-drawer {
  position: absolute;
  top: 0;
  left: 0;
  bottom: 0;
  width: 300px;
  max-width: 82vw;
  background: var(--bg-elev);
  border: none;
  box-shadow: var(--shadow-lg);
  /* Rounded right edge so the panel reads as a floating sheet, not a full-bleed
     slab (its left edge is off-screen, so only the right corners show). Generous
     radius to match the reference. */
  border-radius: 0 var(--radius-hero) var(--radius-hero) 0;
  padding: 14px 12px;
  display: flex;
  flex-direction: column;
  gap: 6px;
  transform: translateX(-100%);
  transition: transform 0.25s var(--ease);
}
.nav-drawer-overlay.open .nav-drawer { transform: translateX(0); }
/* Head holds the agent switcher; leave room for the floating hamburger above. */
.nav-drawer-head {
  padding: 2px 0 10px;
  margin-bottom: 6px;
}
.nav-drawer-item {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  text-align: left;
  background: transparent;
  border: none;
  color: var(--text);
  font-size: 15px;
  padding: 14px 12px;
  border-radius: 999px;
  cursor: pointer;
  transition: background 0.15s var(--ease);
}
.nav-drawer-item:hover { background: var(--bg-elev-2); }
/* Current screen: the same rounded pill, kept lit so the drawer always shows
   where you are. */
.nav-drawer-item.is-current { background: var(--bg-elev-2); }
.nav-drawer-item.is-current .nav-drawer-icon { color: var(--text); }
.nav-drawer-icon { width: 22px; text-align: center; color: var(--text-dim); }

/* ---------------- Tasks home (Gemini-style) + session slide-in ---------------- */
/* A centered column positioned in the upper-middle: gradient greeting, pill
   composer, then the Recent task list. The whole view scrolls if long. */
.tasks-view {
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 100%;
  flex: 1 1 auto;
  min-height: 0;
  background: transparent;
  /* The view itself doesn't scroll — the greeting/composer/recent header is
     pinned and only the task list scrolls (Gemini's home layout). */
  overflow: hidden;
}
.home-center {
  width: 100%;
  max-width: 760px;
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  padding: 0 24px;
}
/* Hero band: occupies the top ~half of the desktop home. The greeting sits in the
   top-middle as the focal point (padding-top) with the composer cluster below it;
   the Recent row and task list follow as siblings underneath. */
.home-header {
  flex: 0 0 auto;
  min-height: 50vh;
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  /* Tight — the mascot is the focal point and sits close to the top. */
  padding-top: 5vh;
  position: relative;
  z-index: 2;
}
.home-greeting,
.home-composer-wrap,
.recent-bar { flex: 0 0 auto; }

/* The greeting as a speech bubble the mascot appears to be saying — a small
   centered tonal pill sitting just under the mascot, with a triangular tail
   (::after) poking up to touch it. Replaces the old full-width gradient
   hero heading now that the mascot itself (not the text) is the focal point. */
.home-greeting {
  position: relative;
  width: fit-content;
  max-width: min(88%, 380px);
  margin: 0 auto 40px;
  text-align: center;
  font-family: var(--font-display);
  font-size: 17px;
  line-height: 1.4;
  font-weight: 600;
  letter-spacing: -0.1px;
  color: var(--text);
  background: var(--bg-elev-1);
  padding: 13px 20px;
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
}
.home-greeting::after {
  content: "";
  position: absolute;
  left: 50%;
  top: -6px;
  width: 12px;
  height: 12px;
  background: var(--bg-elev-1);
  transform: translateX(-50%) rotate(45deg);
}

/* "New task" button — only shown in the split view, where it replaces the hero
   composer (the full composer lives on the full-screen home instead). */
.home-new-task {
  display: none;
  align-items: center;
  justify-content: center;
  gap: 10px;
  width: fit-content;
  margin: 4px auto 18px;
  background: var(--bg-elev-2);
  color: var(--text);
  border: none;
  border-radius: 999px;
  padding: 15px 32px 15px 26px;
  font: inherit;
  font-size: 16px;
  font-weight: 600;
  cursor: pointer;
  transition: background 0.15s var(--ease);
}
.home-new-task:hover { background: var(--bg-elev-3); }
.home-new-task .material-symbols-rounded { font-size: 22px; color: var(--text-dim); }

/* ── Home earnings widget (home-earn.ui.ts) ─────────────────────────────────
   A light card with two parts: a MUST-HAVE primary figure (total earned — always
   there) over a DYNAMIC good-to-know note (agent expiring, funds ready, today's
   gain, daily rate…). The number stays put while the note keeps it current, without
   the overload of a full dashboard. Taps through to the Earn screen. */
/* Mascot hero: a large, purely-decorative live mascot centered above the
   greeting (Gemini's centered-orb pattern) — no card chrome, no text.
   ~1/6 of the viewport height, clamped so it stays sane on very short/tall
   screens. */
/* NEGATIVE gap: the canvas renders the ball at ~48% of its own box (the rest
   is jump-arc headroom), leaving ~26% (≈9.6vh at the current 37vh canvas) of
   empty space below the ball. Pull the greeting up through part of that dead
   space — -5.1vh leaves ≈4.5vh of visual air between ball and bubble (1.5x
   the previous gap, per feedback). The canvas overlap is transparent and
   harmless. */
.home-mascot-slot { flex: 0 0 auto; margin: 0 0 clamp(-90px, -5.1vh, -16px); display: flex; justify-content: center; }
.home-mascot-canvas {
  display: block;
  /* Sized up twice by feedback (1.5x, then 1.5x again) — the mascot IS the
     hero of the tasks screen, and the Recent list is capped at 3 cards to
     make the room. The 2D port frames the ball at ~48% of the canvas
     (jump headroom), so the visible ball is about half these values. */
  width: clamp(158px, 37vh, 470px);
  height: clamp(158px, 37vh, 470px);
  cursor: pointer;
  transition: filter 0.15s var(--ease);
}
.home-mascot-canvas:hover { filter: brightness(1.08); }

/* Narrower than the composer column and outlined rather than filled, so the
   stats widget reads as a distinct info card, not another input. */
.home-earn-slot { flex: 0 0 auto; width: 100%; max-width: 560px; margin: 0 auto 44px; }
.home-earn-slot:empty { display: none; } /* collapse when there's nothing to show (or toggled off) */
.home-earn {
  display: flex; flex-direction: column; width: 100%;
  padding: 14px 17px;
  border-radius: var(--radius-lg);
  background: transparent;
  border: 1px solid var(--border);
  cursor: pointer; text-align: left;
  transition: transform 0.13s var(--ease), background 0.15s var(--ease);
}
.home-earn:hover { background: var(--bg-elev-2); }
.home-earn:active { transform: scale(0.992); }
.home-earn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.home-earn-chev { flex: none; font-size: 22px; color: var(--text-faint); }

/* Primary — the must-have earnings figure (always shown). */
.home-earn-primary { display: flex; align-items: center; gap: 12px; }
.home-earn-primary-main { flex: 1 1 auto; min-width: 0; }
.home-earn-label { font-size: 11.5px; font-weight: 600; letter-spacing: 0.5px; text-transform: uppercase; color: var(--text-faint); }
.home-earn-value {
  font-family: var(--font-display); font-size: 27px; font-weight: 700; line-height: 1.1;
  color: var(--text); font-variant-numeric: tabular-nums;
}
/* The running total with today's gain riding alongside it, baseline-aligned so
   the small "Today +$…" tag sits neatly against the big figure. */
.home-earn-value-row { display: flex; align-items: baseline; gap: 10px; margin-top: 2px; flex-wrap: wrap; }
.home-earn-today {
  flex: 0 0 auto;
  font-size: 13px; font-weight: 650; line-height: 1;
  color: var(--ok); font-variant-numeric: tabular-nums;
  padding: 3px 8px; border-radius: 999px;
  background: color-mix(in srgb, var(--ok) 15%, transparent);
  white-space: nowrap;
}

/* Note — the dynamic good-to-know line under a divider. */
.home-earn-note {
  display: flex; align-items: center; gap: 11px;
  margin-top: 13px; padding-top: 13px;
  border-top: 1px solid color-mix(in srgb, var(--text-faint) 16%, transparent);
}
.home-earn-note-ic {
  display: grid; place-items: center; flex: none;
  width: 34px; height: 34px; border-radius: var(--radius-tile);
  background: color-mix(in srgb, var(--accent) 16%, var(--bg-elev-2)); color: var(--accent);
}
.home-earn-note-ic .material-symbols-rounded { font-size: 19px; }
.home-earn-note-body { flex: 1 1 auto; min-width: 0; }
.home-earn-note-title {
  font-size: 13.5px; font-weight: 600; color: var(--text);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.home-earn-note-sub {
  font-size: 12px; color: var(--text-faint); margin-top: 1px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.home-earn-note-action {
  flex: none; border: none; cursor: pointer; border-radius: 999px;
  padding: 7px 14px; font: inherit; font-size: 12.5px; font-weight: 600;
  transition: filter 0.14s var(--ease), background 0.14s var(--ease);
}
.home-earn-note-action.is-primary { background: var(--grad); color: var(--on-accent); }
.home-earn-note-action.is-primary:hover { filter: brightness(1.08); }
.home-earn-note-action.is-warn { background: color-mix(in srgb, var(--warn) 22%, var(--bg-elev-2)); color: var(--warn); }
.home-earn-note-action.is-warn:hover { background: color-mix(in srgb, var(--warn) 32%, var(--bg-elev-2)); }

/* Note tones — the icon chip color. */
.home-earn-note.is-warn .home-earn-note-ic { background: color-mix(in srgb, var(--warn) 18%, var(--bg-elev-2)); color: var(--warn); }
.home-earn-note.is-positive .home-earn-note-ic { background: color-mix(in srgb, var(--ok) 18%, var(--bg-elev-2)); color: var(--ok); }
.home-earn-note.is-info .home-earn-note-ic { background: color-mix(in srgb, var(--accent) 16%, var(--bg-elev-2)); color: var(--accent); }
.home-earn-note.is-neutral .home-earn-note-ic { background: var(--bg-elev-2); color: var(--text-dim); }

/* New-user brand card — a single inviting row, no primary figure. */
.home-earn--brand { flex-direction: row; align-items: center; gap: 13px; }
.home-earn--brand .home-earn-note-ic { width: 40px; height: 40px; background: color-mix(in srgb, var(--grad-b) 22%, var(--bg-elev-2)); color: var(--text); }
.home-earn--brand .home-earn-note-ic .material-symbols-rounded { font-size: 22px; }
.home-earn--brand .home-earn-note-title { font-size: 15px; }

/* Skeleton: a value bar over a note row, reserving the card height on a cold load. */
.home-earn--skeleton { cursor: default; pointer-events: none; }
.home-earn-skel { background: var(--bg-elev-2); border-radius: 8px; animation: home-earn-pulse 1.3s ease-in-out infinite; }
.home-earn-skel-value { width: 42%; height: 26px; }
.home-earn-skel-note {
  display: flex; align-items: center; gap: 11px;
  margin-top: 13px; padding-top: 13px;
  border-top: 1px solid color-mix(in srgb, var(--text-faint) 16%, transparent);
}
.home-earn-skel-ic { width: 34px; height: 34px; border-radius: var(--radius-tile); flex: none; }
.home-earn-skel-line { height: 13px; flex: 1 1 auto; max-width: 58%; }
@keyframes home-earn-pulse { 0%, 100% { opacity: 0.5; } 50% { opacity: 0.9; } }
@media (prefers-reduced-motion: reduce) { .home-earn-skel { animation: none; } }

/* ── Home self-improvement notice (home-improve.ui.ts) ──────────────────────
   Part of the stats widget: renders as a divider row INSIDE the earnings card
   (only when the daemon has unseen passes — the slot collapses otherwise).
   Brand-new-user fallback: as a sibling below the "Start earning" row card,
   where the default standalone-card look below applies. */
.home-earn-improve-slot:empty { display: none; }
.home-earn-slot > .home-earn-improve-slot { margin-top: 10px; }
.home-earn .home-earn-improve-slot { margin-top: 0; }
.home-earn .home-improve {
  background: transparent; border-radius: 0; padding: 13px 0 0; margin-top: 13px;
  border-top: 1px solid color-mix(in srgb, var(--text-faint) 16%, transparent);
}
.home-earn .home-improve:hover { background: transparent; }
.home-earn .home-improve:active { transform: none; }
.home-earn .home-improve-ic { width: 34px; height: 34px; }
.home-earn .home-improve-ic .material-symbols-rounded { font-size: 19px; }
.home-improve {
  display: flex; align-items: center; gap: 13px; width: 100%;
  padding: 15px 17px;
  border-radius: var(--radius-lg);
  background: var(--bg-elev-1);
  cursor: pointer; text-align: left;
  transition: transform 0.13s var(--ease), background 0.15s var(--ease);
}
.home-improve:hover { background: var(--bg-elev-2); }
.home-improve:active { transform: scale(0.992); }
.home-improve:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.home-improve-ic {
  display: grid; place-items: center; flex: none;
  width: 40px; height: 40px; border-radius: var(--radius-tile);
  background: color-mix(in srgb, var(--grad-b) 22%, var(--bg-elev-2)); color: var(--text);
}
.home-improve-ic .material-symbols-rounded { font-size: 22px; }
/* Needs-review tint when there are staged (ask-first) changes. */
.home-improve.is-review .home-improve-ic { background: color-mix(in srgb, var(--warn) 18%, var(--bg-elev-2)); color: var(--warn); }
.home-improve-body { flex: 1 1 auto; min-width: 0; }
.home-improve-title {
  font-size: 14px; font-weight: 650; color: var(--text);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.home-improve-sub {
  font-size: 12px; color: var(--text-faint); margin-top: 1px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.home-improve-action {
  flex: none; border: none; cursor: pointer; border-radius: 999px;
  font-size: 12px; font-weight: 600; padding: 6px 13px;
  background: color-mix(in srgb, var(--warn) 22%, var(--bg-elev-2)); color: var(--warn);
}
.home-improve-action:hover { background: color-mix(in srgb, var(--warn) 32%, var(--bg-elev-2)); }
.home-improve-chev { flex: none; font-size: 22px; color: var(--text-faint); }

/* Pill composer — in-flow between the stats widget and the Recent list (per
   feedback; it used to be pinned to the viewport bottom). position:relative
   is load-bearing: the slash palette anchors to this wrap and opens upward. */
.home-composer-wrap {
  position: relative;
  width: 100%;
  z-index: 30;
  margin: 0 0 26px;
}
.home-composer {
  display: flex;
  align-items: center;
  gap: 12px;
  background: var(--bg-elev-1);
  border: none;
  border-radius: var(--radius-hero);
  /* Spacious, Gemini-style: the input floats in generous padding rather than
     hugging a slim pill. */
  padding: 19px 24px;
  box-shadow: var(--shadow-md);
  transition: box-shadow 0.15s var(--ease);
}
.home-composer:focus-within { box-shadow: var(--shadow-md); }
.home-composer-plus {
  flex: 0 0 auto;
  font-size: 22px;
  line-height: 1;
  color: var(--text-dim);
}
.home-input {
  flex: 1 1 auto;
  resize: none;
  max-height: 200px;
  background: transparent;
  color: var(--text);
  border: none;
  outline: none;
  padding: 4px 0;
  font: inherit;
  font-size: 16px;
  line-height: 1.5;
}
.home-input::placeholder { color: var(--text-faint); }
/* The home palette opens UPWARD — the composer is pinned to the viewport
   bottom now, so a downward drop would run off-screen. Higher-specificity
   selector so it beats the base `.cmd-palette` bottom/left/right (defined
   later in this file). */
.home-composer-wrap .home-palette {
  top: auto;
  bottom: calc(100% + 8px);
  left: 0;
  right: 0;
}

/* Assist chips — a horizontally-scrollable row of starter prompts above the
   composer that seed a first task (Gemini's mobile pattern). Tapping one fills
   the composer; the row hides once the input has text. */
.home-chips {
  display: flex;
  gap: 8px;
  overflow-x: auto;
  scrollbar-width: none;
  -ms-overflow-style: none;
  -webkit-overflow-scrolling: touch;
  margin: 0 0 10px;
  padding: 2px;
  scroll-snap-type: x proximity;
}
.home-chips::-webkit-scrollbar { display: none; }
.home-chips:empty,
.home-chips.is-hidden { display: none; }
.home-chip {
  flex: 0 0 auto;
  scroll-snap-align: start;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  min-height: 40px;
  padding: 9px 15px;
  border: none;
  border-radius: 999px;
  background: var(--bg-elev-1);
  color: var(--text);
  font: inherit;
  font-size: 13.5px;
  font-weight: 550;
  white-space: nowrap;
  cursor: pointer;
  box-shadow: var(--shadow-sm);
  transition: background 0.14s var(--ease), transform 0.1s var(--ease);
}
.home-chip:hover { background: var(--bg-elev-2); }
.home-chip:active { transform: scale(0.97); }
.home-chip:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.home-chip .material-symbols-rounded { font-size: 18px; color: var(--text-dim); }

/* Recent header: sort dropdown on the left, keyword search on the right. Now a
   sibling of the task list (sits just below the ~50vh hero band on desktop; pins
   beneath the nav on mobile — see the phone media block). */
.recent-bar {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 0 4px 6px;
}
.recent-sort {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  background: none;
  border: none;
  padding: 4px 6px 4px 0;
  font-size: 13.5px;
  font-weight: 600;
  color: var(--text-dim);
  cursor: pointer;
  border-radius: var(--radius-sm);
}
.recent-sort:hover { color: var(--text); }
.recent-caret { font-size: 20px; color: var(--text-faint); }
/* Collapses to a single search icon; clicking it expands the pill (see main.ts). */
.recent-search-wrap {
  display: flex;
  align-items: center;
  gap: 6px;
  flex: 0 0 auto;
  width: 260px;
  max-width: 55%;
  /* Constant height in both states so expanding/collapsing the search never
     changes the header height (which would make the composer jump). */
  height: 40px;
  margin-left: auto;
  padding: 0 14px;
  overflow: hidden;
  background: var(--bg-elev-1);
  border: none;
  border-radius: 999px;
  transition: width 0.22s var(--ease), padding 0.22s var(--ease),
    background 0.15s var(--ease);
}
/* No stroke — matches the rest of the borderless UI; just a tonal fill on focus. */
.recent-search-wrap:focus-within { background: var(--bg-elev-2); }
.recent-search-ic {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  background: transparent;
  border: none;
  padding: 0;
  color: var(--text-faint);
  cursor: pointer;
}
.recent-search-ic .material-symbols-rounded { font-size: 19px; }
.recent-search {
  flex: 1 1 auto;
  min-width: 0;
  background: transparent;
  border: none;
  outline: none;
  color: var(--text);
  font: inherit;
  font-size: 13.5px;
}
.recent-search::placeholder { color: var(--text-faint); }

/* Collapsed: just a round icon button; the input is clipped to zero width. */
.recent-search-wrap.is-collapsed {
  width: 40px;
  padding: 0;
  gap: 0;
  background: transparent;
  border-color: transparent;
}
.recent-search-wrap.is-collapsed .recent-search-ic {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  color: var(--text-dim);
  transition: background 0.15s var(--ease), color 0.15s var(--ease);
}
.recent-search-wrap.is-collapsed .recent-search-ic .material-symbols-rounded { font-size: 22px; }
.recent-search-wrap.is-collapsed .recent-search-ic:hover { background: var(--bg-elev-2); color: var(--text); }
.recent-search-wrap.is-collapsed .recent-search {
  width: 0;
  flex: 0 0 0;
  opacity: 0;
  pointer-events: none;
}
/* Relative time tag on a task row (revealed with the kebab on hover/focus). */
.task-time {
  flex: 0 0 auto;
  font-size: 12px;
  color: var(--text-faint);
  white-space: nowrap;
  opacity: 0;
  transition: opacity 0.12s ease;
}
.task-row:focus-within .task-time { opacity: 1; }
@media (hover: hover) {
  .task-row:hover .task-time { opacity: 1; }
}
.tasks-list {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  /* The composer sits in-flow above the list now — just a small tail gap. */
  padding-bottom: 28px;
  gap: 12px;
}
.tasks-empty {
  color: var(--text-faint);
  padding: 20px 4px;
  font-size: 13.5px;
}
/* Inline "Retry" link in the task-fetch error state (see renderTasksError). */
.tasks-retry {
  background: none;
  border: none;
  padding: 0;
  font: inherit;
  color: var(--text);
  cursor: pointer;
  text-decoration: underline;
}
.tasks-retry:hover { opacity: 0.7; }
/* Loading indicator shown while the task list is first fetched. */
.tasks-loading {
  display: flex;
  align-items: center;
  gap: 9px;
  color: var(--text-faint);
  padding: 18px 4px;
  font-size: 13.5px;
}
.spinner {
  width: 15px;
  height: 15px;
  flex: 0 0 auto;
  border: 2px solid var(--border);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: spin 0.7s linear infinite;
}
@keyframes spin {
  to {
    transform: rotate(360deg);
  }
}
/* Skeleton placeholders for the Recent task list while it loads. The list lives in
   the agent's sandbox, so a cold fetch can take many seconds; shimmer rows shaped
   like real task rows read as "loading" instead of a blank screen. */
.tasks-skeleton { display: flex; flex-direction: column; }
.task-skel-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 20px 14px 20px 18px;
}
.task-skel-main {
  display: flex;
  flex-direction: column;
  gap: 9px;
  flex: 1 1 auto;
  min-width: 0;
}
.skel {
  background: var(--bg-elev-2);
  border-radius: 7px;
  animation: skel-pulse 1.3s ease-in-out infinite;
  animation-delay: var(--skel-d, 0s);
}
.skel-dot { width: 22px; height: 22px; flex: 0 0 auto; border-radius: 50%; }
.skel-line { height: 11px; border-radius: 6px; }
.skel-line--title { max-width: 100%; }
.skel-line--sub { width: 32%; height: 9px; }
@keyframes skel-pulse {
  0%, 100% { opacity: 0.4; }
  50% { opacity: 0.85; }
}
@media (prefers-reduced-motion: reduce) {
  .skel { animation: none; opacity: 0.5; }
}
/* Taller, calmer task cards with a relaxed rhythm (Gemini). Background stays
   transparent — elevation comes from hover only, not a resting fill. */
.task-row {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 12px;
  text-align: left;
  background: transparent;
  border: none;
  border-radius: var(--radius-hero);
  padding: 20px 14px 20px 18px;
  cursor: pointer;
  width: 100%;
  transition: background 0.12s var(--ease);
}
@media (hover: hover) {
  .task-row:hover { background: var(--bg-elev-1); }
}
.task-row-main {
  display: flex;
  flex-direction: column;
  gap: 6px;
  min-width: 0;
  flex: 1 1 auto;
}
@media (hover: hover) {
  .task-row:hover .task-title { color: var(--accent); }
}
/* Kebab on a task row: hidden until the row is hovered/focused or its menu is open. */
.task-kebab {
  flex: 0 0 auto;
  opacity: 0;
  width: 30px;
  height: 30px;
  font-size: 18px;
  line-height: 1;
  border-radius: 50%;
  transition: opacity 0.12s ease, background 0.12s ease;
}
.task-row:focus-within .task-kebab,
.task-kebab[aria-expanded="true"] { opacity: 1; }
@media (hover: hover) {
  .task-row:hover .task-kebab { opacity: 1; }
}
/* Touch devices have no hover to reveal these, and a sticky :hover would force a
   double-tap (first tap highlights the row, second opens it). Show the time + kebab
   always so a single tap opens the task. */
@media (hover: none) {
  .task-time { opacity: 1; }
  .task-kebab { opacity: 1; }
}
.task-pin-mark { color: var(--text-faint); margin-right: 4px; font-size: 16px; }
.task-title {
  font-size: 15px;
  color: var(--text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 100%;
}
.task-subtitle {
  font-size: 13px;
  color: var(--text-faint);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 100%;
}
/* Live-state chip on a task row (working / needs your reply / interrupted). Only
   rendered while the state is known (agent warm) — idle tasks carry no chip. */
.task-state {
  align-self: flex-start;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 11.5px;
  font-weight: 500;
  border-radius: 999px;
  padding: 2px 10px;
  background: var(--bg-elev-2);
  color: var(--text-dim);
  white-space: nowrap;
}
.task-state::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
}
.task-state-working { color: var(--accent); }
.task-state-working::before { animation: task-state-pulse 1.4s ease-in-out infinite; }
.task-state-needs_input { color: var(--warn, #e0a63d); }
.task-state-stopped { color: var(--text-faint); }
@keyframes task-state-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.3; }
}

.session-overlay {
  position: fixed;
  inset: 0;
  z-index: 80;
  background: rgba(0, 0, 0, 0);
  transition: background 0.25s ease;
}
.session-overlay.open { background: rgba(0, 0, 0, 0.4); }
.session-overlay[hidden] { display: none; }
.session-panel {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  width: 760px;
  max-width: 100%;
  border: none;
  border-left: 1px solid transparent;
  border-radius: 0;
  box-shadow: var(--shadow-lg);
  transform: translateX(100%);
  transition: transform 0.25s var(--ease);
}
.session-overlay.open .session-panel { transform: translateX(0); }
.session-bar {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 16px;
  border-bottom: 1px solid transparent;
  /* Sit above the transcript so its fade mask paints over the scrolling text. */
  position: relative;
  z-index: 2;
  background: var(--bg-elev);
}
/* Gemini-style fade: text scrolling up under the title bar dissolves into the bg. */
.session-bar::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: 100%;
  height: 40px;
  background: linear-gradient(to bottom, var(--bg-elev), transparent);
  pointer-events: none;
}
.session-title {
  font-size: 14px;
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  flex: 1 1 auto;
  min-width: 0;
}
/* Status pill (Gemini "Complete" / "Working") between the title and the kebab. */
.session-status {
  flex: 0 0 auto;
  font-size: 12px;
  font-weight: 500;
  color: var(--text-dim);
  background: var(--bg-elev-2);
  border-radius: 999px;
  padding: 4px 12px;
  white-space: nowrap;
}
.session-status[hidden] { display: none; }
.session-status.working { color: var(--accent); }
.session-menu-btn {
  flex: 0 0 auto;
  font-size: 20px;
  line-height: 1;
}
/* Back chevron: only on mobile/narrow, where the session is a full-screen overlay
   (no task list beside it). On desktop the split-view already shows the list.
   Selector is `.session-bar .session-back` (specificity 0,2,0) so it beats the
   later `.icon-btn { display: grid }` rule the button also matches. */
.session-back { flex: 0 0 auto; }
.session-back svg { display: block; }
.session-bar .session-back { display: none; }
@media (max-width: 899px) {
  .session-bar .session-back { display: inline-flex; align-items: center; justify-content: center; }
}

/* Kebab dropdown menu (task rename / pin / delete / close) ----------------- */
.kebab-menu {
  position: fixed;
  z-index: 200;
  min-width: 184px;
  padding: 6px;
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-md);
}
.kebab-item {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  padding: 9px 12px;
  background: transparent;
  border: none;
  border-radius: var(--radius-sm);
  color: var(--text);
  font-size: 14px;
  text-align: left;
  cursor: pointer;
}
.kebab-item:hover { background: var(--bg-elev-1); }
.kebab-item.danger { color: var(--danger); }
.kebab-ic {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  flex: 0 0 auto;
  color: var(--text-faint);
}
.kebab-ic .material-symbols-rounded { font-size: 18px; }
.kebab-item.danger .kebab-ic { color: var(--danger); }
.kebab-sep {
  height: 1px;
  margin: 6px 4px;
  background: var(--border);
}

/* Desktop split-view: opening a task slides the list into a left column and the
   session becomes the right pane (instead of a full-screen modal overlay). */
@media (min-width: 900px) {
  .tasks-view {
    transition: flex-basis 0.3s var(--ease), max-width 0.3s var(--ease);
  }
  .layout.session-active {
    justify-content: flex-start;
  }
  .layout.session-active .tasks-view {
    flex: 0 0 40%;
    max-width: 560px;
    align-items: stretch;
    border-right: 1px solid transparent;
    /* The column itself doesn't scroll — only the task list inside it does. */
    overflow: hidden;
  }
  /* Split the left column into a fixed header (New task + Recent/search) and a
     scrollable task list below — like Gemini's sidebar. */
  .layout.session-active .home-center {
    max-width: none;
    width: 100%;
    height: 100%;
    min-height: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
  }
  /* No 1/3 band in the narrow split column — the header is just the compact
     New-task button + Recent/search, anchored at the top. */
  .layout.session-active .home-header { min-height: 0; justify-content: flex-start; padding-top: 0; }
  .layout.session-active .home-new-task { display: flex; flex: 0 0 auto; margin: 28px auto 18px; }
  .layout.session-active .recent-bar { flex: 0 0 auto; margin: 0 0 4px; padding: 0 28px; }
  .layout.session-active .tasks-list {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    padding: 6px 28px 24px;
  }
  /* The big hero greeting is a home-screen flourish; hide it in the narrow
     split-view column. The hero composer collapses to the "New task" button. */
  .layout.session-active .home-greeting { display: none; }
  .layout.session-active .home-composer-wrap { display: none; }
  /* The earnings widget is a home-screen flourish too — hide it in the narrow column. */
  .layout.session-active .home-earn-slot { display: none; }
  .layout.session-active .home-mascot-slot { display: none; }
  /* Session becomes an in-flow right pane (not a fixed full-screen modal). */
  .layout.session-active .session-overlay {
    position: relative;
    inset: auto;
    flex: 1 1 0;
    min-width: 0;
    background: transparent;
    z-index: 1;
  }
  .layout.session-active .session-panel {
    position: relative;
    width: 100%;
    height: 100%;
    max-width: none;
    border-left: 1px solid transparent;
    box-shadow: none;
  }
}
.model-indicator {
  font-size: 12.5px;
  color: var(--text-dim);
  padding: 4px 10px;
  border: 1px solid var(--border);
  border-radius: 999px;
  white-space: nowrap;
  max-width: 50vw;
  overflow: hidden;
  text-overflow: ellipsis;
}
.model-indicator.no-model { color: var(--warn); border-color: var(--banner-warn-bd); }

.icon-btn {
  background: transparent;
  color: var(--text-dim);
  border: none;
  border-radius: 50%;
  width: 40px;
  height: 40px;
  font-size: 17px;
  cursor: pointer;
  display: grid;
  place-items: center;
  transition: background 0.15s var(--ease), color 0.15s var(--ease);
}
.icon-btn:hover { background: var(--bg-elev-2); color: var(--text); }

/* ---------------- layout ---------------- */

.layout {
  flex: 1 1 auto;
  display: flex;
  justify-content: center;
  min-height: 0;
  overflow: hidden;
}

.chat-col {
  display: flex;
  flex-direction: column;
  min-height: 0;
  width: 100%;
  max-width: 860px;
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
}

/* ---------------- transcript ---------------- */

.transcript {
  flex: 1 1 auto;
  overflow-y: auto;
  /* Generous bottom padding so the last message clears the composer + its fade
     mask at rest, with breathing room above the gradient cover. */
  padding: 24px 24px 44px;
  display: flex;
  flex-direction: column;
  gap: 24px;
  scroll-behavior: smooth;
}

/* ---- conversational message rows (Gemini layout) ----
   User: a right-aligned tonal bubble, no avatar, no label.
   Assistant: full-width text with just the gradient "spark" to its left. */

.msg {
  display: flex;
  gap: 14px;
  align-items: flex-start;
}

.msg-avatar {
  flex: 0 0 auto;
  width: 42px;
  height: 42px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  font-size: 20px;
  font-weight: 650;
  line-height: 1;
  user-select: none;
}
/* Assistant pfp: a filled circular avatar with the Genie spark. Solid color so it
   ALWAYS paints — the old transparent `background-clip:text` spark could render blank
   if the gradient/clip didn't paint, leaving the reply with no avatar at all. */
.msg-assistant .msg-avatar {
  background: var(--bg-elev-2);
  color: var(--accent);
  font-size: 25px;
  font-variation-settings: "FILL" 1, "wght" 500, "GRAD" 0, "opsz" 24;
}
/* The live mascot avatar (main.ts's shared, reparented canvas) — the one
   assistant row it's currently attached to swaps its icon avatar for this.
   The canvas renders the ball at ~48% of its own box (jump headroom), so at
   100% the pfp read tiny; per feedback it's 1.5x — done by overflowing the
   canvas out of the SAME 42px layout slot (negative margins) so message
   indentation stays identical across rows. The visible ball lands at ~30px,
   still inside the slot; only jump/celebrate arcs spill past it, over
   transparent background. */
.msg-avatar.msg-avatar-mascot { background: transparent; overflow: visible; }
.msg-avatar-mascot .msg-avatar-mascot-canvas { width: 150%; height: 150%; margin: -25%; }
.msg-avatar-mascot-canvas { display: block; width: 100%; height: 100%; }

/* No sender labels — the bubble (user) and spark (assistant) carry the role. */
.msg-sender { display: none; }

/* User turn → right-aligned tonal bubble. */
.msg-user { justify-content: flex-end; }
.msg-user .msg-avatar { display: none; }
.msg-user .msg-content {
  flex: 0 1 auto;
  align-items: flex-end;
  max-width: 82%;
}
.msg-user .msg-body {
  background: var(--user-bubble);
  color: var(--text);
  padding: 11px 17px;
  border-radius: var(--radius-lg);
  width: fit-content;
  max-width: 100%;
}

/* Assistant turn → airy, full-width reading column. */
.msg-assistant .msg-content { line-height: 1.7; }

.msg-content {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
}

.msg-body {
  font-size: 16px;
  white-space: pre-wrap;
  word-wrap: break-word;
  overflow-wrap: anywhere;
  position: relative;
}
.msg-body.busy {
  /* Reserve space so the absolutely-positioned working dot never overlaps the
     last line of streamed text. */
  padding-bottom: 14px;
}
.msg-body.busy::after {
  /* The body holds BLOCK-level children (.bubble-thinking, .bubble-text,
     .bubble-activity), so an inline-block dot would drop onto its own line.
     Anchor it to the body (which is position: relative) so it reads as a
     steady "working" indicator at the bottom-left in every phase — including
     agent_start when .bubble-text is still empty. */
  content: "";
  position: absolute;
  left: 0;
  bottom: 2px;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--accent);
  animation: pulse 1s ease-in-out infinite;
}
@keyframes pulse {
  0%, 100% { opacity: 0.25; transform: scale(0.8); }
  50% { opacity: 1; transform: scale(1.1); }
}

/* "Genie is working" indicator: a pulsing dot + a cycling playful line, shown in
   the gap before the first output so model latency reads as activity, not a hang. */
.working-indicator {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 2px 0;
  color: var(--text-dim);
  font-size: 14px;
  font-style: normal;
}
.working-dot {
  flex: none;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--accent);
  animation: pulse 1s ease-in-out infinite;
}
.working-label { animation: workingFade 2.6s ease-in-out infinite; }
@keyframes workingFade {
  0% { opacity: 0.45; }
  12% { opacity: 0.95; }
  88% { opacity: 0.95; }
  100% { opacity: 0.45; }
}
/* Suppress the bare busy dot while the richer indicator is up (avoid two dots). */
.msg-body.busy:has(.working-indicator)::after { display: none; }

.bubble-text { white-space: pre-wrap; }
.bubble-text:empty { display: none; }

/* ---------------- markdown (assistant body) ---------------- */

/* Rendered markdown owns its own block spacing, so the pre-wrap whitespace used
   for plain streamed text is turned off here. */
.markdown { white-space: normal; }
.markdown:empty { display: none; }

/* Collapse outer margins so a bubble doesn't gain leading/trailing whitespace. */
.markdown > :first-child { margin-top: 0; }
.markdown > :last-child { margin-bottom: 0; }

.markdown p { margin: 0 0 8px; }

.markdown h1,
.markdown h2,
.markdown h3 {
  margin: 14px 0 6px;
  line-height: 1.3;
  font-weight: 650;
}
.markdown h1 { font-size: 19px; }
.markdown h2 { font-size: 17px; }
.markdown h3 { font-size: 15px; color: var(--text-dim); }

.markdown ul,
.markdown ol {
  margin: 6px 0 8px;
  padding-left: 22px;
}
.markdown li { margin: 2px 0; }
.markdown li::marker { color: var(--text-faint); }

.markdown blockquote {
  margin: 8px 0;
  padding: 2px 0 2px 11px;
  border-left: 3px solid var(--border);
  color: var(--text-dim);
}

.markdown strong { font-weight: 650; }
.markdown em { font-style: italic; }

.markdown code {
  font-family: var(--font-mono);
  font-size: 0.88em;
  background: var(--bg-elev-1);
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: 1px 5px;
}

.markdown pre {
  margin: 8px 0;
  padding: 11px 13px;
  background: var(--bg-elev-1);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  overflow-x: auto;
}
.markdown pre code {
  display: block;
  background: none;
  border: none;
  padding: 0;
  font-size: 12.5px;
  line-height: 1.5;
  white-space: pre;
  color: var(--text);
}

.markdown a {
  color: var(--accent);
  text-decoration: none;
  overflow-wrap: anywhere;
}
.markdown a:hover { text-decoration: underline; }

/* Collapsible "process" block — folded one-line summary the user can unfold to
   see the streamed reasoning + tool activity (Gemini pattern). Folded by default. */
.process { margin: 0 0 12px; }
.process-toggle {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: transparent;
  border: none;
  padding: 3px 0;
  cursor: pointer;
  color: var(--text-dim);
  font: inherit;
  font-size: 13.5px;
  font-weight: 500;
  transition: color 0.15s var(--ease);
}
.process-toggle:hover { color: var(--text); }
.process-caret {
  font-size: 18px;
  color: var(--text-faint);
  transition: transform 0.2s var(--ease);
}
.process.open .process-caret { transform: rotate(90deg); }
.process-detail {
  display: none;
  margin-top: 10px;
}
.process.open .process-detail { display: block; }

/* Process timeline (Gemini-style): reasoning + tool steps as nodes on a rail. */
.process-timeline {
  position: relative;
  padding: 2px 0;
}
/* The vertical rail connecting node icons. */
.process-timeline::before {
  content: "";
  position: absolute;
  left: 11px;
  top: 12px;
  bottom: 12px;
  width: 1.5px;
  background: var(--border);
}
.tl-step {
  display: grid;
  grid-template-columns: 24px 1fr;
  column-gap: 12px;
  align-items: start;
}
.tl-icon {
  position: relative;
  z-index: 1;
  grid-column: 1;
  display: grid;
  place-items: center;
  width: 24px;
  height: 22px;
  color: var(--text-faint);
  background: var(--bg-elev); /* mask the rail so the icon reads as a node */
  font-size: 18px;
  font-variation-settings: "FILL" 0, "wght" 300, "GRAD" 0, "opsz" 20;
}
.tl-icon.ok { color: var(--ok); }
.tl-icon.failed { color: var(--err); }
.tl-body {
  grid-column: 2;
  min-width: 0;
  padding-bottom: 12px;
  font-size: 13.5px;
  line-height: 1.65;
  color: var(--text-dim);
  word-wrap: break-word;
  overflow-wrap: anywhere;
}
.tl-line { margin: 0; }
/* Tool nodes: name reads a touch stronger than reasoning lines. */
.tl-step.tl-tool .tl-line {
  color: var(--text);
  font-weight: 500;
}
/* Compact markdown inside reasoning nodes — proper numbered lists, code, breaks. */
.tl-body.markdown p { margin: 0 0 5px; }
.tl-body.markdown ol,
.tl-body.markdown ul { margin: 3px 0 5px; padding-left: 22px; }
.tl-body.markdown li { margin: 1px 0; }
.tl-body.markdown li::marker { color: var(--text-faint); }
.tl-body.markdown h1,
.tl-body.markdown h2,
.tl-body.markdown h3 { font-size: 13.5px; margin: 5px 0 2px; color: var(--text-dim); }

/* Streamed reasoning — Gemini style: small, muted, NOT italic. */
.bubble-thinking {
  font-size: 13.5px;
  line-height: 1.6;
  color: var(--text-dim);
  white-space: pre-wrap;
  border-left: 2px solid var(--border);
  padding-left: 12px;
  margin: 0;
}

.bubble-activity {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 10px;
}
.tool-chip {
  font-size: 11.5px;
  padding: 3px 11px;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--bg-elev-1);
  color: var(--text-dim);
  display: inline-flex;
  align-items: center;
  gap: 5px;
}
.tool-chip::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--text-faint);
}
.tool-chip.pending::before { background: var(--accent); animation: pulse 1s ease-in-out infinite; }
.tool-chip.ok::before { background: var(--ok); }
.tool-chip.failed { color: var(--danger-text); border-color: var(--danger-border); }
.tool-chip.failed::before { background: var(--err); }

/* ---------------- composer ---------------- */

/* Positioning context so the slash palette can float ABOVE the composer. */
.composer-wrap {
  flex: 0 0 auto;
  position: relative;
}
/* Gemini-style fade: a gradient mask above the composer so transcript text
   dissolves into the panel background instead of being hard-cut at the edge. */
.composer-wrap::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 100%;
  height: 32px;
  background: linear-gradient(to top, var(--bg-elev), transparent);
  pointer-events: none;
}

/* Gemini-style centered "island" composer: a rounded pill, max-width, centered in
   the panel, floating above the usage HUD (no full-width top border). Roomier
   padding than a typical chat input — Gemini's composer reads spacious, not
   cramped around the text. */
.composer {
  flex: 0 0 auto;
  display: flex;
  gap: 12px;
  align-items: flex-end;
  width: 100%;
  max-width: 768px;
  margin: 0 auto;
  padding: 18px 16px 18px 26px;
  border: none;
  border-radius: var(--radius-hero);
  background: var(--bg-elev-1);
  box-shadow: var(--shadow-md);
  transition: box-shadow 0.15s var(--ease);
}
/* No stroke, no focus highlight — elevation comes from the shadow alone. */
.composer:focus-within { box-shadow: var(--shadow-md); }
.composer-plus {
  flex: 0 0 auto;
  font-size: 23px;
  line-height: 1;
  color: var(--text-dim);
  align-self: center;
}
.composer-wrap { padding: 18px 24px 22px; }

/* Credit readout — shares the usage-hud row with the context/cost labels. */
.credit-balance {
  flex: 0 0 auto;
  display: inline-flex; /* centers the coin glyph + number on the row's vertical axis */
  align-items: center;
  font-size: 11.5px;
  font-variant-numeric: tabular-nums;
  color: var(--text-dim);
  white-space: nowrap;
}
.credit-balance.low { color: var(--warn); }
.credit-balance[hidden] { display: none; } /* display:inline-flex above beats the UA [hidden] rule */

/* Weekly allowance bar (docs/WEEKLY_ALLOWANCE.md) — replaces the raw balance while
   the subscription allowance is active: progress through the week, not a draining
   number. Full detail (credits used/granted, wallet) lives in the tooltip. */
.allowance-hud {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  margin-left: auto; /* takes over the balance's right-alignment while it's hidden */
  font-size: 11.5px;
  line-height: 1; /* shrink text boxes to glyph height so flex centering is optical, not box math */
  font-variant-numeric: tabular-nums;
  color: var(--text-dim);
  white-space: nowrap;
}
.allowance-hud[hidden] { display: none; }
.allowance-track {
  width: 64px;
  height: 6px;
  border-radius: 999px;
  background: var(--bg-elev-3);
  overflow: hidden;
}
.allowance-fill {
  display: block;
  height: 100%;
  border-radius: 999px;
  background: var(--accent);
  transition: width 0.3s var(--ease);
}
.allowance-hud.warn .allowance-fill { background: var(--warn); }
.allowance-pct { color: var(--text); font-weight: 500; }
.allowance-hud.warn .allowance-pct { color: var(--warn); }
.allowance-reset { color: var(--text-dim); opacity: 0.75; }

/* Session savings pill — a summary line at the bottom of the newest reply
   ("−12% credits saved"). Plain words, no glyph; percentage, not a raw credit
   count; the number flips up odometer-style when the session rate changes. */
.savings-pill {
  display: inline-flex;
  align-items: center;
  gap: 4px; /* leading spaces inside the label spans collapse — gap owns spacing */
  margin-top: 10px;
  padding: 3px 11px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--ok) 14%, var(--bg-elev-2));
  color: var(--ok);
  font-size: 11.5px;
  font-weight: 650;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  user-select: none;
}
.savings-pill-pre:empty,
.savings-pill-post:empty { display: none; }
.savings-pill { line-height: 1.25; } /* one shared line box → labels + digits share an optical center */
.savings-pill-num {
  position: relative;
  display: inline-block;
  overflow: hidden;
  height: 1.25em;
}
/* block, not inline-block: baseline alignment inside the clipped window pushed
   the digits ~2px below the labels' center. A block child fills from the top. */
.savings-pill-digit { display: block; line-height: 1.25; }
.savings-pill-digit.flip-in { animation: savings-flip-in 0.35s var(--ease); }
.savings-pill-digit.flip-out {
  position: absolute;
  left: 0;
  top: 0;
  animation: savings-flip-out 0.35s var(--ease) forwards;
}
@keyframes savings-flip-in {
  from { transform: translateY(115%); }
  to { transform: translateY(0); }
}
@keyframes savings-flip-out {
  from { transform: translateY(0); opacity: 1; }
  to { transform: translateY(-115%); opacity: 0; }
}

.credit-topup {
  flex: 0 0 auto;
  font-size: 11.5px;
  font-weight: 600;
  color: var(--accent);
  background: var(--bg-elev-2);
  border: none;
  cursor: pointer;
  padding: 4px 13px;
  border-radius: 999px;
  transition: background 0.15s var(--ease);
}
.credit-topup:hover { background: var(--bg-elev-3); }
.credit-topup:focus { outline: none; }
.credit-topup:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* Receipts sheet — recent credit_ledger movements, opened by tapping the HUD
   balance or the weekly bar. Transparency on demand, no ambient taxi meter. */
.receipts-backdrop {
  position: fixed;
  inset: 0;
  z-index: 12000;
  background: rgba(0, 0, 0, 0.45);
  display: flex;
  align-items: flex-end;
  justify-content: center;
  /* Side + bottom insets so the sheet FLOATS with margins (Gemini style), never
     edge-to-edge; also clears the phone's home indicator. */
  padding: 0 12px calc(12px + env(safe-area-inset-bottom, 0px));
}
.receipts-sheet {
  width: min(560px, 100%);
  max-height: 62vh;
  display: flex;
  flex-direction: column;
  background: var(--bg-elev-1, var(--bg));
  /* Fully rounded — a floating card, not a docked panel. */
  border-radius: 28px;
  padding: 20px 20px 12px;
  box-shadow: 0 8px 40px rgba(0, 0, 0, 0.45);
}
.receipts-title {
  font-size: 14px;
  font-weight: 650;
  margin-bottom: 10px;
}
.receipts-list { overflow-y: auto; font-size: 13px; }
.receipt-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 8px 2px;
  border-bottom: 1px solid var(--bg-elev-2);
}
.receipt-row:last-child { border-bottom: none; }
.receipt-ic { font-size: 18px; color: var(--text-dim); }
.receipt-text { flex: 1 1 auto; min-width: 0; }
.receipt-label {
  color: var(--text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.receipt-time { font-size: 11px; color: var(--text-dim); }
.receipt-amt {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  font-variant-numeric: tabular-nums;
  color: var(--text-dim);
}
.receipt-amt.pos { color: var(--ok); }

/* The HUD money elements now open the receipts sheet. */
.credit-balance, .allowance-hud { cursor: pointer; }

/* Long-conversation hint — a quiet line above the HUD, not a scary banner. */
.context-hint {
  padding: 4px 24px 0;
  font-size: 11.5px;
  color: var(--warn);
  opacity: 0.9;
  white-space: normal;
}
.context-hint[hidden] { display: none; }

/* Budget-guard select (Settings → Agent) — matches the switch rows' scale. */
.agentset-select {
  flex: 0 0 auto;
  font: inherit;
  font-size: 13px;
  color: var(--text);
  background: var(--bg-elev-2);
  border: 1px solid var(--bg-elev-3);
  border-radius: 8px;
  padding: 5px 8px;
}

/* Composer-HUD Effort toggle — a compact pill that flips Chill ⇄ YOLO. Chill reads
   muted (the safe default); YOLO lights up to signal the agent is in autonomous mode. */
.effort-hud {
  flex: 0 0 auto;
  font-size: 11px;
  font-weight: 600;
  color: var(--text-faint);
  background: var(--bg-elev-2);
  border: none;
  cursor: pointer;
  padding: 3px 11px;
  border-radius: 999px;
  transition: background 0.15s var(--ease), color 0.15s var(--ease);
}
.effort-hud:hover { background: var(--bg-elev-3); }
.effort-hud:focus { outline: none; }
.effort-hud:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.effort-hud.is-yolo { color: var(--on-accent); background: var(--accent); }

/* ---------------- slash command palette ---------------- */

.cmd-palette {
  position: absolute;
  left: 24px;
  right: 24px;
  max-width: 768px;
  margin: 0 auto;
  bottom: calc(100% + 2px);
  z-index: 50;
  max-height: 320px;
  overflow-y: auto;
  padding: 6px;
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
  -webkit-overflow-scrolling: touch;
}
.cmd-palette[hidden] { display: none; }

/* "↓ New messages" — appears when the transcript's auto-follow is suppressed
   because the user scrolled up mid-stream. Tapping snaps back to the bottom and
   it hides once the user is there. Mirrors .cmd-palette's anchor: absolute,
   centered, floating just above the composer. */
.scroll-resume {
  position: absolute;
  left: 0;
  right: 0;
  bottom: calc(100% + 10px);
  z-index: 40;
  margin: 0 auto;
  width: fit-content;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 7px 14px 7px 11px;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--bg-elev);
  color: var(--text);
  font: 500 13px/1 system-ui, -apple-system, sans-serif;
  box-shadow: var(--shadow-lg);
  cursor: pointer;
  opacity: 0;
  transform: translateY(6px);
  pointer-events: none;
  transition: opacity 0.18s ease, transform 0.18s ease;
}
.scroll-resume .material-symbols-rounded { font-size: 18px; }
.scroll-resume.is-visible {
  opacity: 1;
  transform: translateY(0);
  pointer-events: auto;
}
@media (prefers-reduced-motion: reduce) {
  .scroll-resume { transition: opacity 0.18s ease; transform: none; }
}

.cmd-group {
  font-size: 10.5px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.6px;
  color: var(--text-faint);
  padding: 6px 8px 4px;
}

.cmd-item {
  display: flex;
  align-items: baseline;
  gap: 10px;
  padding: 8px 10px;
  border-radius: var(--radius-sm);
  cursor: pointer;
  border: 1px solid transparent;
}
.cmd-item.selected {
  background: var(--bg-elev-2);
  border-color: var(--accent);
}
.cmd-name {
  flex: 0 0 auto;
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 600;
  color: var(--accent);
}
.cmd-desc {
  flex: 1 1 auto;
  min-width: 0;
  font-size: 12.5px;
  color: var(--text-dim);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.cmd-empty {
  padding: 9px 10px;
  font-size: 12.5px;
  color: var(--text-faint);
  font-style: italic;
}
.composer-input {
  flex: 1 1 auto;
  resize: none;
  max-height: 200px;
  background: transparent;
  color: var(--text);
  border: none;
  border-radius: 0;
  padding: 11px 0;
  align-self: center;
  font: inherit;
  font-size: 16.5px;
  line-height: 1.55;
  outline: none;
}
.composer-input::placeholder { color: var(--text-faint); }

/* Icon-only round button. Gemini-style: a monochrome light/dark circle (not the
   brand gradient); the stop state just swaps the arrow glyph for a square. */
.composer-send {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  background: var(--text);
  color: var(--bg);
  border: none;
  border-radius: 50%;
  padding: 0;
  cursor: pointer;
  transition: filter 0.15s, transform 0.1s var(--ease);
}
.composer-send .material-symbols-rounded {
  font-size: 22px;
  font-variation-settings: "FILL" 0, "wght" 500, "GRAD" 0, "opsz" 24;
}
.composer-send:hover { filter: brightness(0.9); }
.composer-send:active { transform: scale(0.94); }
.composer-send:focus { outline: none; }
.composer-send:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* Empty + idle: drop the button out of layout (used by the home composer). */
.composer-send.is-hidden { display: none; }
/* …except on the home composer, where we keep the button's box RESERVED (just
   invisible) so the pill's height and the input's width don't jump the instant
   the user starts typing and the send arrow appears. */
.home-composer .composer-send.is-hidden { display: grid; visibility: hidden; }

/* Idle + empty (Gemini): a plain mic, not the filled circle. */
.composer-send.is-mic {
  background: transparent;
  color: var(--text-dim);
}
.composer-send.is-mic:hover { background: var(--bg-elev-2); color: var(--text); filter: none; }
.composer-send.is-listening { color: var(--accent); animation: pulse 1.1s ease-in-out infinite; }

/* Processing: same monochrome button, square glyph (set in JS). */
.composer-send.is-stop {
  background: var(--text);
  color: var(--bg);
}
.composer-send.is-stop:hover { filter: brightness(0.9); }
.composer-send.is-stop .material-symbols-rounded {
  font-variation-settings: "FILL" 1, "wght" 500, "GRAD" 0, "opsz" 24;
}

/* ---------------- usage HUD (statusline under composer) ---------------- */

/* Clean status line, no hard divider — blends into the panel like the rest of
   the UI. Deliberately minimal: effort toggle · credits left · Top up (token/
   context/cost telemetry lives in the admin panel, not user chrome). The Top-up
   pill rides the far edge so the strip still spans the composer. */
.usage-hud {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 2px 24px 12px;
  background: transparent;
  font-family: var(--font-ui);
}
/* Chill anchors the left edge; the credits chip + Top-up pill ride together on the
   right (credits immediately left of the button it feeds). */
.usage-hud .credit-balance { margin-left: auto; }

/* ---------------- surfaces (inline in transcript) ---------------- */

.surface-card {
  flex-shrink: 0; /* prevent transcript flex from collapsing the surface */
  align-self: stretch;
  /* Inset to align with the assistant content column (avatar width + row gap),
     so generated surfaces read as part of the assistant's turn. */
  margin-left: 56px;
  display: flex;
  flex-direction: column;
  background: var(--bg-elev-1);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
}
.surface-header {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 8px 6px 14px;
  background: var(--bg-elev);
  border-bottom: 1px solid var(--border);
}
.surface-title {
  flex: 1 1 auto;
  min-width: 0;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--text-dim);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* Header icon buttons (pin, collapse) — dim until hover, accent when active. */
.surface-btn {
  flex: 0 0 auto;
  display: inline-grid;
  place-items: center;
  width: 26px;
  height: 26px;
  padding: 0;
  border: 0;
  border-radius: 7px;
  background: transparent;
  color: var(--text-dim);
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
  opacity: 0.6;
  transition: opacity 0.15s ease, background 0.15s ease, color 0.15s ease;
}
.surface-btn:hover { opacity: 1; background: var(--bg-elev-1); }
.surface-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.surface-btn.active { opacity: 1; color: var(--accent); }
/* Refresh in flight: spin until the next render frame lands for this surface. */
.surface-refresh.is-refreshing {
  opacity: 1;
  color: var(--accent);
  animation: surface-refresh-spin 1s linear infinite;
}
@keyframes surface-refresh-spin {
  to { transform: rotate(360deg); }
}
@media (prefers-reduced-motion: reduce) {
  .surface-refresh.is-refreshing { animation: none; }
}
.surface-pin.active { font-variation-settings: "FILL" 1, "wght" 500, "GRAD" 0, "opsz" 24; }

/* Pinned: the card sticks to the top of the transcript so an interactive surface (a game,
   a live dashboard) stays visible while chat streams below. CSS-only — the card keeps its
   DOM slot, so an iframe surface never reloads. The FRAME (not the whole card) is height-
   capped, so a tall surface scrolls INTERNALLY and chat keeps a readable strip below. */
.surface-card.pinned {
  position: sticky;
  top: 6px;
  z-index: 6;
  box-shadow: var(--shadow-lg);
}
.surface-card.pinned .surface-frame { max-height: min(62dvh, 900px); }

/* Collapse: hide the body via display:none — an iframe keeps its state, so pausing a
   game/dashboard never resets it. */
.surface-card.collapsed .surface-frame,
.surface-card.collapsed .surface-view { display: none; }
.surface-frame {
  display: block;
  width: 100%;
  height: 340px;
  border: 0;
  background: transparent;
}

/* render_ui state: "loading" — a subtle in-progress cue on the card header,
   whether the surface has real (partial) content yet or is a bare skeleton. */
.surface-card.surface-loading .surface-header {
  animation: surface-header-pulse 1.3s ease-in-out infinite;
}
@keyframes surface-header-pulse {
  0%, 100% { opacity: 0.65; }
  50% { opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .surface-card.surface-loading .surface-header { animation: none; }
}

/* ---------------- structured view surfaces (chart/table) ---------------- */
/* Rendered in-page by views.ts from a data spec — no iframe. Series palette +
   semantic colors are defined here so the canvas renderer can read them. */
.surface-view {
  /* Vibrant trading-desk palette (matches the approved report mockup): gold-first
     series (the classic EMA look), crypto-desk green/red for candles. */
  --view-c1: #e8c447;
  --view-c2: #6fa8ff;
  --view-c3: #c77dff;
  --view-c4: #5ad8cc;
  --view-c5: #ff9f6e;
  --view-up: #16c784;
  --view-down: #ea3943;
  padding: 12px 14px 14px;
}
.view-stack {
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.view-stack-horizontal {
  flex-direction: row;
  flex-wrap: wrap;
}
.view-stack-horizontal > .view-stack-item {
  flex: 1 1 0;
  min-width: 140px;
}
.view-grid {
  display: grid;
  gap: 12px;
}
.view-stack-item,
.view-grid-item {
  min-width: 0;
}
/* Bare loading placeholder (no view/html yet) — an instant "something is
   coming" shape instead of a blank card for the whole wait. */
.view-skeleton-line,
.view-skeleton-block {
  background: var(--bg-elev-2);
  border-radius: 6px;
  animation: view-skeleton-pulse 1.3s ease-in-out infinite;
}
.view-skeleton-line {
  height: 13px;
  width: 38%;
  margin-bottom: 10px;
}
.view-skeleton-line.long {
  width: 62%;
}
.view-skeleton-block {
  height: 120px;
  width: 100%;
}
@keyframes view-skeleton-pulse {
  0%, 100% { opacity: 0.5; }
  50% { opacity: 0.9; }
}
@media (prefers-reduced-motion: reduce) {
  .view-skeleton-line,
  .view-skeleton-block { animation: none; }
}
.view-title {
  font-size: 13.5px;
  font-weight: 600;
  color: var(--text);
  margin-bottom: 8px;
}
.view-caption {
  font-size: 12px;
  color: var(--text-dim);
  margin-top: 8px;
}
.view-chart-wrap {
  position: relative;
  width: 100%;
}
.view-canvas {
  display: block;
  width: 100%;
}
/* Interactive chart: crosshair on hover, grabbing while panning. touch-action
   pan-y lets the page scroll vertically while horizontal drag / pinch are ours. */
.view-chart-wrap .view-canvas {
  cursor: crosshair;
  touch-action: pan-y;
}
.view-chart-wrap .view-canvas.is-panning {
  cursor: grabbing;
}
.view-chart-tip {
  position: absolute;
  z-index: 3;
  pointer-events: none;
  background: var(--bg-elev-2);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 6px 9px;
  font-size: 11.5px;
  line-height: 1.5;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.28);
}
.view-chart-tip-h {
  font-weight: 600;
  margin-bottom: 2px;
  color: var(--text-dim);
}
.view-chart-tip-r {
  color: var(--text);
}
/* Dataset switcher (e.g. timeframes) above an interactive chart. */
.view-chart-tabs {
  display: flex;
  gap: 4px;
  margin: 2px 0 6px;
}
.view-chart-tab {
  appearance: none;
  background: none;
  border: 1px solid transparent;
  border-radius: 8px;
  padding: 3px 10px;
  font: 500 11.5px/1.4 inherit;
  font-family: inherit;
  font-variant-numeric: tabular-nums;
  color: var(--text-dim);
  cursor: pointer;
}
.view-chart-tab:hover {
  color: var(--text);
}
.view-chart-tab:focus-visible {
  outline: 2px solid var(--accent, #8ab4f8);
  outline-offset: 1px;
}
.view-chart-tab.is-active {
  background: var(--bg-elev-2);
  border-color: var(--border);
  color: var(--text);
}
/* Series legend: one toggleable chip per line (click = show/hide, scale re-fits). */
.view-chart-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 2px 4px;
  margin: 0 0 4px;
}
.view-chart-key {
  appearance: none;
  background: none;
  border: 0;
  border-radius: 6px;
  padding: 2px 8px 2px 6px;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font: 500 11px/1.4 inherit;
  font-family: inherit;
  color: var(--text-dim);
  cursor: pointer;
}
.view-chart-key:hover {
  color: var(--text);
  background: var(--bg-elev-1);
}
.view-chart-key:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}
.view-chart-key-dot {
  width: 8px;
  height: 8px;
  border-radius: 3px;
  flex: 0 0 auto;
}
.view-chart-key.is-off {
  opacity: 0.45;
}
.view-chart-key.is-off .view-chart-key-name {
  text-decoration: line-through;
}
.view-table-wrap {
  width: 100%;
  overflow-x: auto;
}
.view-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
}
.view-table th,
.view-table td {
  padding: 6px 10px;
  text-align: left;
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
}
.view-table th {
  font-weight: 600;
  color: var(--text-dim);
  font-size: 12px;
}
.view-table td.num {
  text-align: right;
  font-variant-numeric: tabular-nums;
}
.view-table tbody tr:last-child td {
  border-bottom: 0;
}

/* card */
.view-card-headline {
  font-size: 30px;
  font-weight: 650;
  line-height: 1.1;
  color: var(--text);
  letter-spacing: -0.01em;
}
.view-arrow {
  font-size: 0.6em;
  vertical-align: middle;
}
.view-card-subhead {
  font-size: 13px;
  color: var(--text-dim);
  margin-top: 2px;
}
.view-card-rows {
  margin-top: 12px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.view-card-row {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  font-size: 13px;
  padding-top: 6px;
  border-top: 1px solid var(--border);
}
.view-card-label {
  color: var(--text-dim);
}
.view-card-value {
  color: var(--text);
  font-variant-numeric: tabular-nums;
}

/* kpi grid */
.view-kpi-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
  gap: 10px;
}
.view-kpi {
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 10px 12px;
}
.view-kpi-label {
  font-size: 11.5px;
  color: var(--text-dim);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.view-kpi-value {
  font-size: 20px;
  font-weight: 600;
  color: var(--text);
  margin-top: 3px;
  font-variant-numeric: tabular-nums;
}
.view-kpi-delta {
  font-size: 12px;
  margin-top: 2px;
  font-variant-numeric: tabular-nums;
}

/* list */
.view-list {
  margin: 0;
  padding: 0;
  list-style: none;
  counter-reset: viewlist;
}
.view-list[class] {
  /* keep zero default padding for both ol/ul */
}
ol.view-list {
  counter-reset: viewlist;
}
.view-list-item {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  padding: 7px 0;
  border-bottom: 1px solid var(--border);
  font-size: 13.5px;
}
.view-list-item:last-child {
  border-bottom: 0;
}
ol.view-list .view-list-main::before {
  counter-increment: viewlist;
  content: counter(viewlist) ". ";
  color: var(--text-dim);
}
.view-list-main {
  min-width: 0;
}
.view-list-text {
  color: var(--text);
}
.view-list-secondary {
  color: var(--text-dim);
  margin-left: 8px;
  font-size: 12.5px;
}
.view-list-value {
  color: var(--text);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* form */
.view-form {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.view-field {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.view-field-label {
  font-size: 12px;
  color: var(--text-dim);
}
.view-input {
  width: 100%;
  box-sizing: border-box;
  padding: 8px 10px;
  font: inherit;
  font-size: 13px;
  color: var(--text);
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: 8px;
}
.view-input:focus {
  outline: none;
  border-color: var(--accent);
}
textarea.view-input {
  min-height: 64px;
  resize: vertical;
}
.view-checkbox {
  width: 16px;
  height: 16px;
  accent-color: var(--accent);
  align-self: flex-start;
}
.view-form-status {
  font-size: 12px;
  color: var(--text-dim);
  min-height: 14px;
}

/* buttons */
.view-buttons-text {
  font-size: 13.5px;
  color: var(--text);
  margin-bottom: 8px;
}
.view-buttons {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}
.view-btn {
  font: inherit;
  font-size: 13px;
  font-weight: 500;
  padding: 8px 14px;
  border-radius: 8px;
  border: 1px solid var(--border);
  background: var(--bg-elev);
  color: var(--text);
  cursor: pointer;
  transition: filter 0.12s, opacity 0.12s;
}
.view-btn:hover:not(:disabled) {
  filter: brightness(1.12);
}
.view-btn.primary {
  background: var(--accent);
  border-color: var(--accent);
  color: #06121f;
}
.view-btn.danger {
  background: #f28b82;
  border-color: #f28b82;
  color: #2a0a08;
}
.view-btn.selected {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}
.view-btn:disabled {
  opacity: 0.55;
  cursor: default;
}
.view-form .view-btn {
  align-self: flex-start;
}

/* ---------------- web-search sources (Path 2) ---------------- */
.sources-panel {
  /* Align under the assistant content column, matching surface cards. */
  margin: 10px 0 2px;
  padding: 10px 14px;
  background: var(--bg-elev-1);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}
.sources-head {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-faint);
  margin-bottom: 6px;
}
.sources-list {
  margin: 0;
  padding-left: 18px;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.sources-list li {
  font-size: 13px;
  line-height: 1.45;
}
.sources-list a.src-link {
  color: var(--accent);
  text-decoration: none;
}
.sources-list a.src-link:hover {
  text-decoration: underline;
}
.sources-list .src-host {
  margin-left: 6px;
  color: var(--text-faint);
  font-size: 11.5px;
}

/* ---------------- settings modal ---------------- */

.settings-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.55);
  backdrop-filter: blur(2px);
  display: grid;
  place-items: center;
  padding: 20px;
  /* Above the auth/agent gate (.auth-overlay z 1000) so the buy-agent modal,
     reachable from the agent picker, layers on top of it. */
  z-index: 1100;
}
.settings-panel {
  width: min(560px, 100%);
  max-height: 90dvh;
  overflow-y: auto;
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
}
.settings-titlebar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 16px 20px;
  border-bottom: 1px solid var(--border);
  position: sticky;
  top: 0;
  background: var(--bg-elev);
  /* Above scrolling content — the gacha card's animated transform creates a stacking
     context that would otherwise paint over this sticky bar on mobile. */
  z-index: 2;
}
.settings-titlebar h2 { margin: 0; font-size: 17px; }
.settings-close {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 40px; min-height: 40px;
  background: transparent;
  border: none;
  border-radius: 999px;
  color: var(--text-dim);
  font-size: 24px;
  line-height: 1;
  cursor: pointer;
}
.settings-close:hover { color: var(--text); background: var(--bg-elev-2); }

/* ---------------- in-app confirm / prompt dialog (confirm.ui.ts) ----------------
   Tonal Gemini replacement for window.confirm()/prompt(); centered, --ease motion. */
.confirm-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.55);
  backdrop-filter: blur(2px);
  display: grid;
  place-items: center;
  padding: 20px;
  z-index: 1400;
}
.confirm-dialog {
  width: min(400px, 100%);
  background: var(--bg-elev);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  padding: 24px;
  animation: confirm-in 0.2s var(--ease);
}
@keyframes confirm-in {
  from { opacity: 0; transform: scale(0.96) translateY(8px); }
  to { opacity: 1; transform: none; }
}
.confirm-title { font-family: var(--font-display); font-size: 19px; font-weight: 600; color: var(--text); line-height: 1.3; }
.confirm-msg { margin-top: 8px; font-size: 14px; line-height: 1.5; color: var(--text-dim); }
.confirm-input {
  width: 100%; margin-top: 16px;
  background: var(--bg-elev-2); border: none; border-radius: var(--radius-sm);
  padding: 12px 14px; font: inherit; font-size: 15px; color: var(--text);
  outline: 2px solid transparent; transition: outline-color 0.15s var(--ease);
}
.confirm-input::placeholder { color: var(--text-faint); }
.confirm-input:focus { outline-color: color-mix(in srgb, var(--accent) 50%, transparent); }
.confirm-actions { display: flex; justify-content: flex-end; gap: 10px; margin-top: 22px; }
.confirm-btn {
  border: none; border-radius: 999px; padding: 11px 20px; min-height: 44px;
  font: inherit; font-size: 14px; font-weight: 600; cursor: pointer;
  transition: background 0.15s var(--ease), filter 0.15s var(--ease);
}
.confirm-btn-cancel { background: var(--bg-elev-2); color: var(--text); }
.confirm-btn-cancel:hover { background: var(--bg-elev-3); }
.confirm-btn-ok { background: var(--accent); color: var(--on-accent); }
.confirm-btn-ok:hover { filter: brightness(1.08); }
.confirm-btn-danger { background: var(--danger); color: var(--on-accent); }
.confirm-btn-danger:hover { filter: brightness(1.08); }

.settings-section {
  padding: 18px 20px;
  border-bottom: 1px solid var(--border);
}
.settings-section:last-child { border-bottom: none; }
/* Admin panels: each section is its own Gemini card (elevated surface, rounded, gapped)
   instead of a divider-separated block, so sections read as distinct — matches the
   settings-view treatment but without its narrow width cap (admin holds wide tables/charts). */
.admin-body .settings-section {
  background: var(--bg-elev-1);
  border: none;
  border-radius: var(--radius-lg);
  padding: 28px 32px;
  margin: 0 0 20px;
}
.admin-body .settings-section:last-child { margin-bottom: 0; }
@media (max-width: 640px) {
  .admin-body .settings-section { padding: 22px 20px; }
}
.settings-section h3 { margin: 0 0 12px; font-size: 14px; color: var(--text-dim); text-transform: uppercase; letter-spacing: 0.5px; }

.settings-radios { display: flex; gap: 20px; margin-bottom: 14px; font-size: 14px; }

/* Billing modal (M6) — reuses .settings-overlay/.settings-panel/.settings-section. */
.billing-body { max-height: 70vh; overflow-y: auto; }
/* Buy-agent: let the panel itself own the scroll (90dvh) so the popup runs as tall
   as it can and content rarely needs scrolling. No nested scroll region. */
.buy-agent-body { max-height: none; overflow: visible; }
.billing-note { padding: 24px 20px; color: var(--text-faint); font-size: 14px; }
/* One-line heads-up under the buy CTA (on-chain): payment comes from your wallet. */
.buy-hint { font-size: 12.5px; color: var(--text-dim); line-height: 1.5; text-align: center; margin-top: 2px; }
/* Trial terms at the reinvest checkout — amber, icon + text, matching the yield card's trial
   banner so the "unlock at first fee" deal reads the same at the point of decision. */
.buy-hint--trial {
  display: flex; align-items: center; gap: 8px; text-align: left; color: var(--text);
  margin-top: 8px; padding: 9px 11px; border-radius: var(--radius-md);
  border: 1px solid color-mix(in srgb, var(--warn) 45%, transparent);
  background: color-mix(in srgb, var(--warn) 12%, var(--bg-elev-1));
}
.buy-hint--trial .material-symbols-rounded { flex: none; font-size: 18px; color: var(--warn); }

/* Buy-agent titlebar: groups the "New agent" heading with the reinvest "Locked liquidity"
   badge so the funding source reads as a header-level fact, not fine print. */
.buy-title-group { display: flex; align-items: center; gap: 10px; min-width: 0; }
.buy-locked-badge {
  display: inline-flex; align-items: center; gap: 5px; padding: 4px 10px; border-radius: 999px;
  font-size: 12px; font-weight: 650; font-variant-numeric: tabular-nums; white-space: nowrap;
  background: color-mix(in srgb, var(--grad-b) 18%, var(--bg-elev-1)); color: var(--text);
}
.buy-locked-badge .material-symbols-rounded { font-size: 14px; color: var(--grad-b); }

/* Funding modal (self-custodial deposit) — same Gemini design language as the Wallet
   Receive modal: wallet-modal panel (24px radius, display-font title), wallet QR +
   address + white pill, with a guided amount card / network / withdrawal checklist.
   The 90dvh panel owns the scroll (wallet-modal-body has no inner clip). */
/* wallet-modal sets overflow:visible (its modals are short); the funding modal is
   taller, so restore the panel's own 90dvh scroll (3-class beats .wallet-modal). */
.settings-panel.wallet-modal.fund-panel { overflow-y: auto; }
.fund-body { display: flex; flex-direction: column; gap: 14px; }
.fund-body .wallet-qr,
.fund-body .wallet-receive-addr,
.fund-body .wallet-modal-intro,
.fund-body .auth-btn { margin: 0; }
.fund-card { background: var(--bg-elev-1); border-radius: var(--radius); padding: 16px 18px; }
.fund-card-label {
  font-size: 12px; font-weight: 600; letter-spacing: 0.5px; text-transform: uppercase;
  color: var(--text-dim);
}
.fund-amount { text-align: center; }
.fund-amount-big {
  font-family: var(--font-display); font-size: 30px; font-weight: 700; line-height: 1.1;
  color: var(--text); font-variant-numeric: tabular-nums; margin-top: 7px;
}
.fund-amount-sub { font-size: 13px; color: var(--text-faint); margin-top: 7px; }
.fund-guide { display: flex; flex-direction: column; gap: 12px; }
.fund-guide-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.fund-net-value { font-size: 14px; font-weight: 600; color: var(--text); }
.fund-steps {
  margin: 0; padding-left: 20px; display: flex; flex-direction: column; gap: 7px;
  font-size: 13.5px; line-height: 1.5; color: var(--text-dim);
}
.fund-warn { font-size: 12.5px; color: var(--warn); line-height: 1.5; text-align: center; }
.fund-reassure { font-size: 12.5px; color: var(--text-faint); line-height: 1.55; text-align: center; }
.fund-status { font-size: 13px; color: var(--text-faint); text-align: center; }
.billing-balance { font-size: 14px; color: var(--text); margin-bottom: 12px; }
.billing-balance.billing-warn { color: var(--warn); }
.billing-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 8px;
}
.billing-buy {
  display: block;
  width: 100%;
  min-height: 44px;
  padding: 12px;
  background: var(--bg-elev-2);
  color: var(--text);
  border: none;
  border-radius: 999px;
  font: inherit;
  font-size: 13.5px;
  font-weight: 600;
  cursor: pointer;
  text-align: center;
  transition: background 0.12s var(--ease);
}
.billing-buy:hover:not(:disabled) { background: var(--bg-elev-3); }
.billing-buy:disabled { opacity: 0.5; cursor: default; }
.billing-grid-1 { grid-template-columns: 1fr; }
.settings-radios label { display: inline-flex; align-items: center; gap: 7px; cursor: pointer; }

/* ------------------------------------------------------------------ */
/* Buy-agent screen (Gemini design)                                    */
/* ------------------------------------------------------------------ */
.buy-agent { display: flex; flex-direction: column; gap: 15px; }
.buy-agent .settings-label { margin-top: 0; }

/* Buy-agent modal is wider so the 2-column layout fits everything without scroll. */
.settings-panel.buy-agent-panel { width: min(880px, 100%); }
/* Single column on mobile (stacks: card, then details); two columns from 680px up:
   gacha card + its rarity/supply bar on the left, all details + CTA on the right. */
.buy-agent-grid { display: grid; grid-template-columns: 1fr; gap: 18px; }
.buy-agent-card-col { display: flex; flex-direction: column; gap: 12px; }
.buy-agent-form-col { display: flex; flex-direction: column; gap: 15px; min-width: 0; }
@media (min-width: 680px) {
  .buy-agent-grid { grid-template-columns: minmax(240px, 300px) 1fr; gap: 26px; align-items: start; }
  .buy-agent-card-col { position: sticky; top: 4px; }
}

/* Pre-sheet loading veil: while the catalog/quote load, the overlay holds only a
   shimmering mystery card (aurora drift + a soft pulse around the Genie mark) — the
   New-agent sheet then appears fully formed instead of opening half-empty. */
.buy-loading-stage { display: grid; place-items: center; pointer-events: none; }
.buy-card-skel {
  width: min(58vw, 216px); aspect-ratio: 5 / 7; border-radius: var(--radius-lg);
  display: grid; place-items: center; color: #fff;
  background: linear-gradient(125deg, var(--grad-a), var(--grad-b) 42%, var(--grad-c) 72%, var(--grad-a) 100%);
  background-size: 240% 240%;
  box-shadow: 0 24px 48px -16px rgba(0, 0, 0, 0.6);
  animation: buy-card-aurora 4.5s ease-in-out infinite, buy-skel-pulse 1.6s ease-in-out infinite;
}
.buy-card-skel .material-symbols-rounded { font-size: 46px; filter: drop-shadow(0 2px 10px rgba(0, 0, 0, 0.4)); animation: buy-skel-spark 1.6s ease-in-out infinite; }
@keyframes buy-skel-pulse { 0%, 100% { transform: scale(0.98); } 50% { transform: scale(1); } }
@keyframes buy-skel-spark { 0%, 100% { transform: scale(1); opacity: 0.85; } 50% { transform: scale(1.18); opacity: 1; } }
/* The aurora drift these cards animate with — referenced by the gacha mystery back
   too, which previously pointed at keyframes that were never defined. */
@keyframes buy-card-aurora {
  0%, 100% { background-position: 0% 30%; }
  50% { background-position: 100% 70%; }
}
@media (prefers-reduced-motion: reduce) { .buy-card-skel, .buy-card-skel .material-symbols-rounded { animation: none; } }

/* Hero card — the Genie mascot (Three.js/WebGL orb) on a calm dark back (a
   portrait collectible card). The card lives on a "stage" so entrance
   (scale/fade) and the floating idle animation don't fight over `transform`
   (they're on different elements). */
.buy-card-stage {
  width: 100%;
  max-width: 264px;
  margin: 0 auto;
  perspective: 1000px;
  animation: buy-card-in 0.6s var(--ease) both;
}
.buy-card {
  position: relative;
  width: 100%;
  aspect-ratio: 5 / 7;
  max-height: 370px;
  margin: 0 auto;
  padding: 14px 14px 16px;
  border-radius: var(--radius-lg);
  border: 1.5px solid rgba(255, 255, 255, 0.14);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  /* Calm dark backdrop — the mascot's own rim glow is the color story here, so
     the card behind it stays quiet instead of competing for attention. */
  background: radial-gradient(120% 90% at 50% 8%, #1d1e26, var(--bg-elev-1) 60%, #0c0c10 100%);
  transform-style: preserve-3d;
  animation:
    buy-card-float 6s ease-in-out infinite,
    buy-card-glow 4.5s ease-in-out infinite;
  transition: filter 0.25s var(--ease);
}
/* Static top gloss for depth. */
.buy-card::after {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(120% 75% at 22% 0%, rgba(255, 255, 255, 0.12), transparent 55%);
  pointer-events: none;
}
.buy-card-mascot {
  position: absolute;
  top: 8%;
  left: 0;
  width: 100%;
  height: 68%;
  display: block;
  cursor: pointer;
}
/* Head row: NAME (left) + star-tier pill (right), riding above the mascot canvas. */
.buy-card-head {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  color: #fff;
}
/* Foot: the price alone, centred, dressed as a swing tag. The drop-shadow lives HERE
   (not on the tag) because clip-path on the tag would clip its own box-shadow. */
.buy-card-foot {
  position: relative;
  z-index: 1;
  display: flex;
  justify-content: center;
  color: #fff;
  filter: drop-shadow(0 5px 12px rgba(0, 0, 0, 0.45));
}
.buy-card-name {
  flex: 1;
  min-width: 0;
  font-family: var(--font-display);
  font-size: 18px;
  font-weight: 600;
  text-shadow: 0 1px 8px rgba(0, 0, 0, 0.35);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* Price tag: a light ticket with a pointed left end and a punched string-hole, so the
   number reads as THE PRICE — echoing the light CTA button — not as another data pill. */
.buy-card-price {
  position: relative;
  flex: 0 0 auto;
  font-size: 13.5px;
  font-weight: 700;
  white-space: nowrap;
  color: #14151a;
  background: linear-gradient(180deg, #ffffff, #e8eaf1);
  padding: 6px 14px 6px 24px;
  border-radius: 3px 8px 8px 3px;
  clip-path: polygon(14px 0, 100% 0, 100% 100%, 14px 100%, 0 50%);
}
.buy-card-price::before {
  content: "";
  position: absolute;
  left: 11px;
  top: 50%;
  width: 5px;
  height: 5px;
  transform: translateY(-50%);
  border-radius: 50%;
  background: rgba(20, 21, 26, 0.55); /* the punched hole */
}
/* Star-tier badge in the head row — a frosted dark pill so the star reads on the
   bright card (the generic tier-colored .star-pill would clash with it). */
.buy-card-star {
  flex: 0 0 auto;
  display: inline-flex; align-items: center; gap: 3px;
  padding: 4px 10px; border-radius: 999px;
  background: rgba(0, 0, 0, 0.28); color: #fff;
  font-size: 13px; font-weight: 700; font-variant-numeric: tabular-nums;
  backdrop-filter: blur(2px);
}
.buy-card-star-ic { font-size: 15px; font-variation-settings: "FILL" 1, "wght" 500, "GRAD" 0, "opsz" 20; }
/* Hover: brighten + saturate (not transform — that's owned by the float animation). */
.buy-card-stage:hover .buy-card { filter: brightness(1.08) saturate(1.12); }

@keyframes buy-card-in {
  from { opacity: 0; transform: translateY(16px) scale(0.93); }
  to { opacity: 1; transform: translateY(0) scale(1); }
}
@keyframes buy-card-float {
  0%, 100% { transform: translateY(0) rotate(-0.4deg); }
  50% { transform: translateY(-8px) rotate(0.4deg); }
}
@keyframes buy-card-glow {
  0%, 100% { box-shadow: 0 12px 30px rgba(0, 0, 0, 0.5), 0 0 0 rgba(120, 90, 220, 0); }
  50% { box-shadow: 0 18px 44px rgba(0, 0, 0, 0.55), 0 0 34px rgba(120, 90, 220, 0.45); }
}
@media (prefers-reduced-motion: reduce) {
  .buy-card-stage,
  .buy-card { animation: none; }
}

/* Tier / supply progress */
.buy-tier { display: flex; flex-direction: column; gap: 8px; }
.buy-tier-head { display: flex; align-items: baseline; justify-content: space-between; font-size: 13px; }
.buy-tier-label { color: var(--text-dim); }
.buy-tier-count { color: var(--text); font-weight: 600; font-variant-numeric: tabular-nums; }
.buy-progress { height: 8px; border-radius: 999px; background: var(--bg-elev-2); overflow: hidden; }
.buy-progress-fill {
  height: 100%;
  min-width: 6px;
  border-radius: 999px;
  background: var(--grad);
  transition: width 0.3s var(--ease);
}
.buy-tier-sub { font-size: 12px; color: var(--text-faint); }

/* Earn pitch (billing.ui.ts yieldPreview). Gold hero number (count-up) + always-visible,
   color-coded value lines. Calm, Gemini-organized: a soft static gold wash, no animation,
   no horizontal scroll — the value reads at a glance. Cash-math detail sits in the
   "How payouts work" disclosure. */
.buy-earn--hype {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 16px 18px;
  border: 1px solid color-mix(in srgb, #ffd166 26%, var(--border));
  border-radius: var(--radius-lg, 18px);
  background:
    radial-gradient(130% 120% at 0% 0%, color-mix(in srgb, #ffd166 10%, transparent), transparent 55%),
    var(--bg-elev-1);
}
.buy-earn-ic { font-size: 20px; flex: 0 0 auto; }
.buy-earn-kicker {
  display: flex; align-items: center; gap: 8px;
  font-size: 13px; font-weight: 600;
  color: color-mix(in srgb, #ffd166 60%, var(--text));
}
.buy-earn-kicker .buy-earn-ic { font-size: 18px; color: #ffd166; }
.buy-earn-badge {
  margin-left: auto;
  font-size: 11px; font-weight: 700;
  padding: 2px 8px; border-radius: 999px;
  color: var(--warn);
  background: color-mix(in srgb, var(--warn) 18%, transparent);
}
.buy-earn-bignum { display: flex; align-items: baseline; gap: 10px; }
.buy-earn-bignum-val {
  font-size: 38px; font-weight: 800; line-height: 1;
  color: var(--text);
  font-variant-numeric: tabular-nums;
}
.buy-earn-bignum-unit { display: flex; flex-direction: column; line-height: 1.25; }
.buy-earn-bignum-unit-day { font-size: 14px; font-weight: 600; color: var(--text-dim); }
.buy-earn-bignum-unit-mo { font-size: 12px; color: var(--text-faint); }
/* Always-visible color-coded value lines (no scroll, nothing hidden). */
.buy-earn-values { display: flex; flex-direction: column; gap: 10px; }
.buy-earn-v { display: flex; align-items: flex-start; gap: 11px; }
.buy-earn-v-ic { font-size: 22px; flex: 0 0 auto; margin-top: 1px; }
.buy-earn-v-main { display: flex; flex-direction: column; gap: 1px; }
.buy-earn-v-title { font-size: 14px; font-weight: 700; color: var(--text); }
.buy-earn-v-sub { font-size: 12px; line-height: 1.35; color: var(--text-faint); }
.buy-earn-fine { margin-top: 2px; border-top: 1px solid var(--border); padding-top: 8px; }
.buy-earn-fine-summary {
  cursor: pointer; list-style: none;
  font-size: 12.5px; color: var(--text-faint);
  padding: 4px 0;
}
.buy-earn-fine-summary::-webkit-details-marker { display: none; }
.buy-earn-fine-summary::before { content: "▸ "; }
.buy-earn-fine[open] .buy-earn-fine-summary::before { content: "▾ "; }
.buy-earn-rows { display: flex; flex-direction: column; gap: 8px; padding-top: 6px; }
.buy-earn-row { display: flex; align-items: center; gap: 10px; font-size: 13px; }
.buy-earn-row .buy-earn-ic { font-size: 18px; color: var(--text-faint); }
.buy-earn-row-label { color: var(--text-dim); flex: 1 1 auto; }
.buy-earn-row-val { color: var(--text); font-weight: 600; font-variant-numeric: tabular-nums; }

/* Fields */
.buy-field { display: flex; flex-direction: column; gap: 7px; }

/* Coupon: input + Apply button, with a validity message below. */
.buy-coupon-row { display: flex; gap: 8px; align-items: stretch; }
.buy-coupon-row .settings-input { flex: 1 1 auto; }
.buy-coupon-apply {
  flex: 0 0 auto;
  padding: 0 18px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--bg-elev-2);
  color: var(--text);
  font: inherit; font-size: 14px; font-weight: 600;
  cursor: pointer;
  transition: background 0.15s var(--ease), opacity 0.15s var(--ease);
}
.buy-coupon-apply:hover:not(:disabled) { background: var(--bg-elev-3); }
.buy-coupon-apply:disabled { opacity: 0.55; cursor: default; }
.buy-coupon-msg { font-size: 12.5px; line-height: 1.4; }
/* Coupon collapsed behind a link (saves vertical space on mobile). */
.buy-coupon-fold > .buy-coupon-row { margin-top: 8px; }
.buy-coupon-summary {
  cursor: pointer; list-style: none;
  font-size: 13px; color: var(--text-faint);
  padding: 2px 0;
}
.buy-coupon-summary::-webkit-details-marker { display: none; }
.buy-coupon-summary::before { content: "+ "; }
.buy-coupon-fold[open] .buy-coupon-summary::before { content: "− "; }
.buy-coupon-msg.is-ok { color: var(--ok); }
.buy-coupon-msg.is-err { color: var(--warn); }
/* Original price struck through next to the discounted one on the hero card. */
.buy-card-price-was { text-decoration: line-through; opacity: 0.6; font-weight: 500; margin-right: 7px; }

/* Quantity: quick chips + numeric stepper */
.buy-qty { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.buy-qty-chips { display: flex; gap: 7px; }
.buy-chip {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 40px; min-height: 40px;
  padding: 8px 12px;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--bg-elev-1);
  color: var(--text-dim);
  font: inherit;
  font-size: 13.5px;
  cursor: pointer;
  transition: background 0.12s, border-color 0.12s, color 0.12s;
}
.buy-chip:hover { border-color: var(--accent); }
.buy-chip.active { background: var(--accent); border-color: var(--accent); color: var(--on-accent); font-weight: 600; }
.buy-chip.is-danger { color: var(--err); }
.buy-chip.is-danger:hover { border-color: var(--err); background: color-mix(in srgb, var(--err) 14%, transparent); }
.buy-stepper {
  display: flex;
  align-items: center;
  gap: 4px;
  margin-left: auto;
  padding: 3px;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--bg-elev-1);
}
.buy-step-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border: none;
  border-radius: 50%;
  background: transparent;
  color: var(--text);
  font-size: 20px;
  line-height: 1;
  cursor: pointer;
  transition: background 0.12s;
}
.buy-step-btn:hover:not(:disabled) { background: var(--bg-elev-2); }
.buy-step-btn:disabled { opacity: 0.35; cursor: default; }
.buy-qty-input {
  width: 44px;
  text-align: center;
  background: transparent;
  border: none;
  outline: none;
  color: var(--text);
  font: inherit;
  font-size: 15px;
  font-weight: 600;
  -moz-appearance: textfield;
}
.buy-qty-input::-webkit-outer-spin-button,
.buy-qty-input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }

/* Terms checkbox */
.buy-terms {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  font-size: 13px;
  line-height: 1.45;
  color: var(--text-dim);
  cursor: pointer;
}
.buy-terms-check { flex: 0 0 auto; width: 18px; height: 18px; margin-top: 1px; accent-color: var(--accent); cursor: pointer; }
.buy-terms-link { color: var(--accent); text-decoration: none; }
.buy-terms-link:hover { text-decoration: underline; }

/* CTA — the prominent gradient action */
.buy-cta {
  padding: 15px 16px;
  font-size: 15px;
  font-weight: 600;
  color: var(--on-accent);
  background: var(--grad);
  border: none;
}
.buy-cta:hover:not(:disabled) { background: var(--grad); border: none; filter: brightness(1.05); }
.buy-cta:disabled { opacity: 0.45; }

.settings-fields { display: flex; flex-direction: column; gap: 7px; }
.settings-label { font-size: 12.5px; color: var(--text-dim); margin-top: 6px; }

.settings-input, .settings-textarea {
  width: 100%;
  background: var(--bg-elev-1);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 10px 12px;
  font: inherit;
  font-size: 14px;
  outline: none;
}
.settings-input:focus, .settings-textarea:focus { border-color: var(--accent); }
.settings-textarea { resize: vertical; font-family: var(--font-mono); font-size: 12.5px; }

/* Warn-only cash-safety notice under the settings Save button (the save still succeeds). */
.settings-cash-warning {
  margin-top: 10px;
  padding: 10px 12px;
  border-radius: var(--radius-sm);
  background: var(--banner-warn-bg);
  color: var(--banner-warn-fg);
  border: 1px solid var(--banner-warn-bd);
  font-size: 12.5px;
  line-height: 1.5;
  display: grid;
  gap: 4px;
}
.settings-cash-warning strong { font-weight: 700; }

/* ── Admin → Danger zone: live-money master switches (yield & payments) ─────── */
/* Red-accented nav item so the destructive panel reads as set-apart at a glance. */
.admin-nav-item.is-danger .admin-nav-icon { color: var(--danger-text); }
.admin-nav-item.is-danger.is-active .admin-nav-label,
.admin-nav-item.is-danger.is-active .admin-nav-icon { color: var(--danger-text); }
.admin-danger-banner {
  display: flex; gap: 10px; align-items: flex-start;
  margin-bottom: 20px; padding: 16px 22px;
  border-radius: var(--radius-md);
  background: var(--danger-bg); color: var(--danger-text);
  border: 1px solid var(--danger-border);
  font-size: 13px; line-height: 1.5;
}
.admin-danger-banner .material-symbols-rounded { font-size: 20px; flex: none; }
.admin-danger-banner strong { font-weight: 700; }
.danger-toggle {
  border: 1px solid var(--danger-border);
  background: color-mix(in srgb, var(--danger-bg) 55%, var(--bg-elev-1));
  border-radius: var(--radius-lg);
  padding: 24px 28px; display: grid; gap: 12px;
}
.danger-toggle + .danger-toggle { margin-top: 18px; }
@media (max-width: 640px) {
  .danger-toggle { padding: 18px 20px; }
}
.danger-toggle-title { font-size: 15px; font-weight: 700; color: var(--text); }
.danger-toggle-desc { font-size: 12.5px; color: var(--text-dim); line-height: 1.5; margin-top: 3px; }
.danger-seg { display: flex; gap: 8px; flex-wrap: wrap; }
.danger-opt {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 9px 18px; border-radius: var(--radius-md); cursor: pointer;
  background: var(--bg-elev-1); border: none; color: var(--text-dim);
  font: inherit; font-size: 13.5px; font-weight: 600;
  box-shadow: inset 0 0 0 1.5px transparent;
  transition: color 0.15s var(--ease), background 0.15s var(--ease), box-shadow 0.15s var(--ease);
}
.danger-opt:hover { color: var(--text); background: var(--bg-elev-2); }
.danger-opt:disabled { opacity: 0.55; cursor: default; }
/* Selected state: neutral for Off, amber for partial (admins only), red for fully Live. */
.danger-opt.is-active {
  color: var(--text); background: var(--bg-elev-2);
  box-shadow: inset 0 0 0 1.5px var(--border);
}
.danger-opt.is-active.is-partial {
  color: var(--banner-warn-fg); background: var(--banner-warn-bg);
  box-shadow: inset 0 0 0 1.5px var(--banner-warn-bd);
}
.danger-opt.is-active.is-live {
  color: #fff; background: var(--danger);
  box-shadow: inset 0 0 0 1.5px color-mix(in srgb, var(--danger) 60%, transparent);
}
.danger-status { font-size: 12.5px; color: var(--text-dim); min-height: 16px; }
.danger-status.is-ok { color: var(--ok); }
.danger-status.is-warn { color: var(--banner-warn-fg); }
.danger-status.is-err { color: var(--danger-text); }

.settings-actions { display: flex; gap: 10px; margin-top: 16px; }
.settings-inline-row { display: flex; gap: 8px; }
.settings-inline-row .settings-input { flex: 1 1 auto; }

.settings-btn {
  background: var(--bg-elev-2);
  color: var(--text);
  border: none;
  border-radius: 999px;
  padding: 10px 20px;
  font: inherit;
  font-size: 13.5px;
  font-weight: 550;
  cursor: pointer;
  white-space: nowrap;
  transition: background 0.15s var(--ease);
}
.settings-btn:hover { background: var(--bg-elev-3); }
.settings-btn.primary {
  background: var(--grad);
  color: var(--on-accent);
  border: none;
  font-weight: 650;
}
.settings-btn.primary:hover { filter: brightness(1.08); }

.settings-status { font-size: 13px; margin-top: 10px; min-height: 18px; color: var(--text-dim); }
.settings-status.ok { color: var(--ok); }
.settings-status.err { color: var(--err); }

/* Language picker (International settings) — selectable cards, one per language. */
.settings-lang-options { display: flex; flex-direction: column; gap: 8px; max-width: 420px; }
.settings-lang-option {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  width: 100%;
  padding: 13px 16px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--bg-elev-1);
  color: var(--text);
  font: inherit;
  font-size: 0.95rem;
  text-align: left;
  cursor: pointer;
  transition: background 0.12s ease, border-color 0.12s ease;
}
.settings-lang-option:hover { background: var(--bg-elev-2); }
.settings-lang-option.is-active { border-color: var(--accent); background: var(--bg-elev-2); }
.settings-lang-name { flex: 1 1 auto; font-weight: 500; }
.settings-lang-check { font-size: 20px; color: var(--accent, #6b9fff); opacity: 0; }
.settings-lang-option.is-active .settings-lang-check { opacity: 1; }

.skill-list { list-style: none; margin: 0 0 16px; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.skill-empty { color: var(--text-faint); font-size: 13px; }
.skill-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 9px 11px;
  background: var(--bg-elev-1);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}
.skill-meta { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.skill-name { font-size: 13.5px; font-weight: 600; }
.skill-desc { font-size: 12px; color: var(--text-dim); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.skill-del {
  flex: 0 0 auto;
  background: transparent;
  color: var(--danger-text);
  border: 1px solid var(--danger-border);
  border-radius: 999px;
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 38px; padding: 6px 14px;
  font: inherit;
  font-size: 12.5px;
  cursor: pointer;
}
.skill-del:hover { background: var(--danger-bg); }
/* Neutral counterpart to .skill-del for non-destructive row actions (e.g. Edit). */
.skill-edit {
  flex: 0 0 auto;
  background: var(--bg-elev-2);
  color: var(--text);
  border: none;
  border-radius: 999px;
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 38px; padding: 6px 14px;
  font: inherit;
  font-size: 12.5px;
  cursor: pointer;
}
.skill-edit:hover { background: var(--bg-elev-3); }

/* ---------------- self-improvement section ---------------- */

.settings-hint {
  margin: 0 0 14px;
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--text-dim);
}

/* Master + per-pass toggles share this row layout: checkbox + label/hint stack. */
.settings-toggle {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 7px 0;
  cursor: pointer;
}
.settings-toggle input[type="checkbox"] {
  flex: 0 0 auto;
  width: 16px;
  height: 16px;
  margin: 2px 0 0;
  accent-color: var(--accent);
  cursor: pointer;
}
.settings-toggle input[type="checkbox"]:disabled { cursor: default; }
.settings-toggle-body { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.settings-toggle-label { font-size: 14px; color: var(--text); }
.settings-toggle-hint { font-size: 12px; color: var(--text-faint); }

/* Per-pass toggles are indented under the master switch and dim when it's off. */
.settings-subtoggles {
  display: flex;
  flex-direction: column;
  margin-left: 26px;
  padding-left: 12px;
  border-left: 1px solid var(--border);
}
.settings-subtoggles.disabled {
  opacity: 0.45;
  pointer-events: none;
}

.improve-list {
  list-style: none;
  margin: 8px 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.improve-empty { color: var(--text-faint); font-size: 13px; font-style: italic; }

.improve-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 9px 11px;
  background: var(--bg-elev-1);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
}
.improve-item.reverted { opacity: 0.55; }
.improve-item.reverted .improve-summary { text-decoration: line-through; }

.improve-meta { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.improve-summary {
  font-size: 13.5px;
  color: var(--text);
  overflow: hidden;
  text-overflow: ellipsis;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}
.improve-sub {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
}
.improve-time {
  font-size: 11.5px;
  color: var(--text-faint);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.improve-tags { display: inline-flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.improve-phase {
  font-size: 10.5px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.4px;
  padding: 1px 7px;
  border-radius: 999px;
  border: 1px solid var(--border);
  color: var(--text-dim);
  background: var(--bg-elev-2);
}
/* Phase tags are mono tonal chips — distinguished by their text label, not color
   (reflect/dreaming/curator inherit the base; manual reads quieter). */
.improve-phase.phase-manual { color: var(--text-faint); }
.improve-kinds {
  font-size: 11.5px;
  color: var(--text-faint);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.improve-revert {
  flex: 0 0 auto;
  background: transparent;
  color: var(--danger-text);
  border: 1px solid var(--danger-border);
  border-radius: 999px;
  padding: 5px 13px;
  font: inherit;
  font-size: 12.5px;
  cursor: pointer;
  transition: background 0.15s;
}
.improve-revert:hover { background: var(--danger-bg); }
.improve-revert:disabled { opacity: 0.5; cursor: default; }

/* Pending-approval card (Material/Gemini): content stacked, then one aligned action
   footer — a neutral outline Reject (dismissive, left) and a filled primary Approve
   (affirmative, right), both equal-height pill icon+label buttons. Replaces the old
   mismatched plain-text Approve + red outline Reject. */
.approval-card {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 11px;
  padding: 13px 14px;
  background: var(--bg-elev-1);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
}
.approval-actions { display: flex; justify-content: flex-end; gap: 8px; }
.approval-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 5px;
  height: 34px; padding: 0 15px; border-radius: 999px;
  border: 1px solid transparent;
  font: inherit; font-size: 13px; font-weight: 600; line-height: 1; cursor: pointer;
  transition: background 0.15s var(--ease), filter 0.15s var(--ease), color 0.15s var(--ease), transform 0.1s var(--ease);
}
.approval-btn .material-symbols-rounded { font-size: 17px; }
.approval-btn:disabled { opacity: 0.5; cursor: default; }
.approval-btn--reject { background: transparent; color: var(--text-dim); border-color: var(--border); }
.approval-btn--reject:not(:disabled):hover { background: var(--bg-elev-2); color: var(--text); }
.approval-btn--approve { background: var(--accent); color: var(--on-accent); }
.approval-btn--approve:not(:disabled):hover { filter: brightness(1.06); }
.approval-btn:not(:disabled):active { transform: scale(0.97); }

.improve-reverted-tag {
  flex: 0 0 auto;
  font-size: 11px;
  font-style: italic;
  color: var(--text-faint);
}

/* ---------------- shared toast (toast.ui.ts) ---------------- */
/* Above sheets/modals/confirm dialogs so an action taken inside an overlay (e.g. the
   admin Details sheet) still surfaces its confirmation. Mirrors .sched-toast. */
.genie-toast {
  /* Centered via inset-0 + auto margins, NOT left:50%: a fixed box at left:50%
     shrink-to-fits into the space right of center (HALF the viewport), so long
     messages wrapped into a skinny multi-line blob on phones. fit-content sizes
     to the text; max-width caps it; the 16px insets are the phone edge gutter. */
  position: fixed; left: 16px; right: 16px; bottom: calc(28px + env(safe-area-inset-bottom, 0px));
  margin: 0 auto; width: fit-content; max-width: 560px;
  transform: translateY(6px);
  display: inline-flex; align-items: center; gap: 10px;
  padding: 12px 20px; border-radius: 999px;
  background: var(--bg-elev-3); color: var(--text);
  font-size: 13.5px; line-height: 1.35;
  opacity: 0; pointer-events: none; z-index: 20000;
  box-shadow: 0 6px 24px rgba(0, 0, 0, 0.32);
  transition: opacity var(--ease) 160ms, transform var(--ease) 160ms;
}
.genie-toast.is-shown { opacity: 1; transform: translateY(0); }
.genie-toast.is-error { background: var(--danger-bg); color: var(--danger); }
.genie-toast-icon { font-size: 18px; color: var(--ok); }
.genie-toast.is-error .genie-toast-icon { color: var(--danger); }

/* ---------------- toast ---------------- */

/* (legacy .toast removed — main.ts now uses the shared .genie-toast snackbar) */

/* ---------------- slide-up options modal (ui_request) ---------------- */

.modal-overlay {
  position: fixed;
  inset: 0;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  padding: 0;
  background: rgba(0, 0, 0, 0);
  z-index: 300;
  transition: background 0.25s ease;
}
.modal-overlay.show {
  background: rgba(0, 0, 0, 0.5);
  backdrop-filter: blur(2px);
}

.modal-sheet {
  width: 100%;
  max-width: 860px;
  max-height: 80dvh;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 18px 20px calc(20px + env(safe-area-inset-bottom, 0px));
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-bottom: none;
  border-radius: var(--radius) var(--radius) 0 0;
  box-shadow: var(--shadow-lg);
  transform: translateY(100%);
  transition: transform 0.28s cubic-bezier(0.22, 1, 0.36, 1);
}
.modal-overlay.show .modal-sheet { transform: translateY(0); }

.modal-question {
  font-size: 15px;
  color: var(--text);
}
.modal-question p:first-child { margin-top: 0; }

.modal-options {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.modal-option {
  display: flex;
  align-items: center;
  gap: 11px;
  width: 100%;
  text-align: left;
  background: var(--bg-elev-1);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 12px 14px;
  font: inherit;
  font-size: 14.5px;
  cursor: pointer;
  transition: background 0.12s, border-color 0.12s;
}
.modal-option:hover,
.modal-option.selected {
  background: var(--bg-elev-2);
  border-color: var(--accent);
}
.modal-option:focus-visible { outline: none; border-color: var(--accent); }
.modal-option-num {
  flex: 0 0 auto;
  width: 22px;
  height: 22px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: var(--bg-elev-2);
  border: 1px solid var(--border);
  color: var(--text-dim);
  font-size: 12px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}
.modal-option.selected .modal-option-num {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--on-accent);
}
.modal-option-num:empty { display: none; }
.modal-option-text { flex: 1 1 auto; min-width: 0; }

.modal-input {
  width: 100%;
  resize: none;
  max-height: 160px;
  background: var(--bg-elev-1);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 11px 13px;
  font: inherit;
  font-size: 14.5px;
  line-height: 1.45;
  outline: none;
}
.modal-input:focus { border-color: var(--accent); }
.modal-input::placeholder { color: var(--text-faint); }

.modal-actions {
  display: flex;
  justify-content: flex-end;
  gap: 10px;
}
.modal-btn {
  background: var(--bg-elev-2);
  color: var(--text);
  border: none;
  border-radius: 999px;
  padding: 10px 20px;
  font: inherit;
  font-size: 13.5px;
  font-weight: 550;
  cursor: pointer;
  transition: background 0.15s var(--ease);
}
.modal-btn:hover { background: var(--bg-elev-3); }
.modal-btn.primary {
  background: var(--grad);
  color: var(--on-accent);
  border: none;
  font-weight: 650;
}
.modal-btn.primary:hover { filter: brightness(1.08); }

@media (prefers-reduced-motion: reduce) {
  .modal-sheet { transition: none; }
  .modal-overlay { transition: none; }
}

/* ---------------- responsive ---------------- */

@media (max-width: 860px) {
  .model-indicator { max-width: 38vw; }
}

@media (max-width: 520px) {
  /* --- Phone home: the WHOLE column scrolls as one (mascot → bubble → earnings
     scroll away as you browse), and only the Recent row pins — right beneath the
     floating hamburger — so task browsing stays anchored (Gemini's mobile home).

     Shared gutter so the earnings card and the task list are the same width and
     centered, and their content aligns on a single left edge (gutter + 16px). --- */

  /* The single scroll container is .home-center now (not just the list), so the
     hero scrolls with everything else. .tasks-view is just the clipping frame;
     the fixed composer + top scrim escape it via position:fixed. The gutter var
     is scoped here so every descendant (card, Recent bar, list) shares it. */
  .tasks-view { overflow: hidden; }
  .home-center {
    --home-gutter: 16px;
    padding: 0;
    overflow-y: auto;
    /* Never scroll sideways — the assist-chip row scrolls within its own box, so
       the page itself must not pick up a stray horizontal scroll. */
    overflow-x: hidden;
    overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch;
  }
  /* Opaque top strip: as the hero and task rows scroll up they dissolve behind
     the floating hamburger, above the pinned Recent bar. Sits under the hamburger
     (z 40) but over the scrolling content. */
  .home-center::before {
    content: "";
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    height: calc(env(safe-area-inset-top) + 52px);
    background: var(--bg);
    z-index: 20;
    pointer-events: none;
  }

  /* The hero is now just the top of the scroll — no min-height, no pin. Mascot
     rides high; its transparent canvas headroom tucks under the top scrim. */
  .home-header { min-height: 0; padding-top: calc(env(safe-area-inset-top) + 4.5vh); z-index: 2; }

  /* Hamburger floats top-left over the scrim. */
  .nav-fab { top: calc(env(safe-area-inset-top) + 4px); }

  /* Even vertical rhythm below the ball: bubble → earnings → Recent step 24 / 24,
     and the ball-to-bubble gap is tightened to ~16 by pulling the bubble up
     through more of the canvas' below-ball headroom. No slack band, so a third
     task row clears the fold. */
  .home-mascot-canvas { width: clamp(150px, 37vh, 330px); height: clamp(150px, 37vh, 330px); }
  .home-mascot-slot { margin: 0 0 clamp(-78px, -6.5vh, -26px); }
  .home-greeting {
    margin: 0 auto 24px;
    padding: 11px 18px;
    font-size: 15.5px;
    line-height: 1.35;
  }

  /* Earnings card and task list share the gutter → same width, centered. */
  .home-earn-slot { width: auto; margin: 0 var(--home-gutter) 24px; }
  .home-earn { padding: 14px 16px; }

  /* Recent row: pinned beneath the top scrim as the hero scrolls away. Solid fill
     with a short fade below so task rows dissolve as they pass under it. Its label
     lines up with the task titles (gutter + 16); its search icon with the kebabs. */
  .recent-bar {
    position: sticky;
    top: calc(env(safe-area-inset-top) + 52px);
    z-index: 15;
    margin: 0;
    padding: 6px var(--home-gutter) 8px calc(var(--home-gutter) + 16px);
    background: var(--bg);
  }
  .recent-bar::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    top: 100%;
    height: 14px;
    background: linear-gradient(to bottom, var(--bg), transparent);
    pointer-events: none;
  }
  /* ≥44px hit area for the sort dropdown. */
  .recent-sort { min-height: 44px; }

  /* The list flows in the shared scroll (no inner scroll of its own) and clears
     the docked composer at the bottom (composer + assist chips + safe area). */
  .tasks-list {
    flex: 0 0 auto;
    overflow: visible;
    padding: 0 var(--home-gutter);
    padding-bottom: calc(150px + env(safe-area-inset-bottom));
    gap: 4px;
  }
  /* Title aligns with the earnings label (gutter + 16); kebab hugs the right. */
  .task-row { padding: 16px 6px 16px 16px; }
  .task-title { font-size: 16px; }
  .task-subtitle { font-size: 13.5px; }
  /* Always-visible on touch (see the hover:none rule); ≥44px for the kebab. */
  .task-time { font-size: 12.5px; }
  .task-kebab { width: 44px; height: 44px; font-size: 20px; }

  /* Docked composer, thumb-zone: anchored to the viewport bottom with a scrim so
     list rows dissolve beneath it. The assist-chip row rides just above the pill. */
  .home-composer-wrap {
    position: fixed;
    left: 12px;
    right: 12px;
    bottom: 0;
    width: auto;
    margin: 0;
    padding: 10px 0 calc(10px + env(safe-area-inset-bottom));
    background: linear-gradient(to top, var(--bg) 72%, transparent);
  }
  .home-composer { padding: 18px 18px 18px 22px; border-radius: var(--radius-hero); gap: 14px; }
  .home-composer-plus { font-size: 26px; }
  .home-input { font-size: 16.5px; line-height: 1.55; }

  /* Search + drawer/menu rows: ≥44–48px hit areas. */
  .recent-search-wrap { height: 44px; }
  .recent-search-wrap.is-collapsed,
  .recent-search-wrap.is-collapsed .recent-search-ic { width: 44px; height: 44px; }
  .nav-drawer-item { min-height: 52px; }
  .nav-menu-item { min-height: 44px; }

  .brand-name { display: none; }
  /* Tighter side margins on a phone so the chat + composer use the full width
     (matches the home composer's 12px inset). */
  .transcript { gap: 14px; padding-left: 12px; padding-right: 12px; }
  .composer-wrap { padding-left: 12px; padding-right: 12px; }
  .msg { gap: 9px; }
  .msg-avatar { width: 36px; height: 36px; font-size: 17.5px; }
  .surface-card { margin-left: 45px; }
  .cmd-palette { left: 8px; right: 8px; max-height: 50dvh; }
  .cmd-desc { font-size: 12px; }
}

/* ------------------------------------------------------------------ */
/* Auth overlay (login / invite gate)                                  */
/* ------------------------------------------------------------------ */

.auth-overlay {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  background: radial-gradient(1200px 600px at 50% -10%, var(--bg-elev) 0%, var(--bg) 60%);
}

.auth-card {
  position: relative;
  width: 100%;
  max-width: 380px;
  background: var(--bg-elev);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 28px 26px 24px;
  box-shadow: var(--shadow-lg);
}
.auth-close {
  position: absolute;
  top: 12px;
  right: 12px;
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  border: none;
  border-radius: 50%;
  background: transparent;
  color: var(--text-faint);
  cursor: pointer;
  transition: background 0.15s var(--ease), color 0.15s var(--ease);
}
.auth-close:hover { background: var(--bg-elev-2); color: var(--text); }
.auth-close .material-symbols-rounded { font-size: 20px; }

.auth-brand {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 20px;
}
.auth-mark {
  font-size: 30px;
  font-variation-settings: "FILL" 1, "wght" 500, "GRAD" 0, "opsz" 24;
  /* The first impression — the one sanctioned use of the signature blue→purple→pink
     gradient on the brand mark (mirrors the profile avatar hero). */
  background: linear-gradient(135deg, var(--grad-a), var(--grad-b) 55%, var(--grad-c));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
.auth-brand-name { font-family: var(--font-display); font-size: 17px; font-weight: 600; letter-spacing: 0.2px; }

.auth-title { font-family: var(--font-display); font-size: 24px; font-weight: 600; line-height: 1.2; margin-bottom: 6px; }
.auth-sub { color: var(--text-dim); font-size: 13.5px; line-height: 1.45; margin-bottom: 18px; }

/* Loading / wallet-finalize state: indeterminate spinner + label (the wallet
   setup can take several seconds — never a static line that reads as hung). */
.auth-loading {
  display: flex; flex-direction: column; align-items: center; gap: 14px;
  padding: 14px 0 6px; color: var(--text-dim); font-size: 13.5px; text-align: center;
}
.auth-spinner {
  width: 34px; height: 34px; border-radius: 50%;
  border: 3px solid var(--bg-elev-3); border-top-color: var(--accent);
  animation: spin 0.8s linear infinite;
}
@media (prefers-reduced-motion: reduce) { .auth-spinner { animation-duration: 2.4s; } }

.auth-body { display: flex; flex-direction: column; gap: 10px; }

.auth-input {
  width: 100%;
  background: var(--bg-elev-1);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--text);
  font-size: 15px;
  min-height: 44px;
  padding: 13px;
  outline: none;
}
.auth-input:focus { border-color: var(--accent); }

.auth-btn {
  width: 100%;
  min-height: 44px;
  background: var(--grad);
  color: var(--on-accent);
  border: none;
  border-radius: 999px;
  font-size: 14.5px;
  font-weight: 600;
  padding: 13px;
  cursor: pointer;
  transition: filter 0.15s ease, opacity 0.15s ease;
}
.auth-btn:hover { filter: brightness(1.08); }
.auth-btn:disabled { opacity: 0.55; cursor: default; }
/* Secondary / ghost button (e.g. "Skip for now" in the delegation step). */
.auth-btn-ghost {
  background: transparent;
  color: var(--text-dim);
  border: 1px solid var(--border);
}
.auth-btn-ghost:hover { filter: none; opacity: 1; color: var(--text); border-color: var(--border-strong); }

/* Send success summary (wallet-send island) — our own post-send breakdown, replacing
   Privy's gas-only "Total". */
.send-summary {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin: 4px 0 14px;
  padding: 14px 16px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--bg-elev-1);
}
.send-summary-row { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; font-size: 14px; }
.send-summary-label { color: var(--text-dim); }
.send-summary-value { color: var(--text); font-weight: 600; font-variant-numeric: tabular-nums; text-align: right; }
/* The Total row sits below a divider and reads a touch larger — it's the headline number. */
.send-summary-total { margin-top: 4px; padding-top: 10px; border-top: 1px solid var(--border); font-size: 15px; }
.send-summary-total .send-summary-label { color: var(--text); font-weight: 600; }
.send-summary-link {
  display: inline-block;
  margin-bottom: 16px;
  color: var(--accent);
  font-size: 13.5px;
  text-decoration: none;
}
.send-summary-link:hover { text-decoration: underline; }

/* Info modal (profile / wallet / team) — reuses .auth-overlay / .auth-card. */
.info-card { min-width: 320px; }
.info-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
  padding: 9px 0;
  border-bottom: 1px solid var(--border);
  font-size: 13.5px;
}
.info-row-label { color: var(--text-dim); flex: 0 0 auto; }
.info-row-value {
  color: var(--text);
  text-align: right;
  word-break: break-all;
  font-family: var(--font-mono);
  font-size: 12.5px;
}
.info-card .auth-sub { margin-top: 14px; margin-bottom: 16px; }

.auth-link {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  background: none;
  border: none;
  color: var(--text-dim);
  font-size: 12.5px;
  padding: 4px;
  cursor: pointer;
  align-self: flex-start;
}
.auth-link-icon { font-size: 16px; }
.auth-link:hover { color: var(--text); }
.auth-link:disabled { opacity: 0.5; cursor: default; }
.auth-link:disabled:hover { color: var(--text-dim); }

.auth-err {
  margin-top: 14px;
  color: var(--err);
  font-size: 12.5px;
  line-height: 1.4;
}

/* Agent picker (reuses .auth-overlay / .auth-card) */
.agent-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-bottom: 16px;
}
.agent-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  background: var(--bg-elev-1);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  color: var(--text);
  padding: 13px 15px;
  cursor: pointer;
  transition: border-color 0.15s ease, background 0.15s ease;
}
.agent-row:hover {
  border-color: var(--accent);
  background: var(--bg-elev-2);
}
.agent-name { font-size: 14.5px; font-weight: 600; }
.agent-meta { font-size: 12px; color: var(--text-dim); display: inline-flex; align-items: center; gap: 8px; }

/* ── Schedules screen (standalone view, not a modal) ────────────────────────
   Lives in #schedules-view inside .layout; shown when .layout.schedules-active
   replaces the home (tasks) view. Reuses .settings-btn/.settings-input/.settings-*. */
.schedules-view {
  display: none;
  width: 100%;
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
}
.layout.schedules-active .tasks-view,
.layout.brain-active .tasks-view,
.layout.skills-active .tasks-view,
.layout.earn-active .tasks-view,
.layout.earnings-active .tasks-view,
.layout.store-active .tasks-view,
.layout.wallet-active .tasks-view,
.layout.profile-active .tasks-view,
.layout.team-active .tasks-view,
.layout.settings-active .tasks-view,
.layout.admin-active .tasks-view,
.layout.partner-active .tasks-view { display: none; }
.layout.schedules-active #schedules-view { display: block; }
.layout.brain-active #brain-view { display: block; }
.layout.skills-active #skills-view { display: block; }
.layout.earn-active #earn-view { display: block; }
/* Earn screen: on desktop it scrolls wholesale like the other screens (full
   headline + subtitle at the top). On mobile (≤720) it switches to a pinned
   header + inner scroll (see the earnings media block below). */
.layout.earnings-active #earnings-view { display: block; }
.layout.store-active #store-view { display: block; }
.layout.wallet-active #wallet-view { display: block; }
.layout.profile-active #profile-view { display: block; }
.layout.team-active #team-view { display: block; }
.layout.settings-active #settings-view { display: block; }
.layout.admin-active #admin-view { display: block; }
.layout.partner-active #partner-view { display: block; }

/* Partner screen (Agent Sales System). Reuses .sched-* / .earn-tile primitives. */
.partner-tier {
  margin: 8px 0 4px;
  padding: 18px 20px;
  border: none;
  border-radius: var(--radius);
  background: var(--bg-elev-1);
}
.partner-tier-head { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; flex-wrap: wrap; }
.partner-tier-name { font-size: 1.15rem; font-weight: 650; color: var(--text); }
.partner-tier-rates { font-size: 0.85rem; color: var(--text-dim); }
.partner-tier-next { margin-top: 8px; font-size: 0.85rem; color: var(--text-faint); }
.partner-list { display: flex; flex-direction: column; gap: 2px; }
.partner-section-label { margin: 16px 0 6px; font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.04em; color: var(--text-faint); }
.partner-row {
  display: flex; align-items: center; gap: 12px;
  padding: 11px 14px; border-radius: var(--radius-sm);
  transition: background 0.12s var(--ease);
}
.partner-row:hover { background: var(--bg-elev-1); }
.partner-row-main { flex: 1 1 auto; font-weight: 500; color: var(--text); }
.partner-row-sub { color: var(--text-dim); font-size: 0.85rem; }
.partner-row-date { color: var(--text-faint); font-size: 0.8rem; min-width: 90px; text-align: right; }
.partner-amount { font-variant-numeric: tabular-nums; font-weight: 600; min-width: 110px; text-align: right; color: var(--text); }
.partner-amount.is-pos { color: var(--ok); }
.partner-amount.is-neg { color: var(--text-dim); }

/* Admin screen: categorized sidebar + content panels. */
.admin-layout {
  display: flex;
  gap: 28px;
  max-width: 1100px;
  margin: 0 auto;
  padding: 56px 24px 96px;
  align-items: flex-start;
}
.admin-nav {
  position: sticky;
  top: 56px;
  flex: 0 0 220px;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.admin-nav-item {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  padding: 10px 12px;
  border: none;
  border-radius: var(--radius-tile);
  background: transparent;
  color: var(--text-dim);
  font: inherit;
  font-size: 0.92rem;
  text-align: left;
  cursor: pointer;
  transition: background 0.12s ease, color 0.12s ease;
}
.admin-nav-item { border-radius: 999px; }
.admin-nav-item:hover { background: var(--bg-elev-1); color: var(--text); }
.admin-nav-item.is-active {
  background: color-mix(in srgb, var(--accent) 18%, transparent);
  color: var(--accent);
  font-weight: 600;
}
.admin-nav-item.is-active .admin-nav-icon { color: var(--accent); }
.admin-nav-icon { font-size: 20px; }
.admin-nav-label { flex: 1 1 auto; }
/* Unread-improvements badge on a nav tab (Self-improvement). Accent pill with a
   count; sits at the row's trailing edge on desktop, floats on the icon on mobile. */
.admin-nav-badge {
  flex: none; min-width: 18px; height: 18px; padding: 0 5px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 999px; background: var(--accent); color: var(--on-accent);
  font-size: 11px; font-weight: 700; line-height: 1;
}
/* Transparent wrapper on desktop (items stay direct flex children of the vertical
   sidebar); becomes the horizontal scroller only in the mobile bottom-bar rule. */
.admin-nav-scroll { display: contents; }
.admin-content { flex: 1 1 auto; min-width: 0; }
/* Settings/Admin panels reuse .billing-body for spacing but are NOT a modal —
   drop the modal's `max-height: 70vh; overflow-y: auto` so the panel grows with its
   content and the page (#…-view) scrolls naturally, instead of clipping the list
   with dead space below. */
.admin-body { max-height: none; overflow: visible; }
.admin-panel-head { margin-bottom: 18px; }
.admin-panel-head .sched-headline { margin: 0 0 4px; }
.admin-panel-head .sched-subtitle { margin: 0; }

@media (max-width: 720px) {
  /* The sidebar becomes a bottom-anchored tab bar (icon + name per tab). It fills
     the width when there are few items (Settings, 3) and scrolls horizontally when
     there are many (Admin, 12). Content gets bottom padding so it isn't hidden
     behind the fixed bar. */
  /* Column layout: stretch content to full width (the base align-items:flex-start
     would otherwise shrink each panel to its content width). */
  .admin-layout { flex-direction: column; padding: 0 16px 88px; align-items: stretch; }
  .admin-nav {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    top: auto;
    z-index: 50;
    flex-basis: auto;
    width: 100%;
    padding: 6px 4px;
    padding-bottom: calc(6px + env(safe-area-inset-bottom, 0px));
    /* Read as a distinct elevated bar (the old --surface-0 fallback was nearly the
       page bg, so the bar vanished and content looked hard-"cut off" against it). */
    background: var(--bg-elev);
    border-top: 1px solid var(--border);
    /* The inner .admin-nav-scroll does the horizontal scrolling; the nav itself must
       NOT clip, so its ::before fade can paint above the bar. */
    overflow: visible;
  }
  /* Fade above the bar so scrolling content dissolves into it instead of slicing flat
     at the top edge. Absolute + bottom:100% pins it directly above the fixed bar — no
     magic numbers — and the gradient ends on the bar's own color for a seamless join. */
  .admin-nav::before {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    bottom: 100%;
    height: 28px;
    background: linear-gradient(to top, var(--bg-elev), transparent);
    pointer-events: none;
  }
  /* Right-edge fade hinting more tabs to scroll to — only when the bar actually
     overflows (the JS toggles .is-scrollable via a ResizeObserver), so the 3-tab
     Settings bar doesn't get a misleading fade. Fixes "couldn't find Pricing/Grants"
     (admin tabs 7-12 were scrolled off with no affordance). */
  .admin-nav.is-scrollable::after {
    content: "";
    position: absolute;
    top: 0;
    bottom: 0;
    right: 0;
    width: 24px;
    background: linear-gradient(to right, transparent, var(--bg-elev));
    pointer-events: none;
    z-index: 1;
  }
  .admin-nav-scroll {
    display: flex;
    flex-direction: row;
    flex-wrap: nowrap;
    gap: 0;
    width: 100%;
    overflow-x: auto;
    scrollbar-width: none; /* hide the scrollbar; the bar still scrolls by touch */
  }
  .admin-nav-scroll::-webkit-scrollbar { display: none; }
  /* Gemini / Material-3 nav bar: the active indicator is a pill behind the ICON
     (not the whole tab — that read as a wide, short slab with dead space), with the
     label below. Tabs are evenly distributed at a comfortable height. */
  /* flex: 1 0 auto — grow to fill the bar when there are few tabs (Settings, 3), but
     never shrink below a comfortable min-width when there are many (Admin, 12), so the
     bar scrolls horizontally instead of cramming every tab to ~38px. */
  .admin-nav-item {
    flex: 1 0 auto;
    flex-direction: column;
    align-items: center;
    justify-content: flex-start;
    gap: 6px;
    width: auto;
    min-width: 64px;
    padding: 8px 6px 7px;
    border-radius: 0;
    background: transparent;
    text-align: center;
    font-size: 0.72rem;
    line-height: 1.15;
  }
  .admin-nav-item:hover { background: transparent; }
  .admin-nav-item.is-active { background: transparent; color: var(--text); font-weight: 400; }
  .admin-nav-icon {
    display: grid;
    place-items: center;
    width: 48px;
    height: 30px;
    border-radius: 999px;
    font-size: 21px;
    color: var(--text-dim);
    transition: background 0.15s var(--ease), color 0.15s var(--ease);
  }
  .admin-nav-item.is-active .admin-nav-icon {
    background: color-mix(in srgb, var(--accent) 22%, transparent);
    color: var(--accent);
  }
  .admin-nav-label { display: block; flex: 0 0 auto; white-space: nowrap; color: var(--text-faint); }
  .admin-nav-item.is-active .admin-nav-label { color: var(--text); font-weight: 600; }
}

/* Mobile fit for the rest of the account & settings screens (the nav above is
   handled separately). Without these, label/value rows, the admin data tables, the
   partner dashboard, and the billing grid overflow or crush at ~390px. */
@media (max-width: 720px) {
  /* Label+value rows (Profile, Team, Admin Sales, Connected agents): the label was
     flex:0 0 auto and the row never wrapped, so a long label or trailing action
     buttons pushed past the edge. Let it wrap and let the label shrink. */
  .info-row { flex-wrap: wrap; }
  .info-row-label { flex: 1 1 auto; min-width: 0; }
  .admin-row-actions, .profile-wallet-actions { margin-left: auto; }

  /* Admin data tables: give the table a real min-width so the .dt-wrap's
     overflow-x:auto actually scrolls horizontally instead of crushing 6 columns
     into ~358px. Tighten cell padding to claw back a little room. */
  .dt-table { min-width: 620px; }
  .dt-table th, .dt-table td { padding: 10px 12px; }

  /* Billing modal: stack the 2-up credit/pass purchase buttons to a single column
     so "50 USDT → 100,000"-style labels don't wrap raggedly at ~150px. */
  .billing-grid { grid-template-columns: 1fr; }

  /* Partner / Sales (and Earn) dashboard: 4 stat tiles wrap to 2×2 instead of being
     squeezed to ~76px each; ledger rows drop their fixed date/amount min-widths so
     the main column keeps room (and can wrap). */
  .earn-dash { flex-wrap: wrap; }
  .earn-tile { flex: 1 1 calc(50% - 6px); }
  .partner-row { flex-wrap: wrap; }
  .partner-row-main { min-width: 0; }
  .partner-row-date,
  .partner-amount { min-width: 0; }
}

/* Mobile nav-bar headers: across every screen the headline becomes a left-aligned
   title in a ~56px top bar sitting just to the right of the floating hamburger
   (.nav-fab, fixed top:12, 48px, z-40), vertically centered with it; the subtitle
   is hidden and content scrolls UNDER the pinned bar. The bar stays under the
   hamburger on the z-axis (z-30) so the menu stays tappable, and paints the page
   bg so scrolling content disappears cleanly. Covers .sched-intro (Profile / Team /
   Partner / Schedules / Skills / Store / XP) and .admin-panel-head (Admin / Settings).
   Earnings (.earnings-topbar) and Tasks (.home-greeting) already do this themselves. */
@media (max-width: 720px) {
  /* Center the hamburger in the 56px bar so it lines up with the title. */
  .nav-fab { top: calc(env(safe-area-inset-top) + 4px); }
  /* Kill the desktop top padding on mobile (.layout > … specificity beats the base
     `.sched-center { padding: 72px … }` defined later in the file). */
  .layout .sched-center { padding-top: 0; }

  .admin-panel-head,
  .sched-intro {
    position: sticky;
    top: 0;
    z-index: 30;
    display: flex;
    align-items: center;
    min-height: calc(56px + env(safe-area-inset-top));
    padding: env(safe-area-inset-top) 16px 0 68px; /* left pad clears the hamburger */
    background: var(--bg);
  }
  /* Break each header out of its container's side padding so the bar spans full
     width and the title lands ~60px from the viewport edge (tight to the
     hamburger), matching the Earnings/Tasks bars. */
  .sched-intro { margin: 0 -24px 8px; }       /* .sched-center has 24px side padding */
  .admin-panel-head { margin: 0 -16px 8px; }  /* .admin-layout has 16px side padding */
  .admin-panel-head .sched-headline,
  .sched-intro .sched-headline {
    margin: 0;
    font-size: 18px;
    font-weight: 600;
    letter-spacing: -0.2px;
    line-height: 1;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  .admin-panel-head .sched-subtitle,
  .sched-intro .sched-subtitle { display: none; }
}

/* Breathing room above an action button that follows a field group, so the
   Save/Grant/Create button never sits flush against the input above it. */
.admin-body .admin-save-row { margin-top: 16px; }

/* Overview stat tiles. */
.admin-stat-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(170px, 1fr));
  gap: 10px;
  margin-bottom: 24px;
}
.admin-stat {
  padding: 18px 20px;
  border: none;
  border-radius: var(--radius);
  background: var(--bg-elev-1);
  transition: background 0.12s var(--ease);
}
.admin-stat:hover { background: var(--bg-elev-2); }
.admin-stat-value { font-size: 1.7rem; font-weight: 650; letter-spacing: -0.5px; color: var(--text); font-variant-numeric: tabular-nums; }
.admin-stat-label { margin-top: 4px; font-size: 0.8rem; color: var(--text-faint); }
/* Money-safety anomaly badge: a non-zero count is a warning the owner should notice at a glance. */
.admin-stat-alert { background: color-mix(in srgb, var(--danger, #e5484d) 14%, var(--bg-elev-1)); box-shadow: inset 0 0 0 1px var(--danger, #e5484d); }
.admin-stat-alert .admin-stat-value { color: var(--danger, #e5484d); }
.admin-inline-action { margin-bottom: 14px; max-width: 280px; }

/* CRM sales dashboard: section sub-heads, tier bars, daily-GMV sparkline. */
#admin-view .admin-subhead {
  margin: 22px 0 8px;
  font-size: 0.8rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-faint);
}
.crm-tier-row { display: flex; align-items: center; gap: 12px; padding: 9px 0; }
.crm-tier-name { flex: 0 0 96px; font-size: 13.5px; color: var(--text-dim); }
.crm-tier-count { flex: 0 0 auto; min-width: 36px; text-align: right; font-weight: 600; font-variant-numeric: tabular-nums; color: var(--text); }
.crm-bar { flex: 1 1 auto; height: 8px; border-radius: 999px; background: var(--bg-elev-2); overflow: hidden; }
.crm-bar-fill { height: 100%; border-radius: 999px; background: var(--grad); min-width: 2px; transition: width 0.3s var(--ease); }
/* Daily-GMV bar chart + time-frame selector. */
.crm-chart-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.crm-range { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; }
.crm-range .buy-chip { min-width: 0; min-height: 36px; padding: 6px 12px; font-size: 12.5px; }
.crm-range-custom { margin-top: 8px; }
.crm-range-custom.is-collapsed { display: none; }
.crm-date {
  background: var(--bg-elev-1);
  color: var(--text);
  border: none;
  border-radius: 999px;
  padding: 6px 12px;
  font: inherit;
  font-size: 12.5px;
  outline: none;
  color-scheme: light dark; /* native picker adapts to the active theme */
}
.crm-date:focus { background: var(--bg-elev-2); }
.crm-date-sep { color: var(--text-faint); }
/* Inline label + control, e.g. the drill-down sheet's Agent picker — lighter-weight
   than a full admin-subhead eyebrow since it sits directly beside its control. */
.crm-field-row { display: flex; align-items: center; gap: 10px; margin-bottom: 16px; }
.crm-field-label { flex: 0 0 auto; font-size: 0.8rem; color: var(--text-faint); }
.crm-field-row .dt-filter { flex: 1 1 auto; }
.crm-chart-wrap {
  position: relative;
  margin-top: 8px;
  padding: 14px 14px 10px;
  border-radius: var(--radius);
  background: var(--bg-elev-1);
}
.crm-chart {
  position: relative;
  display: flex;
  align-items: flex-end;
  gap: 3px;
  height: 150px;
}
/* Y-axis gridlines (max down to 0), appended as the last child of .crm-chart so they sit
   ABOVE the bars — each line's value label carries its own background chip, so a tall bar
   passing behind never blots out the scale. Replaces a single top-right max figure with the
   full intermediate scale. `pointer-events: none` keeps it out of the tooltip's hit-testing
   (see chart.ui.ts's attachChartTooltip, which reads the column beneath via elementFromPoint). */
.crm-chart-grid {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  pointer-events: none;
}
.crm-chart-gridline { position: relative; border-top: 1px dashed color-mix(in srgb, var(--border-strong) 70%, transparent); }
.crm-chart-gridline-label {
  position: absolute;
  right: 0;
  top: 0;
  transform: translateY(-50%);
  background: var(--bg-elev-1);
  border-radius: 4px;
  padding: 1px 5px;
  font-size: 10px;
  color: var(--text-faint);
  font-variant-numeric: tabular-nums;
}
.crm-chart-col {
  flex: 1 1 0;
  min-width: 0;
  height: 100%;
  display: flex;
  align-items: flex-end;
  cursor: pointer;
}
.crm-chart-bar {
  width: 100%;
  border-radius: 3px 3px 0 0;
  background: var(--grad);
  min-height: 2px;
  opacity: 0.88;
  transition: opacity 0.12s var(--ease);
}
.crm-chart-col:hover .crm-chart-bar { opacity: 1; }
/* Stacked cost chart (admin-models.ui.ts): segments fill a column bottom-up. */
.crm-chart-stack { display: flex; flex-direction: column-reverse; width: 100%; height: 100%; }
.crm-chart-seg { width: 100%; min-height: 0; opacity: 0.9; }
.crm-chart-col:hover .crm-chart-seg { opacity: 1; }

/* --- Admin model routing chain + catalog picker + cost legend (admin-models.ui.ts) --- */
.mdl-chain { display: flex; flex-direction: column; gap: 8px; margin: 10px 0; }
.mdl-row { display: flex; align-items: center; gap: 10px; padding: 10px 12px; border: 1px solid var(--border); border-radius: 12px; background: var(--bg-elev-2); }
.mdl-rank { flex: 0 0 auto; width: 26px; height: 26px; display: inline-flex; align-items: center; justify-content: center; border-radius: 999px; background: var(--bg-elev-2); color: var(--text-dim); font-size: 12px; font-weight: 600; font-variant-numeric: tabular-nums; }
.mdl-main { flex: 1 1 auto; min-width: 0; }
.mdl-name { font-weight: 600; color: var(--text); overflow-wrap: anywhere; line-height: 1.3; }
.mdl-meta { font-size: 12px; color: var(--text-dim); display: flex; gap: 10px; flex-wrap: wrap; margin-top: 2px; }
.mdl-actions { flex: 0 0 auto; display: inline-flex; gap: 2px; }
.mdl-iconbtn { display: inline-flex; align-items: center; justify-content: center; width: 30px; height: 30px; border: none; background: transparent; color: var(--text-dim); border-radius: 8px; cursor: pointer; }
.mdl-iconbtn:hover:not(:disabled) { background: var(--bg-elev-3); color: var(--text); }
.mdl-iconbtn:disabled { opacity: 0.3; cursor: default; }
.mdl-iconbtn.is-danger:hover { color: var(--err); }
.mdl-iconbtn .material-symbols-rounded { font-size: 20px; }
.mdl-tag { flex: 0 0 auto; font-size: 11px; color: var(--text-faint); }
.mdl-picker { border: 1px solid var(--border); border-radius: 12px; margin-top: 8px; overflow: hidden; background: var(--bg-elev-2); }
.mdl-pick-search { width: 100%; box-sizing: border-box; border: none; border-bottom: 1px solid var(--border); background: transparent; color: var(--text); padding: 10px 12px; font: inherit; font-size: 14px; }
.mdl-pick-search:focus { outline: none; }
.mdl-pick-list { max-height: 300px; overflow: auto; }
.mdl-pick-row { display: flex; align-items: center; gap: 10px; padding: 8px 12px; cursor: pointer; border-bottom: 1px solid var(--border); }
.mdl-pick-row:last-child { border-bottom: none; }
.mdl-pick-row:hover { background: var(--bg-elev-2); }
.mdl-score { flex: 0 0 auto; min-width: 34px; text-align: center; padding: 2px 6px; border-radius: 6px; font-size: 12px; font-weight: 600; font-variant-numeric: tabular-nums; background: color-mix(in srgb, var(--ok) 18%, transparent); color: var(--ok); }
.mdl-score.is-none { background: var(--bg-elev-2); color: var(--text-faint); }
.mdl-legend { display: flex; flex-wrap: wrap; gap: 8px 14px; margin-top: 10px; font-size: 12px; }
.mdl-legend-item { display: inline-flex; align-items: center; gap: 6px; color: var(--text-dim); }
.mdl-swatch { width: 10px; height: 10px; border-radius: 2px; flex: 0 0 auto; }
.mdl-recon { display: flex; gap: 18px; flex-wrap: wrap; margin: 8px 0 2px; font-size: 13px; color: var(--text-dim); }
.mdl-recon strong { color: var(--text); font-variant-numeric: tabular-nums; }
.crm-chart-axis {
  display: flex;
  justify-content: space-between;
  margin-top: 6px;
  font-size: 11px;
  color: var(--text-faint);
  font-variant-numeric: tabular-nums;
}
/* Hover (mouse) / tap (touch) value readout — see chart.ui.ts's attachChartTooltip.
   Positioned relative to .crm-chart-wrap (its offset parent), just above the pointed-at
   column; hidden until a pointer lands on a column. */
.crm-chart-tooltip {
  position: absolute;
  z-index: 2;
  transform: translateX(-50%);
  white-space: pre-line;
  text-align: center;
  background: var(--bg-elev-2);
  color: var(--text);
  border-radius: var(--radius-sm);
  padding: 6px 10px;
  font-size: 11.5px;
  line-height: 1.4;
  font-variant-numeric: tabular-nums;
  box-shadow: var(--shadow-md);
  pointer-events: none;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.1s var(--ease);
}
.crm-chart-tooltip.is-visible { opacity: 1; visibility: visible; }

/* Sales / admin grouped lists as Gemini tonal cards (GMV overview, partners,
   payouts): a single rounded surface with hairline row dividers, no outer stroke. */
#admin-view .admin-card,
#admin-view .admin-list {
  background: var(--bg-elev-1);
  border-radius: var(--radius);
  padding: 2px 16px;
  margin-top: 10px;
}
#admin-view .admin-card .info-row,
#admin-view .admin-list .info-row { padding: 13px 0; }
#admin-view .admin-card .info-row:last-child,
#admin-view .admin-list .info-row:last-child { border-bottom: none; }
/* A muted empty-state line ("No payouts yet.") shouldn't look like a card. */
#admin-view .admin-list > .admin-note:only-child { padding: 14px 0; }

/* Partner/payout row action buttons → compact tonal pills (not full-width). */
#admin-view .admin-row-actions .billing-buy {
  width: auto;
  padding: 7px 16px;
  background: var(--bg-elev-2);
  border: none;
  font-size: 0.82rem;
}
#admin-view .admin-row-actions .billing-buy:hover:not(:disabled) { background: var(--bg-elev-3); }

/* Mascot test panel: centered WebGL preview + expression-trigger chips. */
.admin-mascot-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 18px;
  padding: 32px 16px 24px;
  background: var(--bg-elev-1);
  border-radius: var(--radius);
  margin-top: 10px;
}
.admin-mascot-stage { width: 220px; height: 220px; }
.admin-mascot-canvas { display: block; width: 100%; height: 100%; cursor: pointer; }
.admin-mascot-chips { justify-content: center; }

/* Primary CTAs in admin (Save, Enroll, Grant, Create, Run rebate) → spark gradient. */
#admin-view .billing-grid-1 > .billing-buy {
  background: var(--grad);
  color: var(--on-accent);
  border: none;
  font-weight: 600;
  padding: 13px 16px;
}
#admin-view .billing-grid-1 > .billing-buy:hover:not(:disabled) { background: var(--grad); filter: brightness(1.06); }
#admin-view .billing-grid-1 > .billing-buy:disabled { opacity: 0.5; }

/* Admin data table (search / sort / filter / paginate) — Gemini: borderless tonal
   fills, rounded pills, elevation via fill not stroke. */
.dt-toolbar { display: flex; gap: 10px; flex-wrap: wrap; align-items: center; margin-bottom: 12px; }
.dt-search { display: flex; align-items: center; gap: 8px; flex: 1 1 240px; min-width: 200px;
  padding: 9px 14px; border: none; border-radius: 999px;
  background: var(--bg-elev-1); }
.dt-search .material-symbols-rounded { font-size: 19px; color: var(--text-faint); }
.dt-search-input { flex: 1 1 auto; border: none; background: transparent; color: var(--text); font: inherit; outline: none; }
.dt-filter {
  padding: 9px 14px; border: none; border-radius: 999px;
  background: var(--bg-elev-1); color: var(--text); font: inherit; font-size: 0.9rem; cursor: pointer;
  transition: background 0.12s var(--ease);
}
.dt-filter:hover { background: var(--bg-elev-2); }
.dt-wrap { overflow-x: auto; border: none; border-radius: var(--radius); background: var(--bg-elev-1); }
.dt-table { width: 100%; border-collapse: collapse; font-size: 0.9rem; }
.dt-table th, .dt-table td { text-align: left; padding: 12px 16px; border-bottom: 1px solid var(--border); }
.dt-table tbody tr:last-child td { border-bottom: none; }
.dt-table thead th { font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.04em; color: var(--text-faint); font-weight: 600; white-space: nowrap; }
.dt-table tbody tr { transition: background 0.1s var(--ease); }
.dt-table tbody tr:hover { background: var(--bg-elev-2); }
.dt-table td.is-num, .dt-table th.is-num { text-align: right; font-variant-numeric: tabular-nums; }
/* Cap a column's width (e.g. a long email) so it doesn't crowd out the more
   important numeric columns; full value is still available via title on hover. */
.dt-col-narrow { max-width: 160px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dt-th-btn { display: inline-flex; align-items: center; gap: 4px; background: none; border: none; color: inherit; font: inherit;
  text-transform: inherit; letter-spacing: inherit; cursor: pointer; padding: 0; }
.dt-th-btn:hover { color: var(--text); }
.dt-table th.is-sorted { color: var(--text); }
.dt-sort-ind { font-size: 0.8rem; color: var(--accent); }
.dt-msg { text-align: center; padding: 28px 14px; color: var(--text-faint); }
.dt-actions-col { width: 1%; }
.dt-actions { text-align: right; white-space: nowrap; }
.dt-row-actions { display: inline-flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.dt-action {
  display: inline-flex; align-items: center; justify-content: center; min-height: 36px;
  padding: 6px 14px; border: none; border-radius: 999px;
  background: var(--bg-elev-2); color: var(--text); font: inherit; font-size: 0.82rem; cursor: pointer;
  transition: background 0.12s var(--ease);
}
.dt-action:hover:not(:disabled) { background: var(--bg-elev-3); }
.dt-action:disabled { opacity: 0.5; cursor: default; }
.dt-action-danger { color: var(--err); }
.dt-action-danger:hover:not(:disabled) { background: color-mix(in srgb, var(--err) 16%, transparent); }
.dt-link { color: var(--accent); text-decoration: none; }
.dt-link:hover { text-decoration: underline; }
.dt-mono { font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, monospace); font-size: 0.82rem; color: var(--text-dim); }
/* Copyable code token (e.g. a user's invite code): tonal pill, fill-based, accent-tint confirm. */
.dt-code {
  font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
  font-size: 0.8rem; letter-spacing: 0.02em;
  padding: 3px 10px; border: none; border-radius: 999px;
  background: var(--bg-elev-2); color: var(--text-dim); cursor: pointer;
  transition: background 0.12s var(--ease), color 0.12s var(--ease);
}
.dt-code:hover { background: var(--bg-elev-3); color: var(--text); }
.dt-code.is-copied { background: color-mix(in srgb, var(--accent) 20%, transparent); color: var(--accent); }
.dt-badges { display: inline-flex; gap: 5px; flex-wrap: wrap; }
.dt-badge { padding: 3px 10px; border-radius: 999px; font-size: 0.76rem; font-weight: 500; }
.dt-badge-good { background: color-mix(in srgb, var(--ok) 18%, transparent); color: var(--ok); }
.dt-badge-bad { background: color-mix(in srgb, var(--err) 18%, transparent); color: var(--err); }
.dt-badge-info { background: color-mix(in srgb, var(--accent) 18%, transparent); color: var(--accent); }
.dt-badge-muted { background: var(--bg-elev-3); color: var(--text-dim); }
.dt-footer { display: flex; align-items: center; justify-content: space-between; margin-top: 12px; }
.dt-summary { font-size: 0.85rem; color: var(--text-faint); font-variant-numeric: tabular-nums; }
.dt-page-btns { display: flex; gap: 6px; }
.dt-page-btn {
  display: inline-flex; align-items: center; justify-content: center; width: 38px; height: 38px;
  border: none; border-radius: 50%; background: var(--bg-elev-1);
  color: var(--text); cursor: pointer; transition: background 0.12s var(--ease);
}
.dt-page-btn:hover:not(:disabled) { background: var(--bg-elev-2); }
.dt-page-btn:disabled { opacity: 0.35; cursor: default; }
.dt-page-btn .material-symbols-rounded { font-size: 18px; }

/* Coupon create form — labeled fields, each with an inline "?" help toggle that expands a
   detailed explanation card. Gemini-style: calm tonal surfaces, generous spacing, soft
   rounded geometry, restrained accents. */
.coupon-form { gap: 16px; }
.coupon-field { display: flex; flex-direction: column; gap: 6px; }
.coupon-field-head { display: flex; align-items: center; gap: 6px; min-height: 18px; }
.coupon-field-label { margin-top: 0; font-weight: 500; letter-spacing: 0.1px; }
.coupon-info {
  display: inline-flex; align-items: center; justify-content: center;
  padding: 1px; flex: 0 0 auto;
  border: none; border-radius: 50%; background: transparent;
  color: var(--text-faint); cursor: pointer; line-height: 1;
  font-size: 16px; /* Material symbol glyph size (overrides the 20px base) */
  transition: color 0.15s ease, background 0.15s ease;
}
.coupon-info:hover { color: var(--text); background: var(--bg-elev-2); }
.coupon-info:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.coupon-info.is-active { color: var(--accent); background: var(--accent-dim); }
.coupon-help {
  display: none;
  margin-top: 2px;
  font-size: 12px; line-height: 1.55; color: var(--text-dim);
  background: var(--bg-elev-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 10px 12px;
}
.coupon-help.is-open { display: block; animation: coupon-help-in 0.16s ease; }
@keyframes coupon-help-in { from { opacity: 0; transform: translateY(-2px); } to { opacity: 1; transform: none; } }

/* Coupons: multi-select table + bulk action bar */
.coupon-table { width: 100%; border-collapse: collapse; margin-top: 10px; font-size: 0.85rem; }
.coupon-table th {
  text-align: left; padding: 7px 8px; white-space: nowrap;
  color: var(--text-faint); font-weight: 600; font-size: 0.74rem; letter-spacing: 0.02em;
  border-bottom: 1px solid var(--border);
}
.coupon-table td { padding: 9px 8px; border-bottom: 1px solid var(--border); color: var(--text); vertical-align: middle; }
.coupon-table tbody tr:last-child td { border-bottom: none; }
.coupon-table tbody tr:hover td { background: var(--bg-elev-2); }
.coupon-th-check { width: 1%; white-space: nowrap; }
.coupon-th-check input { cursor: pointer; vertical-align: middle; }
.coupon-code { font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, monospace); font-weight: 600; letter-spacing: 0.04em; }
.coupon-row-actions { width: 1%; text-align: right; }
.coupon-copy {
  display: inline-flex; align-items: center; justify-content: center;
  background: none; border: none; cursor: pointer; padding: 3px; border-radius: 6px;
  color: var(--text-dim); font-size: 18px; line-height: 1;
}
.coupon-copy:hover { color: var(--text); background: var(--bg-elev-2); }
.coupon-bulk-bar { display: flex; align-items: center; gap: 10px; margin-top: 12px; }
.coupon-bulk-count { margin-right: auto; color: var(--text-dim); font-size: 0.85rem; font-variant-numeric: tabular-nums; }
.billing-buy.is-compact { width: auto; padding: 6px 14px; font-size: 0.85rem; }
.billing-buy.is-danger { background: var(--danger); color: var(--on-accent); }
/* Re-assert the red on hover: the base .billing-buy:hover rule is more specific and
   would otherwise repaint it neutral gray exactly as the user goes to click. */
.billing-buy.is-danger:hover:not(:disabled) { background: var(--danger); filter: brightness(1.08); }

/* Admin sales section helpers. */
.admin-list { display: flex; flex-direction: column; gap: 2px; margin-top: 8px; }
.admin-row-actions { display: flex; gap: 6px; margin-left: 12px; }
.admin-note { color: var(--text-faint); font-size: 0.85rem; padding: 8px 2px; }
.admin-warn {
  padding: 12px 14px; margin-bottom: 10px; border-radius: var(--radius-sm);
  background: color-mix(in srgb, var(--warn) 16%, transparent); border: none;
  color: var(--text); font-size: 0.85rem;
}

.sched-center {
  max-width: 760px;
  margin: 0 auto;
  padding: 72px 24px 96px;
}

/* Intro */
.sched-headline {
  font-family: "Google Sans Flex", "Google Sans Text", Roboto, system-ui, sans-serif;
  font-size: 32px;
  font-weight: 400;
  letter-spacing: -0.2px;
  margin: 0 0 10px;
}
.sched-subtitle {
  font-size: 14.5px;
  color: var(--text-dim);
  line-height: 1.55;
  margin: 0;
  max-width: 620px;
}

/* Create actions */
.sched-cta-row { display: flex; flex-wrap: wrap; gap: 12px; margin: 26px 0 8px; }
.sched-cta {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 10px 18px; border-radius: 999px;
  border: none; background: var(--bg-elev-2);
  color: var(--text); font: inherit; font-size: 14px; font-weight: 500; cursor: pointer;
  transition: background var(--ease) 150ms, filter var(--ease) 150ms;
}
.sched-cta:hover { background: var(--bg-elev-3); }
.sched-cta .material-symbols-rounded { font-size: 20px; }
.sched-cta-primary { background: var(--grad); color: var(--on-accent); font-weight: 600; }
.sched-cta-primary:hover { filter: brightness(1.08); background: var(--grad); }

/* Empty state */
.sched-empty { padding: 48px 8px; text-align: center; color: var(--text-dim); }
.sched-empty p { margin: 4px 0; }
.sched-empty-sub { font-size: 13px; color: var(--text-faint); }

/* Grouped list of cards */
.sched-group-label {
  font-size: 13px; font-weight: 600; color: var(--text);
  margin: 30px 0 12px;
}
.sched-cards { display: flex; flex-direction: column; gap: 12px; }
.sched-card {
  position: relative;
  background: var(--bg-elev-1);
  border-radius: var(--radius);
  padding: 18px 20px;
  cursor: pointer;
  transition: background var(--ease) 150ms;
}
.sched-card:hover { background: var(--bg-elev-2); }
.sched-card:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* Keep the title/meta clear of the absolutely-positioned kebab. */
.sched-card-info { padding-right: 40px; }
.sched-card-title { font-size: 15px; font-weight: 500; color: var(--text); }
.sched-card-when { font-size: 13.5px; color: var(--text-dim); margin-top: 4px; }
.sched-card-last { font-size: 13px; color: var(--text-faint); margin-top: 2px; }
.sched-card-last.is-err { color: var(--danger); }

/* Overflow ("⋯") button + popover menu — Run / Edit / Pause / Delete (Gemini style) */
.sched-kebab {
  position: absolute; top: 14px; right: 14px;
  display: inline-flex; align-items: center; justify-content: center;
  width: 40px; height: 40px; border-radius: 999px;
  background: transparent; border: none; color: var(--text-dim); cursor: pointer;
  transition: background var(--ease) 120ms, color var(--ease) 120ms;
}
.sched-kebab:hover { background: var(--bg-elev-3); color: var(--text); }
.sched-kebab:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.sched-kebab .material-symbols-rounded { font-size: 20px; }

.sched-menu {
  position: fixed; z-index: 1200; min-width: 188px;
  background: var(--bg-elev-2); border: 1px solid var(--border);
  border-radius: var(--radius-sm); padding: 6px; box-shadow: var(--shadow-lg);
  display: flex; flex-direction: column;
}
.sched-menu-item {
  display: flex; align-items: center; gap: 12px;
  background: transparent; border: none; color: var(--text);
  font-size: 14px; text-align: left; padding: 9px 12px; border-radius: var(--radius-tile); cursor: pointer;
  transition: background var(--ease) 120ms;
}
.sched-menu-item:hover { background: var(--bg-elev-3); }
.sched-menu-item .material-symbols-rounded { font-size: 20px; color: var(--text-dim); }
.sched-menu-item.is-danger { color: var(--danger); }
.sched-menu-item.is-danger .material-symbols-rounded { color: var(--danger); }
.sched-menu-sep { height: 1px; background: var(--border); margin: 6px 6px; }

/* Create / edit form */
.sched-form { display: flex; flex-direction: column; gap: 12px; margin-top: 18px; }
.sched-form-head { font-size: 16px; font-weight: 600; margin-bottom: 4px; }
.sched-field { display: flex; flex-direction: column; gap: 5px; }
.sched-field[hidden] { display: none; }
.sched-objective { min-height: 78px; font-family: inherit; font-size: 14px; }
/* Tonal select — drop native OS chrome, draw a Gemini chevron instead. */
.sched-select {
  appearance: none; -webkit-appearance: none;
  padding-right: 38px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 24 24' fill='none' stroke='%239aa0a6' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 12px center;
  background-size: 18px;
}
.sched-select::-ms-expand { display: none; }

/* Toast for run-now / errors — fixed to the viewport since there's no modal panel.
   z-index above EVERYTHING, including the confetti canvas (10000) and welcome-overlay
   (9999) — verified live that a gacha-win toast's ~3.2s window overlaps the confetti
   burst's ~5s window for most realistic dismiss timings, and confetti (being decorative,
   full-screen, z-index 10000) was rendering ON TOP of the toast for that whole overlap.
   bottom offset adds env(safe-area-inset-bottom) — every OTHER bottom-pinned element in
   this app (composer, home header, nav) already accounts for it; this one didn't, so on a
   real phone with the browser's bottom toolbar/home-indicator showing, the toast could be
   rendering fine (confirmed via headless testing at every viewport) while sitting fully
   behind that OS chrome — invisible despite being "there." */
.sched-toast {
  position: fixed; left: 50%; bottom: calc(28px + env(safe-area-inset-bottom, 0px)); transform: translate(-50%, 6px);
  display: inline-flex; align-items: center; gap: 8px;
  padding: 10px 16px; border-radius: 999px;
  background: var(--bg-elev-3); color: var(--text);
  font-size: 13px; opacity: 0; pointer-events: none; z-index: 20000;
  box-shadow: 0 6px 24px rgba(0, 0, 0, 0.32);
  transition: opacity var(--ease) 160ms, transform var(--ease) 160ms;
}
.sched-toast.is-shown { opacity: 1; transform: translate(-50%, 0); }
.sched-toast.is-error { background: var(--danger-bg); color: var(--danger); }
/* Optional leading icon (see flash()'s iconName param) — same size/role as the top banner's
   info/warn/error glyph. */
.sched-toast .material-symbols-rounded { font-size: 16px; flex: none; color: var(--text-dim); }
.sched-toast.is-error .material-symbols-rounded { color: var(--danger); }

/* ── Skills screen (standalone view; Marketplace | Installed) ────────────────
   Reuses .sched-center/.sched-intro/.sched-headline/.sched-subtitle/.sched-empty/
   .sched-toast and the .sched-menu popover. Gemini-style: pill controls, tonal
   surfaces, an expandable search mirroring the recent-tasks search. */

/* Controls row: sort chip on the left, expandable search pinned right. */
.skills-controls { display: flex; align-items: center; gap: 10px; min-height: 40px; margin-bottom: 16px; }
.skills-sort-chip {
  display: inline-flex; align-items: center; gap: 6px;
  background: var(--bg-elev-1); border: none; cursor: pointer;
  color: var(--text); font-size: 13.5px; font-weight: 500;
  height: 40px; padding: 0 8px 0 16px; border-radius: 999px;
  transition: background var(--ease) 120ms;
}
.skills-sort-chip:hover { background: var(--bg-elev-2); }
.skills-chip-label { color: var(--text-faint); font-weight: 400; }
.skills-chip-arrow { color: var(--text-dim); font-size: 13px; }
.skills-sort-chip .material-symbols-rounded { font-size: 20px; color: var(--text-dim); margin-left: -2px; }

.skills-sort-menu { min-width: 210px; }
.skills-menu-check { width: 20px; display: inline-flex; justify-content: center; flex: none; }
.skills-menu-check .material-symbols-rounded { font-size: 18px; color: var(--accent); }
.skills-sort-menu .sched-menu-item { gap: 8px; }

/* Expandable search — same behavior as the recent-tasks search. */
.skills-search-wrap {
  display: flex; align-items: center; gap: 6px; flex: 0 0 auto;
  width: 260px; max-width: 60%; height: 40px; margin-left: auto; padding: 0 14px;
  overflow: hidden; background: var(--bg-elev-1); border: none; border-radius: 999px;
  transition: width 0.22s var(--ease), padding 0.22s var(--ease), background 0.15s var(--ease);
}
.skills-search-wrap:focus-within { background: var(--bg-elev-2); }
.skills-search-ic {
  flex: 0 0 auto; display: grid; place-items: center;
  background: transparent; border: none; padding: 0; color: var(--text-faint); cursor: pointer;
}
.skills-search-ic .material-symbols-rounded { font-size: 19px; }
.skills-search {
  flex: 1 1 auto; min-width: 0; background: transparent; border: none; outline: none;
  color: var(--text); font: inherit; font-size: 13.5px;
}
.skills-search::placeholder { color: var(--text-faint); }
.skills-search-wrap.is-collapsed { width: 40px; padding: 0; gap: 0; background: transparent; }
.skills-search-wrap.is-collapsed .skills-search-ic {
  width: 40px; height: 40px; border-radius: 50%; color: var(--text-dim);
  transition: background 0.15s var(--ease), color 0.15s var(--ease);
}
.skills-search-wrap.is-collapsed .skills-search-ic .material-symbols-rounded { font-size: 22px; }
.skills-search-wrap.is-collapsed .skills-search-ic:hover { background: var(--bg-elev-2); color: var(--text); }
.skills-search-wrap.is-collapsed .skills-search { width: 0; flex: 0 0 0; opacity: 0; pointer-events: none; }

/* Cards */
.skills-cards { display: flex; flex-direction: column; gap: 10px; }
.skills-card {
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  background: var(--bg-elev-1); border-radius: var(--radius-lg); padding: 16px 20px; cursor: pointer;
  transition: background var(--ease) 150ms;
}
.skills-card:hover { background: var(--bg-elev-2); }
.skills-card:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.skills-card-info { min-width: 0; flex: 1; }
.skills-card-title { font-size: 15px; font-weight: 600; color: var(--text); }
.skills-card-desc {
  font-size: 13px; color: var(--text-dim); margin-top: 4px; line-height: 1.45;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.skills-stats { display: flex; flex-wrap: wrap; gap: 14px; margin-top: 9px; font-size: 12px; color: var(--text-faint); }
.skills-stats > span { position: relative; }
.skills-stats > span + span::before {
  content: "·"; position: absolute; left: -8px; color: var(--text-faint);
}
.skills-rate { display: inline-flex; align-items: center; gap: 3px; }
.skills-rate .material-symbols-rounded { font-size: 14px; }

.skills-action {
  flex: none; align-self: center; white-space: nowrap;
  display: inline-flex; align-items: center; justify-content: center; min-height: 44px;
  background: var(--accent); color: var(--on-accent); border: none;
  border-radius: 999px; padding: 9px 20px; font-size: 13px; font-weight: 600; cursor: pointer;
  transition: filter var(--ease) 120ms, background var(--ease) 120ms, color var(--ease) 120ms;
}
.skills-action:hover { filter: brightness(1.08); }
.skills-action:disabled { cursor: default; }
.skills-action.is-installed {
  background: transparent; color: var(--text-faint);
  box-shadow: inset 0 0 0 1px var(--border); filter: none;
}
.skills-action.is-danger {
  background: transparent; color: var(--text-dim); box-shadow: inset 0 0 0 1px var(--border); filter: none;
}
.skills-action.is-danger:hover { color: var(--danger); box-shadow: inset 0 0 0 1px var(--danger); background: var(--danger-bg); }

/* Skill detail modal — a centered popup. Reuses the .settings-overlay backdrop,
   but centers with flexbox (grid place-items can mis-place a single auto-sized
   child). A column layout caps the height and lets the description scroll while
   the header, KPIs, and action stay pinned. */
.skills-modal-overlay { display: flex; align-items: center; justify-content: center; }
.skills-sheet {
  display: flex;
  flex-direction: column;
  width: min(460px, 100%);
  max-height: 86dvh;
  background: var(--bg-elev);
  border-radius: var(--radius-lg);
  padding: 24px;
  box-shadow: var(--shadow-lg);
  transform: scale(0.96);
  opacity: 0;
  transition: transform 0.18s var(--ease), opacity 0.18s var(--ease);
}
.skills-sheet.is-open { transform: scale(1); opacity: 1; }
.skills-sheet-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; }
.skills-sheet-title { margin: 0; font-size: 20px; font-weight: 600; line-height: 1.25; }
.skills-sheet-sub { font-size: 13px; color: var(--text-dim); margin-top: 6px; flex: none; }
.skills-kpis { display: flex; gap: 10px; margin: 20px 0; flex: none; }
.skills-kpis[hidden] { display: none; }
.skills-kpi { flex: 1; background: var(--bg-elev-1); border-radius: var(--radius); padding: 14px 10px; text-align: center; }
.skills-kpi-value { font-size: 18px; font-weight: 600; color: var(--text); }
.skills-kpi-label { font-size: 11px; color: var(--text-faint); text-transform: uppercase; letter-spacing: 0.5px; margin-top: 5px; }
/* The description takes the remaining height and scrolls when long. */
.skills-sheet-desc {
  flex: 1 1 auto; min-height: 64px; overflow-y: auto;
  font-size: 14px; color: var(--text); line-height: 1.6; margin: 4px 0 20px;
  padding-right: 4px;
}
.skills-sheet-actions { display: flex; flex: none; }
.skills-sheet-action { width: 100%; text-align: center; padding: 12px; font-size: 14px; }

/* ── Earn screen (standalone view) ──────────────────────────────────────────
   Reuses .sched-center/.sched-intro/.sched-headline/.sched-subtitle/.sched-region/
   .sched-empty/.sched-toast and the .tabs-primary underline tabs. */
.earn-jackpot {
  margin: 18px 0 14px;
  padding: 22px 24px;
  border-radius: var(--radius-lg);
  background: linear-gradient(135deg, color-mix(in srgb, var(--accent) 26%, var(--bg-elev-1)), var(--bg-elev-1));
  border: 1px solid color-mix(in srgb, var(--accent) 24%, transparent);
}
.earn-jackpot-head { display: flex; align-items: center; justify-content: space-between; }
.earn-jackpot-label { font-size: 12.5px; font-weight: 600; letter-spacing: 0.6px; text-transform: uppercase; color: var(--text-dim); }
.earn-jackpot-edit { background: transparent; border: none; color: var(--text-dim); cursor: pointer; padding: 4px; border-radius: 999px; }
.earn-jackpot-edit:hover { color: var(--text); background: var(--bg-elev-2); }
.earn-jackpot-edit .material-symbols-rounded { font-size: 18px; }
.earn-jackpot-value { display: flex; align-items: baseline; gap: 8px; margin-top: 6px; }
.earn-jackpot-xp { font-size: 40px; font-weight: 700; line-height: 1; color: var(--text); }
.earn-jackpot-unit { font-size: 16px; font-weight: 600; color: var(--accent); }
.earn-jackpot-editor { display: flex; flex-direction: column; gap: 6px; }

.earn-dash { display: flex; gap: 12px; margin-bottom: 6px; }
.earn-tile { flex: 1; background: var(--bg-elev-1); border-radius: var(--radius); padding: 16px; text-align: center; }
.earn-tile-value { font-size: 22px; font-weight: 700; color: var(--text); }
.earn-tile-label { font-size: 12px; color: var(--text-faint); margin-top: 4px; }

.earn-bounties { display: flex; flex-direction: column; gap: 12px; }
.earn-new { align-self: flex-start; }
.earn-bounty-list { display: flex; flex-direction: column; gap: 10px; }
.earn-bounty {
  display: flex; align-items: center; gap: 14px;
  background: var(--bg-elev-1); border-radius: var(--radius); padding: 14px 16px;
}
.earn-bounty-icon {
  flex: none; width: 46px; height: 46px; border-radius: var(--radius-sm); overflow: hidden;
  display: grid; place-items: center; background: var(--bg-elev-2); color: var(--accent);
}
.earn-bounty-icon img { width: 100%; height: 100%; object-fit: cover; }
.earn-bounty-icon .material-symbols-rounded { font-size: 26px; }
.earn-bounty-meta { min-width: 0; flex: 1; }
.earn-bounty-titlerow { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.earn-bounty-name { font-size: 15px; font-weight: 600; color: var(--text); }
.earn-bounty-reward {
  font-size: 11.5px; font-weight: 700; color: var(--accent);
  background: color-mix(in srgb, var(--accent) 16%, transparent); padding: 2px 8px; border-radius: 999px;
}
.earn-bounty-desc {
  font-size: 13px; color: var(--text-dim); margin-top: 3px; line-height: 1.45;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.earn-bounty-sub { font-size: 12px; color: var(--text-faint); margin-top: 4px; }
.earn-bounty-actions { flex: none; display: flex; align-items: center; gap: 6px; }
.earn-icon-btn {
  width: 40px; height: 40px; border-radius: 999px; flex: none; cursor: pointer;
  background: transparent; border: none; color: var(--text-dim);
  display: inline-grid; place-items: center; transition: background var(--ease) 120ms, color var(--ease) 120ms;
}
.earn-icon-btn:hover { background: var(--bg-elev-2); color: var(--text); }
.earn-icon-btn .material-symbols-rounded { font-size: 19px; }
.earn-icon-btn.is-danger:hover { color: var(--danger); background: var(--danger-bg); }
.skills-action.is-ghost { background: transparent; color: var(--text-faint); box-shadow: inset 0 0 0 1px var(--border); filter: none; }

.earn-ranks { display: flex; flex-direction: column; gap: 22px; }
.earn-rank-title { font-size: 13px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px; color: var(--text-dim); margin-bottom: 8px; }
.earn-rank-list { display: flex; flex-direction: column; gap: 4px; }
.earn-rank-row {
  display: flex; align-items: center; gap: 14px;
  padding: 11px 14px; border-radius: var(--radius-sm); background: var(--bg-elev-1);
}
.earn-rank-row.is-me { background: color-mix(in srgb, var(--accent) 14%, var(--bg-elev-1)); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent) 30%, transparent); }
.earn-rank-pos { font-size: 13px; font-weight: 700; color: var(--text-dim); width: 40px; flex: none; }
.earn-rank-name { flex: 1; min-width: 0; font-size: 14px; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.earn-rank-xp { font-size: 13px; font-weight: 600; color: var(--text-dim); flex: none; }

/* Congrats notif — slides up from the bottom when a reward lands. */
.earn-congrats {
  position: fixed; left: 50%; bottom: 24px; transform: translate(-50%, 140%);
  z-index: 1300; display: flex; align-items: center; gap: 14px;
  background: var(--bg-elev-2); border: 1px solid color-mix(in srgb, var(--accent) 30%, var(--border));
  border-radius: var(--radius-lg); padding: 14px 18px; box-shadow: var(--shadow-lg);
  max-width: min(440px, calc(100vw - 32px)); transition: transform 0.34s var(--ease);
}
.earn-congrats.is-shown { transform: translate(-50%, 0); }
.earn-congrats-emoji { font-size: 28px; line-height: 1; color: var(--accent); }
.earn-congrats-title { font-size: 15px; font-weight: 700; color: var(--text); }
.earn-congrats-sub { font-size: 12.5px; color: var(--text-dim); margin-top: 2px; }
.earn-congrats-view {
  margin-left: 6px; flex: none; background: var(--accent); color: var(--on-accent); border: none;
  border-radius: 999px; padding: 8px 14px; font-size: 13px; font-weight: 600; cursor: pointer;
}

/* Earn: season end text + Ranks sub-tabs (Agents | Team) */
.earn-jackpot-ends { font-size: 12px; color: var(--text-dim); }
.earn-subtabs { display: flex; gap: 8px; margin-bottom: 16px; }
.earn-subtab {
  display: inline-flex; align-items: center; justify-content: center; min-height: 40px;
  background: var(--bg-elev-1); border: none; cursor: pointer;
  color: var(--text-dim); font-size: 13px; font-weight: 500;
  padding: 8px 16px; border-radius: 999px;
  transition: color var(--ease) 120ms, background var(--ease) 120ms;
}
.earn-subtab:hover { color: var(--text); }
.earn-subtab.is-active { color: var(--accent); background: color-mix(in srgb, var(--accent) 14%, var(--bg-elev-1)); }

/* ── Two clear levels of navigation ────────────────────────────────────────
   Primary: the Activity | Ranks section tabs render as bold underline tabs (not
   pills) so they're unmistakably the top level. Secondary: the in-section filters
   (All/Yield/… and the Ranks sub-tabs) stay as small, quiet pills. */
/* Material-3 / Gemini primary tabs: text labels on a full-width rail (the divider),
   with a rounded active indicator that sits on the rail. */
.tabs-primary { gap: 6px; margin: 16px 0 16px; border-bottom: 1px solid var(--border); }
.tabs-primary .earn-subtab {
  position: relative; align-items: flex-end; min-height: 40px;
  background: none; border-radius: 0;
  padding: 11px 14px 9px; font-size: 14.5px; font-weight: 600; letter-spacing: 0.2px;
  color: var(--text-dim);
}
.tabs-primary .earn-subtab:first-child { padding-left: 2px; }
.tabs-primary .earn-subtab:hover { background: none; color: var(--text); }
.tabs-primary .earn-subtab.is-active { background: none; color: var(--accent); }
/* Active indicator: a rounded bar that spans the label (inset matches the side
   padding) and sits on the divider rail just below it. */
.tabs-primary .earn-subtab.is-active::after {
  content: ""; position: absolute; left: 14px; right: 14px; bottom: 0; height: 3px;
  border-radius: 3px 3px 0 0; background: var(--accent);
}
.tabs-primary .earn-subtab:first-child.is-active::after { left: 2px; }

/* ── User-level Earn screen (earnings.ui.ts) ───────────────────────────────
   Reward-pool overview + sub-dashboard tiles + Leaderboards/Details tabs.
   Reuses .earn-dash/.earn-tile, .earn-subtab, .earn-rank-* primitives.
   Desktop: a normal centered column that scrolls wholesale (headline + subtitle
   like the other screens). Mobile: a pinned header + inner scroll (media block). */
.earnings-screen { display: block; }
/* Desktop header: big headline + subtitle, matching .sched-intro. */
.earnings-topbar {
  width: 100%; max-width: 760px; margin: 0 auto;
  padding: 72px 24px 4px;
}
.earnings-topbar-title {
  margin: 0 0 10px;
  font-family: "Google Sans Flex", "Google Sans Text", Roboto, system-ui, sans-serif;
  font-size: 32px; font-weight: 400; letter-spacing: -0.2px; line-height: 1.1;
}
.earnings-subtitle {
  margin: 0; max-width: 620px;
  font-size: 14.5px; color: var(--text-dim); line-height: 1.55;
}
/* One scroll column: giveaway + hero + actions all scroll together (nothing pinned). */
.earnings-scroll {
  width: 100%; max-width: 760px; margin: 0 auto;
  padding: 0 24px 96px;
}
.earnings-jackpot-slot { margin: 12px 0 16px; }
.earnings-hero-slot { margin-bottom: 6px; }

/* Mobile: compact pinned top bar (title beside the hamburger); everything below scrolls
   together in one region, the tabs sticking just under the top bar. */
@media (max-width: 720px) {
  .layout.earnings-active #earnings-view { display: flex; flex-direction: column; overflow: hidden; }
  .earnings-screen { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; }
  .earnings-topbar {
    flex: 0 0 auto;
    display: flex; align-items: center;
    max-width: none; margin: 0;
    min-height: calc(56px + env(safe-area-inset-top));
    padding: env(safe-area-inset-top) 16px 0 68px; /* left pad clears the wider hamburger */
    background: var(--bg);
  }
  .earnings-topbar-title { margin: 0; font-size: 18px; font-weight: 600; line-height: 1; }
  .earnings-subtitle { display: none; }
  .earnings-scroll { flex: 1 1 auto; min-height: 0; overflow-y: auto; max-width: none; padding: 0 16px 96px; }
}

.earnings-overview {
  background: var(--bg-elev-1);
  border-radius: var(--radius-lg);
  padding: 20px 22px;
  margin-bottom: 12px;
}
.earnings-overview-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.earnings-overview-label {
  font-size: 12.5px; font-weight: 600; letter-spacing: 0.6px;
  text-transform: uppercase; color: var(--text-dim);
}
.earnings-overview-expiry {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 12px; color: var(--text-dim);
}
.earnings-overview-expiry .material-symbols-rounded { font-size: 16px; }
.earnings-pool {
  font-family: var(--font-display);
  font-size: 42px; font-weight: 700; line-height: 1.05; margin-top: 10px;
  background: var(--grad-h); -webkit-background-clip: text; background-clip: text; color: transparent;
}
.earnings-progress { margin-top: 18px; }
.earnings-progress-track {
  height: 10px; border-radius: 999px; background: var(--bg-elev-3); overflow: hidden;
}
.earnings-progress-bar {
  height: 100%; width: 0; border-radius: 999px; background: var(--grad-h);
  transition: width 0.7s var(--ease);
}
.earnings-progress-meta {
  display: flex; align-items: baseline; justify-content: space-between;
  margin-top: 9px; font-size: 12.5px; color: var(--text-dim);
}
.earnings-progress-meta strong { color: var(--text); font-weight: 600; }

/* Keep all 4 stat tiles on one line (override the shared 2×2 wrap rule); the
   value font scales down on narrow phones so "$3,847.55" still fits at 4-up. */
.earn-dash.earnings-dash { flex-wrap: nowrap; gap: 8px; }
.earnings-dash .earn-tile { flex: 1 1 0; min-width: 0; padding: 15px 8px; }
.earnings-dash .earn-tile-value {
  font-size: clamp(14px, 4.2vw, 22px);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.earnings-dash .earn-tile-label { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* "How yield works" primer — a foldable card directly under the yield dashboard. */
.yield-how {
  margin: 10px 0 4px; border-radius: var(--radius-lg);
  border: 1px solid var(--border); background: var(--surface-2, rgba(255, 255, 255, 0.03));
}
.yield-how-summary {
  display: flex; align-items: center; gap: 8px; cursor: pointer; list-style: none;
  padding: 12px 14px; font-size: 13.5px; font-weight: 700; color: var(--text);
}
.yield-how-summary::-webkit-details-marker { display: none; }
.yield-how-summary > span { flex: 1; }
.yield-how-summary .material-symbols-rounded { font-size: 18px; color: var(--accent); }
/* Chevron rotates when open. */
.yield-how-summary .material-symbols-rounded:last-child { color: var(--text-dim); transition: transform 0.18s var(--ease); }
.yield-how[open] .yield-how-summary .material-symbols-rounded:last-child { transform: rotate(180deg); }
.yield-how-list { list-style: none; margin: 0; padding: 0 14px 12px; display: flex; flex-direction: column; gap: 10px; }
.yield-how-row { display: flex; align-items: flex-start; gap: 10px; font-size: 12.5px; line-height: 1.45; color: var(--text-dim); }
.yield-how-row .material-symbols-rounded { font-size: 17px; color: var(--accent); flex: none; margin-top: 1px; }

/* Leaderboard amount (reuses .earn-rank-row layout, prominent value column). */
.earnings-rank-amount {
  flex: none; font-size: 14px; font-weight: 600; color: var(--text);
  font-variant-numeric: tabular-nums;
}

/* Detail list rows (yield / referral). */
.earnings-list { display: flex; flex-direction: column; gap: 4px; }
.earnings-row {
  display: flex; align-items: center; gap: 14px;
  padding: 12px 14px; border-radius: var(--radius-sm); background: var(--bg-elev-1);
}
.earnings-row-main { flex: 1 1 auto; min-width: 0; }
.earnings-row-title {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  font-size: 14px; font-weight: 500; color: var(--text);
}
.earnings-row-sub { font-size: 12px; color: var(--text-faint); margin-top: 3px; }
.earnings-type {
  font-size: 11px; font-weight: 600; color: var(--text-dim);
  background: var(--bg-elev-2); padding: 2px 8px; border-radius: 999px;
}
.earnings-row-amount {
  font-size: 14px; font-weight: 700; color: var(--text);
  font-variant-numeric: tabular-nums; text-align: right;
}
.earnings-row-amount.is-pos { color: var(--ok); }
.earnings-row-date { font-size: 11.5px; color: var(--text-faint); text-align: right; margin-top: 3px; }

/* ── Store screen (store.ui.ts) ────────────────────────────────────────────
   Active-agent balance strip + two bundle grids (Power, Credits). Reuses the
   .sched-center scaffold and .skills-action button. */
/* Store header: the title and the wallet HUD share ONE row (so the HUD is always
   level with "Store"), with the subtitle on the line below. On mobile the row fills
   the sticky bar and centers with the floating hamburger. */
.store-intro-row { display: flex; align-items: center; justify-content: space-between; gap: 16px; flex: 1 1 auto; min-width: 0; }
.store-intro-row .sched-headline { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
/* Wallet HUD: Power + Credits grouped in one bordered pill. */
.store-wallet {
  flex: none; display: inline-flex; align-items: center; gap: 10px;
  padding: 6px 12px; border-radius: 999px;
  background: var(--bg-elev-1); border: 1px solid var(--border);
}
.store-wallet .cur { font-size: 14px; font-weight: 600; color: var(--text); }
.store-wallet-sep { width: 1px; height: 14px; background: var(--border-strong); }

.store-balance {
  display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap;
  background: var(--bg-elev-1); border-radius: var(--radius); padding: 14px 18px; margin: 4px 0 22px;
}
.store-balance-agent { font-size: 14px; font-weight: 600; color: var(--text); }
.store-balance-pills { display: flex; gap: 22px; }
.store-bal { display: flex; align-items: center; gap: 9px; }
.store-bal .material-symbols-rounded { font-size: 22px; color: var(--accent); }
.store-bal-value { font-size: 17px; font-weight: 700; color: var(--text); line-height: 1.1; font-variant-numeric: tabular-nums; }
.store-bal-label { font-size: 11.5px; color: var(--text-faint); }

.store-section { margin-top: 26px; }
.store-section-title {
  font-size: 13px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px;
  color: var(--text-dim); margin: 0 0 4px;
}
.store-section-hint { font-size: 12.5px; color: var(--text-faint); margin: 0 0 14px; line-height: 1.5; }

.store-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 12px; }
.store-card {
  position: relative;
  display: flex; flex-direction: column; gap: 8px;
  background: var(--bg-elev-1); border-radius: var(--radius); padding: 16px;
}
/* Best-value card: accent ring + a faint accent wash so the promotion reads at a glance. */
.store-card.is-best {
  box-shadow: inset 0 0 0 1.5px color-mix(in srgb, var(--accent) 55%, transparent);
  background: color-mix(in srgb, var(--accent) 8%, var(--bg-elev-1));
}
.store-badge {
  position: absolute; top: 12px; right: 12px;
  font-size: 10.5px; font-weight: 700; letter-spacing: 0.3px; color: var(--on-accent);
  background: var(--accent); border-radius: 999px; padding: 2px 9px; white-space: nowrap;
}
.store-card-name { font-size: 13px; font-weight: 600; color: var(--text-dim); }
/* Reserve room under the absolute "Best value" badge so a long name can't slide beneath it. */
.store-card.is-best .store-card-name { max-width: calc(100% - 88px); }
/* Per-bundle discount / bonus chip — its own line (never crowds the price+Buy row), nowrap. */
.store-card-save {
  align-self: flex-start;
  font-size: 11px; font-weight: 700; white-space: nowrap; line-height: 1.3;
  color: var(--accent);
  background: color-mix(in srgb, var(--accent) 15%, transparent);
  border-radius: 999px; padding: 2px 9px;
}
.store-card-save.is-best { color: var(--on-accent); background: var(--accent); }
.store-card-amount { display: flex; align-items: baseline; gap: 6px; }
.store-card-amount .material-symbols-rounded { font-size: 22px; color: var(--accent); align-self: center; }
.store-card-amount > span:nth-of-type(1) { font-size: 26px; font-weight: 700; color: var(--text); line-height: 1; font-variant-numeric: tabular-nums; }
.store-card-unit { font-size: 13px; font-weight: 600; color: var(--text-faint); }
.store-card-sub { font-size: 12px; color: var(--text-faint); }
/* Price ABOVE a full-width button (two lines) — in the narrow 2-column grid a
   side-by-side row squeezes/misaligns the button (esp. with CJK labels). */
.store-card-foot { display: flex; flex-direction: column; align-items: stretch; gap: 10px; margin-top: auto; padding-top: 6px; }
.store-card-price { font-size: 16px; font-weight: 700; color: var(--text); font-variant-numeric: tabular-nums; }
/* Price shown as the locked-earnings chip: shrink to its content, don't stretch to the
   card-foot's full width (the foot is a stretch column). */
.store-card-foot .earn-lock-chip { align-self: flex-start; }
.store-card-cost { display: inline-flex; align-items: center; gap: 3px; }
.store-card-cost .material-symbols-rounded { font-size: 17px; color: var(--accent); }
.store-buy { width: 100%; align-self: stretch; padding: 11px 18px; min-height: 44px; }

/* ── Top-up modal (topup.ui.ts) — one job: allocate Credits pool → agent.
   Gemini language: a centered balance hero, quick-amount chips, one primary
   action. Reuses .settings-overlay/.settings-panel + .buy-chip + .auth-btn. ── */
.settings-panel.topup-panel { width: min(440px, 100%); }
.topup-body { padding: 8px 22px 24px; }

/* Hero: the pool balance, in the app's balance-card treatment (mirrors .wallet-hero). */
.topup-hero {
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  padding: 28px 20px; margin: 4px 0 22px;
  border-radius: var(--radius-hero);
  background:
    radial-gradient(125% 80% at 50% -10%, color-mix(in srgb, var(--grad-b) 16%, transparent), transparent 62%),
    var(--bg-elev-1);
  text-align: center;
}
.topup-hero-label {
  font-family: var(--font-display);
  font-size: 12px; font-weight: 600; text-transform: uppercase; letter-spacing: 1.1px;
  color: var(--text-faint);
}
.topup-hero-num { display: inline-flex; align-items: center; gap: 8px; }
.topup-hero-num .cur-icon { font-size: 32px; color: var(--accent); }
.topup-hero-num .cur-val {
  font-family: var(--font-display);
  font-size: 46px; font-weight: 500; line-height: 1.02; letter-spacing: -1.4px;
  font-variant-numeric: tabular-nums; color: var(--accent);
}

.topup-label { font-size: 13px; font-weight: 600; color: var(--text-dim); margin: 0 0 10px; }
.topup-chips { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 12px; }
.topup-input {
  width: 100%; box-sizing: border-box; padding: 12px 14px; margin-bottom: 16px;
  border-radius: var(--radius-md);
  border: 1px solid var(--border); background: var(--bg-elev-1); color: var(--text);
  font-size: 16px; font-variant-numeric: tabular-nums;
}
.topup-input:focus { outline: none; border-color: var(--border-strong); }
.topup-primary { width: 100%; }
.topup-foot { text-align: center; font-size: 12.5px; color: var(--text-faint); margin: 14px 0 0; }
.topup-empty { text-align: center; font-size: 14px; color: var(--text-dim); margin: 2px 0 16px; }

.topup-note { padding: 14px 2px 0; font-size: 12.5px; color: var(--text-dim); line-height: 1.5; text-align: center; }
.topup-note.is-error { color: var(--err); }

/* ── Wallet screen (portfolio · receive · send) — Gemini-style ─────────────── */
/* Fill the .sched-center column so the hero card / actions / asset rows share the
   exact left+right edges of the headline + subtitle (no indented, off-balance card). */
.wallet-body { width: 100%; margin: 12px 0 0; }

/* Hero: the headline number rendered in Gemini's signature blue→purple→pink
   gradient (Google Sans Flex display face), on a softly gradient-lit card. */
.wallet-hero {
  position: relative;
  display: flex; flex-direction: column; align-items: center; gap: 7px;
  padding: 36px 20px 30px; margin: 6px 0 22px;
  border-radius: var(--radius-hero);
  background:
    radial-gradient(125% 80% at 50% -10%, color-mix(in srgb, var(--grad-b) 16%, transparent), transparent 62%),
    var(--bg-elev-1);
  text-align: center;
}
.wallet-hero-label {
  font-family: var(--font-display);
  font-size: 12px; font-weight: 600; text-transform: uppercase; letter-spacing: 1.1px;
  color: var(--text-faint);
}
.wallet-hero-total {
  font-family: var(--font-display);
  font-size: 56px; font-weight: 500; line-height: 1.02; letter-spacing: -1.6px;
  font-variant-numeric: tabular-nums;
  /* Mono accent: white on dark, black on light (matches the app's greeting). */
  color: var(--accent);
}
.wallet-address {
  display: inline-flex; align-items: center; gap: 7px; margin-top: 4px; min-height: 40px;
  background: var(--bg-elev-2); border: none; border-radius: 999px; padding: 8px 16px;
  color: var(--text-dim); font: inherit; font-size: 13px; cursor: pointer;
  transition: color 0.15s var(--ease), background 0.15s var(--ease);
}
.wallet-address:hover { color: var(--text); background: var(--bg-elev-3); }
.wallet-address .material-symbols-rounded { font-size: 16px; }
.wallet-degraded { font-size: 12px; color: var(--warn); margin-top: 6px; }
/* Network badge — quiet/neutral on mainnet, a loud warning on any test network. */
.wallet-net {
  display: inline-flex; align-items: center; gap: 5px; align-self: center; margin-top: 10px;
  padding: 3px 10px; border-radius: 999px; font-size: 11.5px; font-weight: 600; letter-spacing: 0.2px;
  background: var(--bg-elev-2); color: var(--text-faint);
}
.wallet-net.is-test {
  background: color-mix(in srgb, var(--warn) 18%, var(--bg-elev-2)); color: var(--warn);
}
.wallet-net .material-symbols-rounded { font-size: 15px; }
/* Receive-screen test-network warning — sits above the address/QR. */
.wallet-receive-warn {
  display: flex; align-items: flex-start; gap: 8px; margin: 0 0 12px;
  padding: 11px 13px; border-radius: var(--radius-md); line-height: 1.5; font-size: 13px;
  background: color-mix(in srgb, var(--warn) 14%, var(--bg-elev-1)); color: var(--text);
  border: 1px solid color-mix(in srgb, var(--warn) 40%, transparent);
}
.wallet-receive-warn .material-symbols-rounded { font-size: 19px; color: var(--warn); flex: none; }

/* Manual refresh — a subtle icon button in the hero's top-right corner. */
.wallet-refresh {
  position: absolute; top: 14px; right: 14px;
  display: inline-flex; align-items: center; justify-content: center;
  width: 40px; height: 40px; border-radius: 50%; border: none; cursor: pointer;
  background: transparent; color: var(--text-faint);
  transition: background 0.15s var(--ease), color 0.15s var(--ease);
}
.wallet-refresh:hover { background: var(--bg-elev-2); color: var(--text); }
.wallet-refresh:disabled { cursor: default; }
.wallet-refresh .material-symbols-rounded { font-size: 20px; }
/* Earnings shortcut pinned to the balance card (top-left, mirrors refresh top-right). */
.wallet-hero-earn {
  position: absolute; top: 14px; left: 14px;
  display: inline-flex; align-items: center; gap: 5px;
  padding: 6px 11px 6px 9px; border-radius: 999px;
  border: 1px solid var(--border);
  background: color-mix(in srgb, var(--bg) 35%, transparent);
  color: var(--text-dim);
  font: inherit; font-size: 12px; font-weight: 600;
  cursor: pointer;
  transition: background 0.15s var(--ease), color 0.15s var(--ease);
}
.wallet-hero-earn:hover { background: var(--bg-elev-2); color: var(--text); }
.wallet-hero-earn .material-symbols-rounded { font-size: 16px; }
.wallet-refresh.is-spinning .material-symbols-rounded { animation: wallet-spin 0.8s linear infinite; }
@keyframes wallet-spin { to { transform: rotate(360deg); } }

/* Receive / Send — Gemini tonal pills. */
.wallet-actions { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin-bottom: 28px; }
.wallet-action {
  display: inline-flex; align-items: center; justify-content: center; gap: 9px;
  padding: 15px 16px; border-radius: 999px; border: none; cursor: pointer;
  background: var(--bg-elev-1); color: var(--text); font: inherit; font-size: 15px; font-weight: 600;
  transition: background 0.15s var(--ease), transform 0.15s var(--ease);
}
.wallet-action:hover { background: var(--bg-elev-2); }
.wallet-action:active { transform: scale(0.985); }
.wallet-action .material-symbols-rounded { font-size: 20px; color: var(--text-dim); }

/* Asset list — Gemini list rows with a tonal hover. */
.wallet-tokens { display: flex; flex-direction: column; margin: 0 -8px; }
.wallet-token {
  display: flex; align-items: center; gap: 13px; padding: 12px 12px; border-radius: var(--radius);
  transition: background 0.15s var(--ease);
}
.wallet-token:hover { background: var(--bg-elev-1); }
.wallet-token-logo { width: 38px; height: 38px; border-radius: 50%; flex: none; object-fit: cover; background: var(--bg-elev-2); }
.wallet-token-logo-fallback {
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 16px; font-weight: 600; color: var(--text-dim);
}
.wallet-token-main { flex: 1 1 auto; min-width: 0; }
.wallet-token-symbol { font-size: 15px; font-weight: 600; color: var(--text); }
.wallet-token-name { font-size: 12.5px; color: var(--text-faint); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.wallet-token-right { text-align: right; flex: none; }
.wallet-token-usd { font-size: 15px; font-weight: 600; color: var(--text); font-variant-numeric: tabular-nums; }
.wallet-token-bal { font-size: 12.5px; color: var(--text-faint); font-variant-numeric: tabular-nums; }
.wallet-token-empty { font-size: 13.5px; color: var(--text-faint); padding: 16px 12px; }
.wallet-empty { color: var(--text-faint); }
.wallet-spam-toggle {
  background: none; border: none; color: var(--text-dim); font: inherit; font-size: 13px;
  cursor: pointer; padding: 12px; margin: 4px -8px 0; text-align: left; border-radius: var(--radius-sm);
}
.wallet-spam-toggle:hover { color: var(--text); background: var(--bg-elev-1); }

/* Activity (in/out history) — rows are explorer links; incoming amounts are green,
   settled-withdrawal arrivals get an accent highlight. */
.wallet-tabs { margin-top: 22px; }
.wallet-tab-content { min-height: 80px; }
.wallet-activity { display: flex; flex-direction: column; margin: 0 -8px; }
.wallet-act-row {
  display: flex; align-items: center; gap: 13px; padding: 11px 12px; border-radius: var(--radius);
  text-decoration: none; color: inherit; transition: background 0.15s var(--ease);
}
.wallet-act-row:hover { background: var(--bg-elev-1); }
.wallet-act-icon {
  display: inline-flex; align-items: center; justify-content: center; flex: none;
  width: 36px; height: 36px; border-radius: 50%; overflow: hidden;
  background: var(--bg-elev-2); color: var(--text-dim); font-size: 19px;
}
.wallet-act-main { flex: 1 1 auto; min-width: 0; }
.wallet-act-title {
  display: flex; align-items: center; gap: 8px;
  font-size: 14.5px; font-weight: 600; color: var(--text);
}
.wallet-act-badge {
  font-size: 10.5px; font-weight: 700; letter-spacing: 0.02em; text-transform: uppercase;
  color: var(--ok); background: color-mix(in srgb, var(--ok) 16%, transparent);
  padding: 2px 7px; border-radius: 999px;
}
.wallet-act-badge.is-pending { color: var(--warn); background: color-mix(in srgb, var(--warn) 16%, transparent); }
.wallet-act-badge.is-failed { color: var(--danger); background: color-mix(in srgb, var(--danger) 16%, transparent); }
/* Activity subcategory chips — All | Withdrawals. */
.wallet-act-filters { display: flex; gap: 6px; margin: 2px 0 10px; }
.wallet-act-filter {
  border: 1px solid var(--border); background: transparent; color: var(--text-dim);
  font: inherit; font-size: 12px; font-weight: 600;
  padding: 4px 12px; border-radius: 999px; cursor: pointer;
  transition: background 0.15s var(--ease), color 0.15s var(--ease);
}
.wallet-act-filter:hover { color: var(--text); background: var(--bg-elev-1); }
.wallet-act-filter.is-active {
  color: var(--accent); border-color: color-mix(in srgb, var(--accent) 45%, transparent);
  background: color-mix(in srgb, var(--accent) 12%, transparent);
}
.wallet-act-sub { font-size: 12.5px; color: var(--text-faint); margin-top: 2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.wallet-act-right { text-align: right; flex: none; }
.wallet-act-amount { font-size: 14.5px; font-weight: 700; color: var(--text-dim); font-variant-numeric: tabular-nums; }
.wallet-act-amount.is-pos { color: var(--ok); }
.wallet-act-date { font-size: 11.5px; color: var(--text-faint); margin-top: 2px; }
/* Settled earnings withdrawal landing — the highlighted "withdraw received" row. */
.wallet-act-row.is-withdrawal { background: color-mix(in srgb, var(--ok) 9%, transparent); }
.wallet-act-row.is-withdrawal:hover { background: color-mix(in srgb, var(--ok) 14%, transparent); }
.wallet-act-row.is-withdrawal .wallet-act-icon { background: color-mix(in srgb, var(--ok) 18%, var(--bg-elev-1)); color: var(--ok); }

/* Receive modal: QR + address. */
.wallet-qr { display: flex; align-items: center; justify-content: center; margin: 18px 0; }
.wallet-qr-img { width: 232px; height: 232px; image-rendering: pixelated; border-radius: var(--radius-lg); background: #fff; padding: 14px; box-shadow: var(--shadow-md); }
.wallet-qr-loading { font-size: 13px; color: var(--text-faint); padding: 46px 0; }
.wallet-receive-addr { background: var(--bg-elev-1); border-radius: var(--radius-md); padding: 13px 16px; margin-bottom: 12px; word-break: break-all; text-align: center; }
.wallet-receive-addr code { font-size: 13px; color: var(--text-dim); font-family: var(--font-mono); letter-spacing: 0.2px; }

/* Send modal: labeled fields (inputs reuse .auth-input / button reuses .auth-btn). */
.wallet-field { display: flex; flex-direction: column; gap: 7px; margin-bottom: 16px; }
.wallet-field-label { font-size: 12.5px; font-weight: 600; color: var(--text-dim); }
.wallet-field-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.wallet-send-hint { font-size: 12px; color: var(--warn); margin: -6px 0 14px; min-height: 16px; line-height: 1.5; }

/* Custom asset dropdown — a dark, themed replacement for the native <select>, whose
   option popup renders in the OS (light) theme and can't be styled. */
.wallet-asset-wrap { position: relative; }
.wallet-asset-trigger {
  width: 100%; display: flex; align-items: center; gap: 10px;
  padding: 10px 14px; border-radius: var(--radius-sm); border: 1px solid var(--border);
  background: var(--bg-elev-1); color: var(--text); font: inherit; font-size: 15px; cursor: pointer;
  transition: background 0.15s var(--ease), border-color 0.15s var(--ease);
}
.wallet-asset-trigger:hover { background: var(--bg-elev-2); }
.wallet-asset-label { flex: 1 1 auto; text-align: left; }
.wallet-asset-chev { font-size: 22px; color: var(--text-faint); }
.wallet-asset-logo { width: 24px; height: 24px; border-radius: 50%; flex: none; object-fit: cover; background: var(--bg-elev-2); font-size: 11px; }
.wallet-asset-menu {
  position: absolute; left: 0; right: 0; top: calc(100% + 6px); z-index: 6;
  padding: 6px; border-radius: var(--radius-sm); border: 1px solid var(--border);
  background: var(--bg-elev-2); box-shadow: var(--shadow-lg);
  max-height: 244px; overflow-y: auto;
}
.wallet-asset-option {
  width: 100%; display: flex; align-items: center; gap: 11px;
  padding: 9px 10px; border-radius: var(--radius-sm); border: none; background: none; color: var(--text);
  font: inherit; cursor: pointer; text-align: left; transition: background 0.12s var(--ease);
}
.wallet-asset-option:hover { background: var(--bg-elev-3); }
.wallet-asset-opt-main { flex: 1 1 auto; min-width: 0; }
.wallet-asset-opt-sym { font-size: 14px; font-weight: 600; }
.wallet-asset-opt-bal { font-size: 12px; color: var(--text-faint); }
.wallet-asset-check { font-size: 19px; color: var(--accent); opacity: 0; flex: none; }
.wallet-asset-option.is-selected .wallet-asset-check { opacity: 1; }

/* Quick-amount chips. */
.wallet-amount-chips { display: flex; gap: 6px; }
.wallet-chip {
  display: inline-flex; align-items: center; justify-content: center; min-height: 40px;
  padding: 8px 16px; border-radius: 999px; border: none; cursor: pointer;
  background: var(--bg-elev-2); color: var(--text-dim); font: inherit; font-size: 12px; font-weight: 600;
  transition: background 0.15s var(--ease), color 0.15s var(--ease);
}
.wallet-chip:hover { background: var(--bg-elev-3); color: var(--text); }

/* Wallet modals (Receive / Send) — shared Gemini chrome so both read identically:
   softer corners than the default settings panel, a borderless title, and even body
   padding so the QR / fields / address / buttons all align to the same gutters. */
/* overflow:visible so the asset dropdown menu can float past the body/panel edges
   (wallet modals are short, so they never need the panel's own scroll). */
.settings-panel.wallet-modal { border-radius: var(--radius-lg); overflow: visible; }
.settings-panel.wallet-modal .settings-titlebar { border-bottom: none; padding: 18px 22px 6px; }
.settings-panel.wallet-modal .settings-titlebar h2 { font-family: var(--font-display); font-weight: 500; }
.wallet-modal-body { padding: 4px 22px 22px; max-height: none; overflow: visible; }
.wallet-modal-intro { font-size: 14px; color: var(--text-dim); line-height: 1.55; margin: 2px 0 8px; }
/* The primary modal button (Copy address / Confirm send) is the same white pill in both. */
.wallet-modal-body .auth-btn { margin-top: 4px; }

/* ── Settings → Appearance: light/dark segmented toggle ────────────────────── */
.theme-toggle-row { display: flex; gap: 10px; margin-top: 8px; }
.theme-opt {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 12px 20px; border-radius: var(--radius-md); cursor: pointer;
  background: var(--bg-elev-1); border: none; color: var(--text-dim);
  font: inherit; font-size: 14px; font-weight: 600;
  box-shadow: inset 0 0 0 1.5px transparent;
  transition: color 0.15s var(--ease), background 0.15s var(--ease), box-shadow 0.15s var(--ease);
}
.theme-opt .material-symbols-rounded { font-size: 20px; }
.theme-opt:hover { color: var(--text); background: var(--bg-elev-2); }
.theme-opt.is-active {
  color: var(--text);
  background: color-mix(in srgb, var(--accent) 12%, var(--bg-elev-1));
  box-shadow: inset 0 0 0 1.5px color-mix(in srgb, var(--accent) 45%, transparent);
}

/* Settings → Agent: inline input + action button rows. */
.settings-row { display: flex; gap: 8px; align-items: center; margin-top: 6px; }
.settings-row .settings-input { flex: 1 1 auto; min-width: 0; }
.settings-row .skills-action { flex: none; }

/* ── Settings → Agent panel (Gemini-style cards) ───────────────────────────── */
.agentset { display: flex; flex-direction: column; gap: 14px; max-width: 560px; }
.agentset-card { background: var(--bg-elev-1); border-radius: var(--radius-lg); padding: 20px 22px; }
.agentset-label {
  font-size: 12px; font-weight: 600; letter-spacing: 0.5px; text-transform: uppercase;
  color: var(--text-dim); margin-bottom: 14px;
}

/* advanced web search toggle */
.agentset-toggle-row { display: flex; align-items: center; justify-content: space-between; gap: 16px; }
.agentset-toggle-text { min-width: 0; }
.agentset-toggle-row .agentset-label { margin-bottom: 4px; }
.agentset-hint { font-size: 12.5px; line-height: 1.4; color: var(--text-faint); text-transform: none; letter-spacing: 0; font-weight: 400; }
.agentset-switch {
  appearance: none; -webkit-appearance: none; flex: 0 0 auto; position: relative;
  width: 44px; height: 26px; border-radius: 999px; cursor: pointer;
  background: var(--bg-elev-2); border: 1px solid var(--border); transition: background 0.15s var(--ease);
}
.agentset-switch::after {
  content: ""; position: absolute; top: 2px; left: 2px; width: 20px; height: 20px;
  border-radius: 50%; background: var(--text-dim); transition: transform 0.15s var(--ease), background 0.15s var(--ease);
}
.agentset-switch:checked { background: var(--accent); border-color: var(--accent); }
.agentset-switch:checked::after { transform: translateX(18px); background: var(--bg); }
.agentset-switch:disabled { opacity: 0.6; cursor: default; }

.agentset-name-row { display: flex; gap: 10px; align-items: center; }
.agentset-name,
.agentset-input {
  flex: 1 1 auto; min-width: 0;
  background: var(--bg-elev-2); border: none; border-radius: var(--radius-sm);
  padding: 12px 14px; color: var(--text); font: inherit; outline: none;
  transition: box-shadow 0.15s var(--ease);
}
.agentset-name { font-size: 16px; font-weight: 600; }
.agentset-input { font-size: 14px; }
.agentset-name::placeholder,
.agentset-input::placeholder { color: var(--text-faint); }
.agentset-name:focus,
.agentset-input:focus { box-shadow: inset 0 0 0 1.5px color-mix(in srgb, var(--accent) 45%, transparent); }

/* identity card: label + the agent's star tier, side by side */
.agentset-label-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 14px; }
.agentset-label--inline { margin-bottom: 0; }

/* Yield section: star + price/yield/unlock tiles, a one-line takeaway, and an
   expandable "How yield works" explainer. Values come from GET /api/agents. */
.agentset-ystats { display: flex; flex-wrap: wrap; gap: 8px; }
.agentset-ystat {
  flex: 1 1 0; min-width: 110px; text-align: center;
  display: flex; flex-direction: column; align-items: center; gap: 3px;
  background: var(--bg-elev-2); border-radius: var(--radius-sm); padding: 12px 8px;
}
.agentset-ystat-val { font-size: 16px; font-weight: 700; color: var(--text); font-variant-numeric: tabular-nums; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.agentset-ystat-label { font-size: 11px; font-weight: 600; color: var(--text-dim); }
.agentset-ystat-sub { font-size: 10px; color: var(--text-faint); }
.agentset-yhint { font-size: 12px; color: var(--text-dim); margin-top: 12px; line-height: 1.45; }
.agentset-ydisc { margin-top: 12px; }
.agentset-ydisc-sum {
  font-size: 13px; font-weight: 600; color: var(--text-dim); cursor: pointer;
  list-style: none; display: inline-flex; align-items: center; gap: 6px; padding: 8px 0;
}
.agentset-ydisc-sum::-webkit-details-marker { display: none; }
.agentset-ydisc-chev { font-size: 18px; transition: transform 0.15s var(--ease); }
.agentset-ydisc[open] .agentset-ydisc-chev { transform: rotate(90deg); }
.agentset-ydisc-list { margin: 8px 0 8px; padding-left: 20px; display: flex; flex-direction: column; gap: 12px; }
.agentset-ydisc-list li { font-size: 13px; color: var(--text-dim); line-height: 1.65; }
.agentset-ydisc-list li::marker { color: var(--text-faint); }

.agentset-save,
.agentset-btn {
  flex: none; cursor: pointer; border: none; border-radius: 999px;
  background: var(--bg-elev-2); color: var(--text);
  font: inherit; font-size: 14px; font-weight: 600; padding: 11px 22px;
  transition: background 0.15s var(--ease), filter 0.15s var(--ease);
}
.agentset-save:hover,
.agentset-btn:hover { background: var(--bg-elev-3); }
.agentset-btn-primary { background: var(--accent); color: var(--on-accent); }
.agentset-btn-primary:hover { background: var(--accent); filter: brightness(1.06); }
.agentset-btn-sm { font-size: 12.5px; padding: 7px 16px; }
/* Star-up CTA: wears the brand gradient (the feature's color on the Earn screen). */
.agentset-btn-starup {
  color: #fff;
  background: linear-gradient(120deg, var(--grad-a), var(--grad-b) 55%, var(--grad-c));
  box-shadow: 0 6px 18px -10px color-mix(in srgb, var(--grad-b) 90%, transparent);
}
.agentset-btn-starup:hover {
  background: linear-gradient(120deg, var(--grad-a), var(--grad-b) 55%, var(--grad-c));
  filter: brightness(1.08);
}

/* Gemini-style settings list rows (Yield economics, Credits, Subscription). */
.agentset-rows { margin-top: 4px; }
.agentset-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 13px 0; }
.agentset-row + .agentset-row,
.agentset-rowgroup + .agentset-rowgroup { border-top: 1px solid color-mix(in srgb, var(--border) 55%, transparent); }
.agentset-row-text { min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.agentset-row-label { font-size: 14px; font-weight: 500; color: var(--text); }
.agentset-row-sub { font-size: 12px; color: var(--text-faint); display: flex; align-items: center; gap: 3px; flex-wrap: wrap; }
.agentset-row-side { flex: none; display: flex; align-items: center; gap: 10px; }
.agentset-row-val { font-size: 14.5px; font-weight: 600; color: var(--text); font-variant-numeric: tabular-nums; white-space: nowrap; }
.agentset-row-val.is-warn { color: var(--warn); }
.agentset-row-val.is-danger { color: var(--danger-text); }
/* Collapsed-by-default controls under a row (top-up field, month picker). [hidden]
   must beat the blocks' own display values. */
.agentset-subctl { display: flex; flex-direction: column; gap: 10px; padding: 2px 0 12px; }
.agentset-rowgroup > .agentset-field { margin: 2px 0 12px; }
.agentset-subctl[hidden], .agentset-field[hidden] { display: none; }
/* Upgrade block: x/y counter pill + card-set progress bar (earn-screen language). */
.agentset-upgrade { border-top: 1px solid color-mix(in srgb, var(--border) 55%, transparent); }
.agentset-upgrade .uset-actions { display: flex; justify-content: flex-end; margin-top: 16px; }
.agentset-upgrade .agentset-hint { margin-top: 12px; }
.agentset-prog {
  flex: none; font-size: 12.5px; font-weight: 800; font-variant-numeric: tabular-nums;
  color: var(--text); background: var(--bg-elev-2); border-radius: 999px; padding: 5px 12px;
}
.agentset-progbar { height: 6px; border-radius: 999px; background: var(--bg-elev-2); overflow: hidden; margin: 1px 0 4px; }
.agentset-progbar-fill {
  height: 100%; border-radius: 999px; min-width: 6px;
  background: linear-gradient(90deg, var(--grad-a), var(--grad-b));
  transition: width 0.3s var(--ease);
}

.agentset-id-row { display: flex; align-items: center; gap: 8px; margin-top: 12px; }
.agentset-id {
  font-family: var(--font-mono); font-size: 12px; color: var(--text-faint);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.agentset-copy {
  flex: none; display: grid; place-items: center; cursor: pointer;
  background: transparent; border: none; color: var(--text-faint);
  padding: 4px; border-radius: var(--radius-tile); transition: background 0.15s var(--ease), color 0.15s var(--ease);
}
.agentset-copy:hover { background: var(--bg-elev-2); color: var(--text); }
.agentset-copy .material-symbols-rounded { font-size: 16px; }

.agentset-stat { display: flex; align-items: baseline; gap: 8px; }
.agentset-stat-value {
  font-family: var(--font-display); font-size: 32px; font-weight: 700; line-height: 1;
  color: var(--text); font-variant-numeric: tabular-nums;
}
.agentset-stat-unit { font-size: 14px; font-weight: 600; color: var(--text-faint); }
.agentset-meta { font-size: 12.5px; color: var(--text-faint); margin-top: 8px; }
.agentset-field { display: flex; gap: 10px; align-items: center; margin-top: 14px; }

.agentset-status { font-family: var(--font-display); font-size: 24px; font-weight: 600; color: var(--text); }
.agentset-status-expired { color: var(--danger-text); }
.agentset-status-none { color: var(--text-faint); }
.agentset-months { display: flex; gap: 8px; flex-wrap: wrap; margin: 16px 0 16px; }
.agentset-chip {
  cursor: pointer; border: none; border-radius: 999px;
  background: var(--bg-elev-2); color: var(--text-dim);
  font: inherit; font-size: 13px; font-weight: 600; padding: 8px 16px;
  transition: color 0.15s var(--ease), background 0.15s var(--ease);
}
.agentset-chip:hover { color: var(--text); }
.agentset-chip.is-active { color: var(--accent); background: color-mix(in srgb, var(--accent) 16%, var(--bg-elev-2)); }
.agentset-buy-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.agentset-cost { font-size: 13px; color: var(--text-dim); font-variant-numeric: tabular-nums; }

/* User settings panels in the same Gemini card style as the Agent panel. Scoped to
   the settings screen so admin/profile forms (which also use .settings-section) are
   untouched. Cards: International, Spending, Appearance, Self-improvement. */
#settings-view .settings-section {
  background: var(--bg-elev-1);
  border: none;
  border-radius: var(--radius-lg);
  padding: 20px 22px;
  margin: 0 0 14px;
  max-width: 560px;
}
#settings-view .settings-section h3,
#settings-view .settings-label {
  margin: 0 0 14px;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.5px;
  text-transform: uppercase;
  color: var(--text-dim);
}
/* Tonal (borderless) inputs — the Gemini field style. Shared by the Settings
   screen and the Schedules create/edit form (both use .settings-input/-textarea)
   so neither falls back to the legacy 1px-border + white-on-focus outline. */
#settings-view .settings-input,
#settings-view .settings-textarea,
#schedules-view .settings-input,
#schedules-view .settings-textarea {
  background: var(--bg-elev-2);
  border: none;
  border-radius: var(--radius-sm);
  padding: 12px 14px;
  transition: box-shadow 0.15s var(--ease);
}
#settings-view .settings-input:focus,
#settings-view .settings-textarea:focus,
#schedules-view .settings-input:focus,
#schedules-view .settings-textarea:focus {
  border: none;
  box-shadow: inset 0 0 0 1.5px color-mix(in srgb, var(--accent) 45%, transparent);
}
/* Language rows + theme toggle sit a touch below the card label. */
#settings-view .settings-lang-options,
#settings-view .theme-toggle-row { margin-top: 4px; }
#settings-view .settings-hint { margin-top: 10px; }

/* User settings cards (International / Spending / Appearance), Gemini style — same
   card language as the Agent panel, self-contained (no inherited .settings-* quirks). */
.uset { display: flex; flex-direction: column; gap: 14px; max-width: 560px; }
.uset-card { background: var(--bg-elev-1); border-radius: var(--radius-lg); padding: 20px 22px; }
/* Memory / Instructions / Persona editor: each textarea sits in its own uset-card section */
.uset-card > .settings-textarea { margin-top: 10px; background: var(--bg-elev-2); }
/* Memory graph view (docs/SECOND_BRAIN.md): 2D force-directed canvas of the topic wiki. */
.memory-graph-canvas {
  display: block; width: 100%; height: 320px; margin-top: 10px;
  background: var(--bg-elev-2); border: 1px solid var(--border); border-radius: 10px;
  touch-action: none; /* let pointer-drag work without the page panning */
}
.memory-graph-empty { margin-top: 10px; }
.memory-graph-legend {
  display: flex; flex-wrap: wrap; gap: 16px; margin-top: 10px;
  font-size: 11px; color: var(--text-faint);
}
.mg-legend-item { display: inline-flex; align-items: center; gap: 6px; }
.mg-dot { width: 9px; height: 9px; border-radius: 50%; background: var(--accent); display: inline-block; }
.mg-line { width: 16px; height: 0; border-top: 2px solid var(--text-faint); display: inline-block; }
.mg-inferred { border-top-style: dashed; border-top-color: var(--accent); }
/* Brain screen — layout comes from the shared .sched-center/.sched-intro/.sched-headline/
   .sched-subtitle convention (see renderBrain); only the canvas + empty message are specific. */
.memory-graph-canvas.brain-canvas { height: min(62vh, 600px); margin-top: 16px; }
/* Positioned box the canvas + floating legend + empty-state share (see renderBrain).
   On mobile it goes full-bleed and the legend/detail overlay it. */
.brain-graph { position: relative; }
.brain-empty { margin: 40px 0; text-align: center; }
/* The sheet backdrop is mobile-only; inert on desktop. */
.brain-backdrop { display: none; }
/* Detail panel: the "open note" for a clicked topic node. Class-driven (not the
   `hidden` attr) so the mobile sheet can transition; on desktop it's an inline card
   shown only once a node is opened. */
.brain-detail {
  display: none; margin-top: 14px; padding: 14px 16px;
  background: var(--bg-elev-2); border: 1px solid var(--border); border-radius: 12px;
}
.brain-detail.open { display: block; }
.brain-detail-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-bottom: 10px; }
.brain-detail-title { font-size: 14px; font-weight: 600; letter-spacing: 0.2px; }
.brain-detail-close {
  background: none; border: none; color: var(--text-dim); font-size: 13px; line-height: 1;
  cursor: pointer; padding: 4px 6px; border-radius: 6px;
}
.brain-detail-close:hover { color: var(--text); background: color-mix(in srgb, var(--text) 10%, transparent); }
/* Each topic note renders as its own block (a lead line / a sentence-per-line body /
   an arrow-timeline stepped list), separated by a hairline, so a long note reads as
   structure instead of a wall of text. */
.brain-detail-list { margin: 0; padding: 0; display: flex; flex-direction: column; gap: 14px; }
.brain-note { display: flex; flex-direction: column; gap: 7px; }
.brain-note + .brain-note { border-top: 1px solid var(--border); padding-top: 14px; }
.brain-note strong { color: var(--text); font-weight: 600; }
.brain-line { margin: 0; font-size: 13px; line-height: 1.6; color: var(--text-dim); }
.brain-steps { list-style: none; margin: 2px 0 0; padding: 0; display: flex; flex-direction: column; gap: 10px; }
.brain-step {
  position: relative; margin: 0; padding-left: 18px;
  font-size: 13px; line-height: 1.55; color: var(--text-dim);
}
.brain-step::before {
  content: ""; position: absolute; left: 2px; top: 6px;
  width: 6px; height: 6px; border-radius: 50%; background: var(--accent);
}
/* Connector line down the timeline. */
.brain-step:not(:last-child)::after {
  content: ""; position: absolute; left: 4.5px; top: 13px; bottom: -10px; width: 1px; background: var(--border);
}
.brain-detail-muted { margin: 0; font-size: 13px; color: var(--text-faint); }

/* Brain on mobile: the graph goes full-bleed under the 56px title bar, the
   topic/linked/inferred legend floats over it as a widget, and tapping a node slides
   its note up as a bottom sheet (matching the app's other slide-up modals). The
   .sched-intro keeps its 24px-negating side margin, so we keep the center's side
   padding and break the graph out to full width instead of zeroing it. */
@media (max-width: 720px) {
  .layout .brain-center { padding-bottom: 0; }
  .brain-center .sched-intro { margin-bottom: 0; }
  .brain-graph {
    margin: 0 -24px; /* full-bleed past .sched-center's 24px side padding */
    height: calc(100vh - 56px - env(safe-area-inset-top));
    height: calc(100dvh - 56px - env(safe-area-inset-top));
  }
  /* Compound selectors beat the .memory-graph-canvas / .memory-graph-legend bases. */
  .brain-canvas.memory-graph-canvas {
    height: 100%; margin: 0; border: none; border-radius: 0; background: var(--bg);
  }
  .brain-legend.memory-graph-legend {
    position: absolute; top: 12px; right: 12px; z-index: 2; margin: 0;
    flex-direction: column; gap: 8px; padding: 9px 11px; border-radius: 12px;
    background: color-mix(in srgb, var(--bg-elev-2) 82%, transparent);
    border: 1px solid var(--border);
    -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
  }
  .brain-empty {
    position: absolute; inset: 0; margin: 0; padding: 0 32px;
    display: flex; align-items: center; justify-content: center;
  }
  /* Tap-to-dismiss backdrop. */
  .brain-backdrop {
    display: block; position: fixed; inset: 0; z-index: 50;
    background: color-mix(in srgb, #000 45%, transparent);
    opacity: 0; visibility: hidden;
    transition: opacity 200ms var(--ease), visibility 200ms var(--ease);
  }
  .brain-backdrop.visible { opacity: 1; visibility: visible; }
  /* The note as a bottom sheet: always laid out (display:block) but slid off-screen
     until .open, so it can animate in. */
  .brain-detail {
    display: block; position: fixed; left: 0; right: 0; bottom: 0; z-index: 51;
    margin: 0; max-height: 72vh; overflow-y: auto;
    padding: 18px 18px calc(18px + env(safe-area-inset-bottom));
    border: 1px solid var(--border); border-bottom: none;
    border-radius: 18px 18px 0 0;
    transform: translateY(101%); visibility: hidden;
    transition: transform 260ms var(--ease), visibility 260ms var(--ease);
  }
  .brain-detail.open { transform: translateY(0); visibility: visible; }
  /* Grabber affordance. */
  .brain-detail::before {
    content: ""; display: block; width: 36px; height: 4px; border-radius: 999px;
    background: var(--border); margin: -4px auto 12px;
  }
}
@media (prefers-reduced-motion: reduce) {
  .brain-backdrop, .brain-detail { transition: none; }
}
.uset-label {
  margin: 0 0 14px; font-size: 12px; font-weight: 600; letter-spacing: 0.5px;
  text-transform: uppercase; color: var(--text-dim);
}
.uset-options { display: flex; flex-direction: column; gap: 8px; }
.uset-option {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  width: 100%; padding: 14px 16px; cursor: pointer; text-align: left;
  background: var(--bg-elev-2); border: none; border-radius: var(--radius-md);
  color: var(--text); font: inherit; font-size: 15px; font-weight: 500;
  transition: background 0.15s var(--ease), box-shadow 0.15s var(--ease);
}
.uset-option:hover { background: var(--bg-elev-3); }
.uset-option.is-active {
  background: color-mix(in srgb, var(--accent) 12%, var(--bg-elev-2));
  box-shadow: inset 0 0 0 1.5px color-mix(in srgb, var(--accent) 50%, transparent);
}
.uset-option-name { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.uset-option-check { flex: none; font-size: 20px; color: var(--accent); opacity: 0; }
.uset-option.is-active .uset-option-check { opacity: 1; }
.uset-status { font-size: 12.5px; color: var(--text-faint); line-height: 1.5; margin-top: 12px; }
.uset-status.err { color: var(--danger-text); }
.uset-field {
  display: flex; align-items: center; gap: 8px;
  background: var(--bg-elev-2); border-radius: var(--radius-sm); padding: 0 14px;
  transition: box-shadow 0.15s var(--ease);
}
.uset-field:focus-within { box-shadow: inset 0 0 0 1.5px color-mix(in srgb, var(--accent) 45%, transparent); }
.uset-prefix { flex: none; color: var(--text-faint); font-size: 15px; }
.uset-input {
  flex: 1 1 auto; min-width: 0; background: transparent; border: none; outline: none;
  color: var(--text); font: inherit; font-size: 15px; padding: 12px 0;
}
.uset-input::placeholder { color: var(--text-faint); }

/* Self-improvement: Gemini toggle switches + indented sub-toggles + tonal history. */
.uset-toggle { display: flex; align-items: center; gap: 14px; padding: 11px 0; cursor: pointer; }
.uset-toggle-body { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.uset-toggle-label { font-size: 14px; font-weight: 500; color: var(--text); }
.uset-toggle-hint { font-size: 12px; color: var(--text-faint); line-height: 1.45; }
.uset-switch-input { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }
.uset-switch {
  flex: none; position: relative; width: 42px; height: 24px; border-radius: 999px;
  background: var(--bg-elev-3); transition: background 0.18s var(--ease);
}
.uset-switch::after {
  content: ""; position: absolute; top: 3px; left: 3px; width: 18px; height: 18px;
  border-radius: 50%; background: var(--text-dim);
  transition: transform 0.18s var(--ease), background 0.18s var(--ease);
}
.uset-switch-input:checked + .uset-switch { background: var(--accent); }
.uset-switch-input:checked + .uset-switch::after { transform: translateX(18px); background: var(--on-accent); }
.uset-switch-input:focus-visible + .uset-switch { box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 30%, transparent); }
.uset-subtoggles { margin-left: 4px; padding-left: 16px; border-left: 2px solid var(--border); }
.uset-subtoggles.is-disabled { opacity: 0.45; pointer-events: none; }
.uset-actions { margin-top: 14px; }

/* Per-target apply mode: row (label/hint left, segmented control right) + the
   Gemini segmented control itself (tonal track, accent-filled active pill). */
.uset-apply { display: flex; flex-direction: column; }
.uset-apply.is-disabled { opacity: 0.45; pointer-events: none; }
.uset-apply-row {
  display: flex; align-items: center; gap: 16px; padding: 11px 0;
}
.uset-apply-row + .uset-apply-row { border-top: 1px solid color-mix(in srgb, var(--border) 55%, transparent); }
.uset-seg {
  flex: none; display: inline-flex; align-items: center; gap: 2px;
  background: var(--bg-elev-3); border-radius: 999px; padding: 3px;
}
.uset-seg-btn {
  appearance: none; border: none; cursor: pointer; font: inherit;
  font-size: 12.5px; font-weight: 500; line-height: 1; white-space: nowrap;
  color: var(--text-faint); background: transparent;
  padding: 7px 14px; border-radius: 999px;
  display: inline-flex; align-items: center; justify-content: center; gap: 5px;
  transition: background 0.18s var(--ease), color 0.18s var(--ease), box-shadow 0.18s var(--ease);
}
/* M3-style leading check on the selected segment — slides in with the tonal fill. */
.uset-seg-btn::before {
  content: "check"; font-family: "Material Symbols Rounded"; font-size: 14px; line-height: 1;
  max-width: 0; opacity: 0; overflow: hidden;
  transition: max-width 0.18s var(--ease), opacity 0.18s var(--ease);
}
.uset-seg-btn:hover { color: var(--text); }
.uset-seg-btn.is-active {
  /* Soft tonal thumb (iOS/Gemini style) instead of a full-contrast accent fill. */
  background: color-mix(in srgb, var(--accent) 16%, var(--bg-elev-2));
  color: var(--text);
  box-shadow: 0 1px 3px color-mix(in srgb, #000 25%, transparent);
}
.uset-seg-btn.is-active::before { max-width: 14px; opacity: 1; }
/* Narrow screens: the label column and the segmented control can't share a row
   (the label squeezes to one word per line) — stack them, control full-width. */
@media (max-width: 540px) {
  .uset-apply-row { flex-direction: column; align-items: stretch; gap: 10px; }
  .uset-apply-row .uset-seg { display: flex; width: 100%; }
  .uset-apply-row .uset-seg-btn { flex: 1 1 0; text-align: center; }
}
.uset-seg-btn:focus-visible {
  outline: none; box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 30%, transparent);
}

.uset .improve-list { display: flex; flex-direction: column; gap: 8px; margin: 4px 0 0; padding: 0; list-style: none; }
.uset .improve-item { background: var(--bg-elev-2); border: none; border-radius: var(--radius-md); padding: 13px 15px; }

/* ── Account screens (Profile / Team / Settings / Admin) ─────────────────────
   These reuse the modal section look (.settings-section / .billing-*) inside the
   standalone screen scaffold (.sched-center). Neutralize the modal-only chrome
   (side padding, inner scroll caps) so sections align with the intro. */
/* NOTE: #admin-view is intentionally excluded — the admin panel renders each
   .settings-section as a padded card (see `.admin-body .settings-section`), so it
   must NOT get this edge-to-edge, zero-horizontal-padding modal treatment. */
#profile-view .settings-section,
#team-view .settings-section,
#settings-view .settings-section {
  padding: 22px 0;
  border-bottom: 1px solid var(--border);
}
#profile-view .settings-section:last-child,
#team-view .settings-section:last-child,
#settings-view .settings-section:last-child { border-bottom: none; }
#admin-view .billing-body { max-height: none; overflow: visible; }
#admin-view .billing-note { padding: 16px 0; }

/* Copy button beside an info-row value/code (Profile + Team). */
.profile-copy {
  display: inline-flex; align-items: center; justify-content: center;
  background: transparent; border: none; color: var(--text-faint); cursor: pointer;
  min-width: 40px; min-height: 40px; padding: 2px; border-radius: 999px; margin-left: 2px;
  transition: color var(--ease) 120ms, background var(--ease) 120ms;
}
.profile-copy:hover { color: var(--text); background: var(--bg-elev-2); }
.profile-copy .material-symbols-rounded { font-size: 16px; }

/* ── Profile screen (profile.ui.ts) — Gemini identity hero + tonal tiles ──────
   A lettered avatar on the signature blue→purple→pink gradient (email + role
   pill) over a softly gradient-lit card (mirrors .wallet-hero), then a column of
   tonal detail tiles for the copyable user id / invite code / wallet address. */
.profile-hero-slot { margin: 8px 0 6px; }
.profile-hero {
  position: relative;
  display: flex; flex-direction: column; align-items: center; gap: 13px;
  padding: 34px 20px 28px;
  border-radius: var(--radius-hero);
  background:
    radial-gradient(125% 80% at 50% -10%, color-mix(in srgb, var(--grad-b) 18%, transparent), transparent 62%),
    var(--bg-elev-1);
  text-align: center;
}
.profile-avatar {
  display: grid; place-items: center;
  width: 88px; height: 88px; border-radius: 50%;
  font-family: var(--font-display);
  font-size: 38px; font-weight: 500; line-height: 1;
  color: #fff;
  background: linear-gradient(135deg, var(--grad-a), var(--grad-b) 52%, var(--grad-c));
  box-shadow: 0 8px 26px color-mix(in srgb, var(--grad-b) 40%, transparent);
}
.profile-hero-identity {
  display: flex; flex-direction: column; align-items: center; gap: 3px; max-width: 100%;
}
.profile-hero-email {
  font-family: var(--font-display);
  font-size: 20px; font-weight: 500; letter-spacing: -0.2px;
  color: var(--text); word-break: break-all; max-width: 100%;
}
.profile-hero-sub { font-size: 13px; color: var(--text-faint); word-break: break-all; }
.profile-role-pill {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 5px 13px 5px 10px; border-radius: 999px;
  background: var(--bg-elev-2); color: var(--text-dim);
  font-size: 12.5px; font-weight: 600; letter-spacing: 0.2px;
}
.profile-role-pill .material-symbols-rounded { font-size: 16px; }
.profile-role-pill.is-admin {
  background: color-mix(in srgb, var(--grad-b) 24%, var(--bg-elev-2)); color: var(--text);
}

/* Tonal detail tiles. */
.profile-detail-list { display: flex; flex-direction: column; gap: 8px; }
.profile-detail {
  display: flex; align-items: center; gap: 14px;
  padding: 12px 14px; border-radius: var(--radius);
  background: var(--bg-elev-1);
  transition: background 0.15s var(--ease);
}
.profile-detail:hover { background: var(--bg-elev-2); }
/* Editable tile (Your name): the whole row is the tap target, not just the pencil. */
.profile-detail.is-editable { cursor: pointer; }
.profile-detail.is-editable:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.profile-detail.is-editable:has(.profile-name-input) { cursor: default; }
.profile-detail-icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 38px; height: 38px; flex: none; border-radius: var(--radius-tile);
  background: color-mix(in srgb, var(--accent) 14%, var(--bg-elev-2)); color: var(--text-dim);
}
.profile-detail-icon .material-symbols-rounded { font-size: 20px; }
.profile-detail-main { flex: 1 1 auto; min-width: 0; }
.profile-detail-label {
  font-size: 11.5px; font-weight: 600; letter-spacing: 0.5px; text-transform: uppercase;
  color: var(--text-faint);
}
.profile-detail-value { font-size: 14.5px; color: var(--text); margin-top: 2px; word-break: break-all; }
.profile-detail-value.is-mono { font-family: var(--font-mono); font-size: 13px; }
.profile-detail-sub { font-size: 12px; margin-top: 3px; }
.profile-detail-sub.is-ok { color: var(--ok); }
.profile-detail-sub.is-muted { color: var(--text-faint); }
.profile-detail-copy {
  display: inline-flex; align-items: center; justify-content: center; flex: none;
  width: 40px; height: 40px; border-radius: 50%; border: none; cursor: pointer;
  background: transparent; color: var(--text-faint);
  transition: color 0.15s var(--ease), background 0.15s var(--ease);
}
.profile-detail-copy:hover { color: var(--text); background: var(--bg-elev-3); }
.profile-detail-copy:disabled { opacity: 0.5; cursor: default; }
.profile-detail-copy .material-symbols-rounded { font-size: 18px; }
.profile-detail-copy.is-primary { color: var(--accent); }
.profile-detail-copy.is-primary:hover:not(:disabled) {
  color: var(--accent); background: color-mix(in srgb, var(--accent) 16%, transparent);
}

/* Editable display-name tile. */
.profile-detail-value.is-placeholder { color: var(--text-faint); }
.profile-name-actions { display: inline-flex; align-items: center; gap: 4px; flex: none; }
.profile-name-input {
  width: 100%; margin-top: 3px; box-sizing: border-box;
  font-family: inherit; font-size: 14.5px; color: var(--text);
  background: var(--bg-elev-3); border: none; border-radius: 8px; padding: 7px 10px;
}
.profile-name-input::placeholder { color: var(--text-faint); }
.profile-name-input:focus {
  outline: none;
  box-shadow: inset 0 0 0 1.5px color-mix(in srgb, var(--accent) 45%, transparent);
}

/* Pending agent wallet approvals. */
.profile-actions-hint { margin: 14px 0 0; }
.profile-actions { display: flex; flex-direction: column; gap: 8px; margin-top: 10px; }
.profile-action-row {
  display: flex; align-items: center; justify-content: space-between; gap: 14px;
  padding: 12px 14px; border-radius: var(--radius); background: var(--bg-elev-1);
}
.profile-action-what { font-size: 13.5px; color: var(--text); min-width: 0; word-break: break-word; }
.profile-action-btns { flex: none; display: inline-flex; gap: 8px; }
.profile-action-btns .skills-action { padding: 6px 14px; font-size: 12.5px; }

/* Team invite codes + create action. */
.team-code { font-family: var(--font-mono); font-size: 13.5px; color: var(--text); }
.team-actions { margin-top: 14px; }

/* Team screen — Gemini referral-count hero + tonal cards (matches profile/earn),
   replacing the old hard-bordered settings-form look. */
.team-hero {
  max-width: 560px;
  background: var(--bg-elev-1);
  border-radius: var(--radius-lg);
  padding: 22px 22px 20px;
  margin-bottom: 14px;
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent) 10%, transparent);
}
.team-hero-value { font-family: var(--font-display); font-size: 44px; font-weight: 700; line-height: 1.05; color: var(--text); }
.team-hero-label { font-size: 12.5px; font-weight: 600; letter-spacing: 0.5px; text-transform: uppercase; color: var(--text-dim); margin-top: 2px; }
.team-hero-sub { display: inline-flex; align-items: center; gap: 6px; margin-top: 14px; font-size: 13px; color: var(--text-faint); }
.team-hero-sub .material-symbols-rounded { font-size: 17px; }
/* Tonal cards + borderless rows for the Team screen (standalone view + embedded tab). */
#team-view .settings-section,
.team-embed .settings-section {
  background: var(--bg-elev-1);
  border: none;
  border-radius: var(--radius-lg);
  padding: 18px 20px;
  margin: 0 0 14px;
  max-width: 560px;
}
#team-view .settings-section h3,
.team-embed .settings-section h3 {
  margin: 0 0 6px; font-size: 12px; font-weight: 600;
  letter-spacing: 0.5px; text-transform: uppercase; color: var(--text-dim);
}
#team-view .info-row,
.team-embed .info-row { border-bottom: none; padding: 11px 0; }
#team-view .info-row + .info-row,
.team-embed .info-row + .info-row { border-top: 1px solid var(--border); }

/* ===================================================================
   Earn screen redesign (earnings.ui.ts) — hero + referral/yield sheets.
   Reuses .earnings-topbar/.earnings-scroll/.earnings-overview/.earn-tile/
   .earn-rank-* and adds the hero, gauges, invite, team, market, search +
   chips below. The Activity feed + Leaderboard are embedded inside the
   Referral/Yield sheets (not a top-level tab), so they never duplicate the
   Wallet screen's own Activity tab. */

/* Hero: total earned + breakdown + the cash-out/reinvest pockets, all one card — the
   pockets ARE the total, just split spendable-now vs locked, not a separate surface. */
.earnings-hero {
  background: var(--bg-elev-1);
  border-radius: var(--radius-lg);
  padding: 20px 22px;
  display: flex; flex-direction: column; justify-content: center;
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent) 12%, transparent);
}
.earnings-hero-label {
  font-size: 12.5px; font-weight: 600; letter-spacing: 0.6px;
  text-transform: uppercase; color: var(--text-dim);
}
.earnings-hero-total {
  font-family: var(--font-display);
  font-size: 44px; font-weight: 700; line-height: 1.05; margin-top: 6px;
  background: var(--grad-h); -webkit-background-clip: text; background-clip: text; color: transparent;
}
/* Source breakdown (Referral / Yield) — TIER 3: quiet navigation into the detail sheets,
   not headline stats. Deliberately recessive (flat, muted, label-led) so it doesn't fight
   the hero total above it or the action pockets below it. */
.earnings-hero-breakdown { display: flex; gap: 8px; margin-top: 14px; }
.earnings-bd-chip {
  flex: 1; display: flex; align-items: center; gap: 8px;
  background: transparent; border: 1px solid var(--border); border-radius: var(--radius-md);
  padding: 8px 8px 8px 11px; min-width: 0;
  cursor: pointer; text-align: left; font: inherit; color: inherit;
  transition: background var(--ease) 130ms, transform var(--ease) 130ms;
}
.earnings-bd-chip:hover { background: var(--bg-elev-1); }
.earnings-bd-chip:active { transform: scale(0.985); }
.earnings-bd-main { min-width: 0; display: flex; flex-direction: column-reverse; }
.earnings-bd-chip .earnings-bd-chev { margin-left: auto; flex: none; font-size: 18px; color: var(--text-faint); }
.earnings-bd-icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 22px; height: 22px; flex: none; color: var(--text-faint);
}
.earnings-bd-icon .material-symbols-rounded { font-size: 17px; }
/* Label leads (normal weight), amount is the small secondary line. */
.earnings-bd-label { font-size: 12.5px; font-weight: 600; color: var(--text-dim); }
.earnings-bd-amount { font-size: 11.5px; font-weight: 600; color: var(--text-faint); font-variant-numeric: tabular-nums; margin-top: 1px; }

/* Withdraw / claim CTA row. */
.earnings-claim {
  display: flex; align-items: center; justify-content: space-between; gap: 14px;
  margin-top: 16px; padding-top: 16px; border-top: 1px solid var(--border);
}
.earnings-claim-meta { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.earnings-claim-label { font-size: 11.5px; color: var(--text-faint); text-transform: uppercase; letter-spacing: 0.5px; }
.earnings-claim-amount { font-size: 20px; font-weight: 700; color: var(--text); font-variant-numeric: tabular-nums; }
.earnings-claim-pending { font-size: 11.5px; color: var(--warn); }
.earnings-claim-btn {
  display: inline-flex; align-items: center; gap: 7px; flex: none;
  border: none; cursor: pointer; border-radius: 999px; padding: 11px 20px;
  font-family: var(--font-ui); font-size: 14px; font-weight: 600;
  background: var(--grad); color: var(--on-accent);
  transition: filter var(--ease) 140ms, opacity var(--ease) 140ms;
}
.earnings-claim-btn:hover:not(:disabled) { filter: brightness(1.08); }
.earnings-claim-btn:disabled { opacity: 0.45; cursor: default; }
.earnings-claim-btn .material-symbols-rounded { font-size: 18px; }

/* ── Genesis Giveaway hero (top of the Earn screen) ─────────────────────────
   The ONE card that breaks the calm mono palette. Deep restrained violet gradient
   (premium depth), a warm champagne glow + glassy highlight for richness (not just
   text), and ONE accent — gold, reserved strictly for the prize money. */
.earn-jackpot-promo {
  position: relative; overflow: hidden;
  border-radius: var(--radius-lg); padding: 22px 22px 20px;
  display: flex; flex-direction: column; gap: 2px;
  color: #fff;
  background:
    radial-gradient(135% 120% at 14% 0%, rgba(255, 255, 255, 0.22) 0%, transparent 52%),
    linear-gradient(140deg, #2e1065 0%, #5b21b6 34%, #7c3aed 64%, #9d2d8f 100%);
  background-size: 135% 120%, 240% 240%;
  background-position: 0% 0%, 0% 50%;
  border: 1px solid rgba(255, 255, 255, 0.16);
  box-shadow: 0 20px 48px -18px rgba(46, 16, 101, 0.7), inset 0 1px 0 rgba(255, 255, 255, 0.16);
  animation: earn-jackpot-flow 20s ease-in-out infinite;
}
/* Diagonal shine sweep. */
.earn-jackpot-promo::before {
  content: ""; position: absolute; top: -25%; left: -75%;
  width: 45%; height: 150%; pointer-events: none; z-index: 1;
  background: linear-gradient(100deg, transparent, rgba(255, 255, 255, 0.35), transparent);
  transform: skewX(-18deg);
  animation: earn-jackpot-shine 6s var(--ease) 1.4s infinite;
}
/* Warm champagne glow in the lower-right — depth + a quiet tie to the gold money. */
.earn-jackpot-promo::after {
  content: ""; position: absolute; right: -15%; bottom: -28%;
  width: 66%; height: 78%; pointer-events: none; z-index: 0;
  background: radial-gradient(circle at center, rgba(255, 206, 120, 0.22) 0%, transparent 62%);
}
.earn-jackpot-promo > * { position: relative; z-index: 2; }
@keyframes earn-jackpot-shine { 0% { left: -75%; } 24% { left: 135%; } 100% { left: 135%; } }
@keyframes earn-jackpot-flow {
  0%, 100% { background-position: 0% 0%, 0% 50%; }
  50% { background-position: 0% 0%, 100% 50%; }
}
@media (prefers-reduced-motion: reduce) {
  .earn-jackpot-promo { animation: none; }
  .earn-jackpot-promo::before { animation: none; }
}
.earn-jackpot-promo-head { position: relative; display: flex; align-items: center; gap: 12px; }
.earn-jackpot-promo-label {
  display: inline-flex; align-items: center; gap: 7px;
  font-size: 12.5px; font-weight: 700; letter-spacing: 0.7px; text-transform: uppercase; color: rgba(255, 244, 230, 0.78);
}
/* The headline IS the money → metallic champagne gold (with a soft drop shadow for
   depth, so it reads as an object, not flat text). The only big gold on the card. */
.earn-jackpot-promo-amount {
  position: relative; font-family: var(--font-display);
  font-size: clamp(42px, 12vw, 56px); font-weight: 800; line-height: 1.02; margin: 6px 0 2px;
  background: linear-gradient(135deg, #fff6da 0%, #ffe2a0 44%, #f4b95a 100%);
  -webkit-background-clip: text; background-clip: text;
  color: transparent; -webkit-text-fill-color: transparent;
  filter: drop-shadow(0 2px 14px rgba(0, 0, 0, 0.28));
}
.earn-jackpot-promo .earnings-progress { position: relative; margin-top: 14px; }
.earn-jackpot-promo .earnings-progress-track { background: rgba(255, 255, 255, 0.22); }
.earn-jackpot-promo .earnings-progress-bar { background: linear-gradient(90deg, rgba(255, 255, 255, 0.85), #ffffff); }
.earn-jackpot-promo .earnings-progress-meta { color: rgba(255, 255, 255, 0.75); }
.earn-jackpot-promo .earnings-progress-meta strong { color: #fff; }

/* Premium CTA — one clean solid-white button: benefit line + the code in a single
   violet accent, a quiet copy glyph, and a soft breathing halo. No tile, no chip. */
.earn-jackpot-cta {
  position: relative; display: flex; align-items: center; gap: 12px; width: 100%;
  margin-top: 16px; padding: 12px 16px; border-radius: var(--radius-md); cursor: pointer;
  background: #fff; border: none; color: #1a1430; font: inherit; text-align: left;
  box-shadow: 0 8px 22px -12px rgba(0, 0, 0, 0.5);
  transition: transform var(--ease) 130ms, filter var(--ease) 130ms;
  animation: earn-cta-pulse 3s ease-in-out infinite;
}
.earn-jackpot-cta:hover { filter: brightness(0.98); }
.earn-jackpot-cta:active { transform: scale(0.99); }
@keyframes earn-cta-pulse {
  0%, 100% { box-shadow: 0 8px 22px -12px rgba(0, 0, 0, 0.5), 0 0 0 0 rgba(255, 255, 255, 0); }
  50% { box-shadow: 0 8px 22px -12px rgba(0, 0, 0, 0.5), 0 0 0 4px rgba(255, 255, 255, 0.16); }
}
@media (prefers-reduced-motion: reduce) { .earn-jackpot-cta { animation: none; } }
.earn-jackpot-cta-main { min-width: 0; flex: 1 1 auto; }
.earn-jackpot-cta-title { font-size: 14.5px; font-weight: 700; color: #1a1430; letter-spacing: -0.1px; }
.earn-jackpot-cta-code { display: flex; align-items: baseline; gap: 7px; margin-top: 2px; }
.earn-jackpot-cta-code-label { font-size: 10.5px; font-weight: 600; letter-spacing: 0.4px; text-transform: uppercase; color: rgba(26, 20, 48, 0.5); }
.earn-jackpot-cta-code-val { font-family: var(--font-mono); font-size: 14px; font-weight: 700; letter-spacing: 1.5px; color: #5b21b6; }
.earn-jackpot-cta-go { flex: none; display: inline-flex; align-items: center; color: #5b21b6; }
.earn-jackpot-cta-go .material-symbols-rounded { font-size: 20px; }

/* Deadline badge — quiet date chip under the amount (no days-left pill). */
.earn-jackpot-deadline {
  position: relative; display: inline-flex; align-items: center; gap: 7px; align-self: flex-start;
  margin-top: 10px; padding: 6px 12px; border-radius: 999px;
  background: rgba(0, 0, 0, 0.2); border: 1px solid rgba(255, 255, 255, 0.2);
  font-size: 12.5px; color: rgba(255, 255, 255, 0.92);
}
.earn-jackpot-deadline .material-symbols-rounded { font-size: 17px; color: rgba(255, 255, 255, 0.78); }
.earn-jackpot-deadline-date { font-weight: 600; }
.earn-jackpot-deadline.is-urgent { border-color: rgba(255, 209, 92, 0.55); }
.earn-jackpot-deadline.is-urgent .earn-jackpot-deadline-date { color: #ffd98a; }

/* "How it works" disclosure — admin-configured conditions + prize tiers + note. */
.earn-jackpot-how-wrap { position: relative; margin-top: 14px; }
.earn-jackpot-how-btn {
  display: inline-flex; align-items: center; gap: 5px; padding: 2px 0;
  background: none; border: none; cursor: pointer; font: inherit;
  font-size: 12px; font-weight: 600; color: rgba(255, 255, 255, 0.78);
}
.earn-jackpot-how-btn:hover { color: rgba(255, 255, 255, 0.95); }
.earn-jackpot-how-btn .material-symbols-rounded { font-size: 17px; }
.earn-jackpot-how-chev { transition: transform 0.2s var(--ease); }
.earn-jackpot-how-btn.is-open .earn-jackpot-how-chev { transform: rotate(180deg); }
.earn-jackpot-how { margin-top: 8px; }
.earn-jackpot-how.is-collapsed { display: none; }
.earn-jackpot-how-cap {
  font-size: 11px; font-weight: 700; letter-spacing: 0.4px; text-transform: uppercase;
  color: rgba(255, 255, 255, 0.78); margin: 10px 0 6px;
}
.earn-jackpot-how-rule { margin: 0 0 4px; font-size: 12.5px; line-height: 1.55; color: rgba(255, 255, 255, 0.86); }
.earn-jackpot-conditions { display: flex; flex-direction: column; gap: 5px; }
.earn-jackpot-condition { display: flex; align-items: flex-start; gap: 7px; font-size: 12.5px; line-height: 1.4; color: rgba(255, 255, 255, 0.92); }
.earn-jackpot-condition .material-symbols-rounded { font-size: 17px; color: #ffe08a; flex: none; margin-top: 0.5px; }
.earn-jackpot-prizes { display: flex; flex-direction: column; gap: 9px; }
.earn-jackpot-prize {
  display: flex; align-items: center; gap: 14px;
  padding: 12px 14px; border-radius: var(--radius-md); background: rgba(0, 0, 0, 0.22);
}
/* Big champagne-gold prize figures — the exciting part. */
.earn-jackpot-prize-amt {
  flex: none; min-width: 96px;
  font-family: var(--font-display); font-weight: 800; font-size: 25px;
  line-height: 1; letter-spacing: -0.5px; font-variant-numeric: tabular-nums;
  background: linear-gradient(135deg, #fff6da 0%, #ffe2a0 44%, #f4b95a 100%);
  -webkit-background-clip: text; background-clip: text;
  color: transparent; -webkit-text-fill-color: transparent;
}
.earn-jackpot-prize-main { min-width: 0; }
.earn-jackpot-prize-label { font-size: 13px; font-weight: 700; color: #fff; }
.earn-jackpot-prize-desc { font-size: 12px; line-height: 1.45; color: rgba(255, 255, 255, 0.86); margin-top: 2px; }
.earn-jackpot-note { margin: 10px 0 0; font-size: 11.5px; line-height: 1.45; color: rgba(255, 255, 255, 0.74); }

/* ── Referral / yield slide-in detail sheet ────────────────────────────────
   Opened from the total-earned card's breakdown buttons. Slides in from the
   right (matches the session panel); full-width on mobile. */
.earn-sheet-overlay {
  position: fixed; inset: 0; z-index: 1100; display: flex; justify-content: flex-end;
  background: rgba(0, 0, 0, 0); transition: background 0.26s var(--ease);
}
.earn-sheet-overlay.is-open { background: rgba(0, 0, 0, 0.5); backdrop-filter: blur(2px); }
.earn-sheet {
  display: flex; flex-direction: column;
  width: min(480px, 100%); height: 100%;
  background: var(--bg-elev); box-shadow: var(--shadow-lg);
  transform: translateX(100%); transition: transform 0.28s var(--ease);
}
.earn-sheet-overlay.is-open .earn-sheet { transform: translateX(0); }
/* Admin "Details" sheet only (admin-bi.ui.ts) — wide enough on desktop to hold a real
   data table (7 metric columns + a 4-button per-row action cell) without the actions
   collapsing into a vertical stack; the earnings screen's own sheet usage is untouched
   (stays 480px-capped). */
@media (min-width: 721px) {
  .earn-sheet.is-wide { width: min(1240px, 96vw); }
}
.earn-sheet-bar {
  flex: 0 0 auto; display: flex; align-items: center; gap: 8px;
  padding: 12px 14px; border-bottom: 1px solid var(--border); background: var(--bg-elev);
}
/* Title takes the middle so any trailing element (e.g. Power) pins to the right. */
.earn-sheet-title { flex: 1 1 auto; min-width: 0; font-size: 17px; font-weight: 600; color: var(--text); }
/* Back chevron, top-left (replaces the close X). */
.earn-sheet-back {
  flex: none; width: 36px; height: 36px; border-radius: 999px; cursor: pointer; border: none;
  background: transparent; color: var(--text-dim); display: inline-grid; place-items: center;
  transition: background var(--ease) 120ms, color var(--ease) 120ms;
}
.earn-sheet-back:hover { background: var(--bg-elev-2); color: var(--text); }
.earn-sheet-back .material-symbols-rounded { font-size: 24px; }
.earn-sheet-power { flex: none; display: inline-flex; align-items: center; }
.earn-sheet-body { flex: 1 1 auto; min-height: 0; overflow-y: auto; padding: 18px; }
/* First section heading inside a sheet shouldn't carry the big top margin. */
.earn-sheet-body > div > .earnings-section-head:first-child { margin-top: 4px; }
/* Admin "Details" sheet tab strip (Overview/Activity/Agents) — reuses .buy-chip's
   pill-toggle look verbatim, just needs its own row layout. */
.earn-sheet-tabs { display: flex; gap: 6px; margin-bottom: 16px; }

/* Yield-agent subscription progress ring (days left out of the 30-day window). */
/* ── Yield tab: compact Power chip + taller agent cards ───────────────────── */
/* Agents-section header meta: "N agents | ⚡ 4,961". */
.yield-agents-meta { display: inline-flex; align-items: center; gap: 9px; }
.yield-meta-sep { width: 1px; height: 12px; background: var(--border-strong); flex: none; }
/* Power balance as a ⚡ + number chip (the word "Power" is never shown). Taps → Store. */
.yield-power-chip {
  display: inline-flex; align-items: center; gap: 4px; cursor: pointer;
  border: none; background: none; font: inherit; padding: 2px 2px;
  font-size: 13px; font-weight: 700; color: var(--text); font-variant-numeric: tabular-nums;
  transition: color var(--ease) 120ms;
}
.yield-power-chip:hover { color: var(--accent); }
.yield-power-chip .material-symbols-rounded { font-size: 17px; color: #f0b94a; }
.yield-power-chip.is-empty { color: var(--accent); font-weight: 600; }

/* One tall card per owned agent. */
.yield-cards { display: flex; flex-direction: column; gap: 10px; }
.yield-card {
  display: flex; flex-direction: column; gap: 12px;
  padding: 14px 16px 12px; border-radius: var(--radius); background: var(--bg-elev-1);
  box-shadow: inset 0 0 0 1px var(--border);
}
.yield-card.is-lapsed { box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--warn) 40%, transparent); }
.yield-card-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.yield-card-name { font-size: 15.5px; font-weight: 600; color: var(--text); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* (the star tier renders via the shared .star-pill — see src/web/star.ts) */
/* (b) the three numbers that matter */
.yield-card-stats { display: flex; gap: 8px; }
.yield-card-stat { flex: 1 1 0; min-width: 0; background: var(--bg-elev-2); border-radius: var(--radius-sm); padding: 10px 8px; text-align: center; }
.yield-card-stat-value { font-size: 16px; font-weight: 700; color: var(--text); font-variant-numeric: tabular-nums; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.yield-card-stat-label { font-size: 11px; color: var(--text-faint); margin-top: 3px; }
/* Earn-back progress (revenue model v2 §5): gross generated vs purchase price. */
.yield-payback { display: flex; flex-direction: column; gap: 5px; }
.yield-payback-row { display: flex; justify-content: space-between; align-items: baseline; gap: 8px; font-size: 12px; }
.yield-payback-label { font-weight: 600; color: var(--text-dim); }
.yield-payback.is-done .yield-payback-label { color: var(--ok); }
.yield-payback-nums { color: var(--text-faint); font-variant-numeric: tabular-nums; }
.yield-payback-track { height: 5px; border-radius: 999px; background: var(--bg-elev-2); overflow: hidden; }
.yield-payback-fill { height: 100%; width: 0; border-radius: inherit; background: linear-gradient(90deg, #0036ff, #c600ff); transition: width 0.6s ease; }
.yield-payback.is-done .yield-payback-fill { background: var(--ok); }
/* Appreciation line: new-agent tranche price vs what this one cost. */
.yield-apprec { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; color: var(--ok); }
.yield-apprec .material-symbols-rounded { font-size: 16px; }
/* (c) time left + extend */
.yield-card-foot { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding-top: 11px; border-top: 1px solid var(--border); }
.yield-card-status { display: inline-flex; align-items: center; gap: 6px; font-size: 13px; font-weight: 600; color: var(--text-dim); }
.yield-card-status .material-symbols-rounded { font-size: 18px; }
.yield-card-status.is-lapsed { color: var(--warn); }
/* Extend CTA: two segments — "+30 days" | "39 ⚡" — split by a divider. */
.yield-card-extend {
  flex: none; display: inline-flex; align-items: stretch; cursor: pointer;
  border: none; border-radius: 999px; overflow: hidden; font: inherit; font-size: 13px; font-weight: 700;
  background: var(--grad); color: var(--on-accent); transition: filter var(--ease) 130ms;
}
.yield-card-extend:hover { filter: brightness(1.06); }
.yield-card-extend-gain { display: inline-flex; align-items: center; padding: 9px 12px; }
.yield-card-extend-cost {
  display: inline-flex; align-items: center; gap: 3px; padding: 9px 13px 9px 11px;
  border-left: 1px solid color-mix(in srgb, var(--on-accent) 22%, transparent);
  font-variant-numeric: tabular-nums;
}
.yield-card-extend-cost .material-symbols-rounded { font-size: 17px; }

/* Tile icons (referral/yield dashboards). */
.earn-tile-icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 26px; height: 26px; margin: 0 auto 6px; border-radius: var(--radius-tile);
  background: color-mix(in srgb, var(--accent) 14%, var(--bg-elev-1)); color: var(--accent);
}
.earn-tile-icon .material-symbols-rounded { font-size: 16px; }

/* Section labels + meta. */
.earnings-section-label { font-size: 12.5px; font-weight: 600; letter-spacing: 0.5px; text-transform: uppercase; color: var(--text-dim); }
.earnings-section-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; margin: 22px 0 10px; }
.earnings-section-meta { font-size: 12px; color: var(--text-faint); }

/* Reward-pool label + tier-name with leading icons (scoped so partner.ui is untouched). */
.earnings-screen .earnings-overview-label,
.earnings-screen .partner-tier-name { display: inline-flex; align-items: center; gap: 7px; }
.earnings-screen .partner-tier { margin-bottom: 12px; }

/* Tier qualification gauges. */
.earnings-gauges { display: flex; flex-direction: column; gap: 12px; margin-top: 14px; }
.earnings-gauge-head { display: flex; align-items: baseline; justify-content: space-between; font-size: 12.5px; color: var(--text-dim); margin-bottom: 6px; }
.earnings-gauge-num { color: var(--text); font-weight: 600; font-variant-numeric: tabular-nums; }
.earnings-mini-track { height: 8px; }

/* Invite-code card. */
.earnings-invite { background: var(--bg-elev-1); border-radius: var(--radius); padding: 16px 18px; margin-top: 14px; }
.earnings-invite-main { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.earnings-invite-label { font-size: 12px; color: var(--text-faint); text-transform: uppercase; letter-spacing: 0.5px; }
.earnings-invite-code { display: flex; align-items: center; gap: 6px; }
.earnings-invite-code .team-code { font-size: 18px; letter-spacing: 1px; }
.earnings-invite-hint { font-size: 12.5px; color: var(--text-dim); margin-top: 8px; line-height: 1.5; }

/* List-row leading icon + negative amounts. */
.earnings-row-icon {
  display: inline-flex; align-items: center; justify-content: center; flex: none;
  width: 36px; height: 36px; border-radius: var(--radius-tile);
  background: var(--bg-elev-2); color: var(--text-dim);
}
.earnings-row-icon .material-symbols-rounded { font-size: 19px; }
/* Qualified daily-pool row: green check. */
.earnings-row-icon.is-qualified { background: color-mix(in srgb, var(--ok) 18%, var(--bg-elev-1)); color: var(--ok); }
.earnings-row-amount.is-neg { color: var(--text-faint); }

/* Explainer notes. */
.earnings-note { font-size: 12.5px; color: var(--text-dim); background: var(--bg-elev-1); border-radius: var(--radius-sm); padding: 12px 14px; margin: 12px 0; line-height: 1.5; }
.earnings-note-split { display: flex; flex-direction: column; gap: 4px; }
.earnings-note strong { color: var(--text); }

/* ====================== Node-tier badges & referral upgrades ===============
   A cohesive metal family, premium escalating: Regular (graphite) → Light (silver)
   → Master (gold) → Super (polished black-diamond). Identities fixed across themes. */
.tier-badge {
  position: relative; flex: none; overflow: hidden;
  display: inline-flex; align-items: center; justify-content: center;
  color: #1b1b1b;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.4), inset 0 0 0 1px rgba(255, 255, 255, 0.08), 0 3px 10px rgba(0, 0, 0, 0.3);
}
.tier-badge .material-symbols-rounded { position: relative; z-index: 1; font-variation-settings: "FILL" 1; }
.tier-badge-shine {
  position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background: linear-gradient(150deg, rgba(255, 255, 255, 0.5), rgba(255, 255, 255, 0) 48%);
  mix-blend-mode: screen;
}
.tier-badge--lg { width: 54px; height: 54px; border-radius: var(--radius); }
.tier-badge--lg .material-symbols-rounded { font-size: 28px; }
.tier-badge--sm { width: 38px; height: 38px; border-radius: var(--radius-tile); }
.tier-badge--sm .material-symbols-rounded { font-size: 20px; }
.tier-badge--regular { background: linear-gradient(145deg, #9aa3af, #646b78); color: #f3f4f6; }
.tier-badge--light { background: linear-gradient(145deg, #e8edf3, #a7b2c0); color: #2b333f; }
.tier-badge--master { background: linear-gradient(145deg, #f6d98b, #d2a23c); color: #4a360f; }
.tier-badge--super { background: linear-gradient(150deg, #2c3242, #0f1219); color: #dbe6ff;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.18), inset 0 0 0 1px rgba(150, 180, 255, 0.2), 0 3px 14px rgba(70, 110, 200, 0.4);
}
.tier-badge--super .material-symbols-rounded { text-shadow: 0 0 10px rgba(140, 180, 255, 0.7); }

/* Current-tier hero block: card + the "All tiers" benefits disclosure. */
.tier-block { display: flex; flex-direction: column; }
.tier-card { display: flex; flex-direction: column; }
.tier-card-top { display: flex; align-items: flex-start; gap: 14px; }
.tier-card-id { flex: 1 1 auto; min-width: 0; }
.tier-card-name { font-family: var(--font-display); font-size: 1.25rem; font-weight: 650; color: var(--text); line-height: 1.12; }
.tier-card .partner-tier-rates { margin-top: 3px; }
.tier-card--light { background: linear-gradient(180deg, color-mix(in srgb, #aeb8c4 10%, var(--bg-elev-1)), var(--bg-elev-1)); }
.tier-card--master { background: linear-gradient(180deg, color-mix(in srgb, #f2c14e 12%, var(--bg-elev-1)), var(--bg-elev-1)); }
.tier-card--super {
  background: linear-gradient(180deg, color-mix(in srgb, #6c8bff 14%, var(--bg-elev-1)), var(--bg-elev-1));
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent) 22%, transparent);
}
/* Clear pill button on the badge row that opens the all-tiers comparison. */
.tier-benefits-btn {
  flex: none; display: inline-flex; align-items: center; gap: 5px;
  padding: 6px 11px; border-radius: 999px; cursor: pointer; white-space: nowrap;
  background: color-mix(in srgb, var(--accent) 14%, transparent);
  color: var(--accent); border: 1px solid color-mix(in srgb, var(--accent) 32%, transparent);
  font: inherit; font-size: 12px; font-weight: 600;
}
.tier-benefits-btn:hover { background: color-mix(in srgb, var(--accent) 22%, transparent); }
.tier-benefits-btn .material-symbols-rounded { font-size: 15px; }
.tier-learn-chev { transition: transform 0.2s var(--ease); }
.tier-benefits-btn.is-open .tier-learn-chev { transform: rotate(180deg); }
/* In-card performance dashboard (3 stats) + invite code. */
.tier-divider { height: 1px; background: color-mix(in srgb, var(--text-faint) 16%, transparent); margin: 16px 0; }
.tier-perf { display: flex; gap: 8px; }
.tier-perf-stat { flex: 1 1 0; min-width: 0; text-align: center; }
.tier-perf-icon { color: var(--text-faint); }
.tier-perf-icon .material-symbols-rounded { font-size: 18px; }
.tier-perf-value { font-family: var(--font-display); font-size: clamp(15px, 4.6vw, 20px); font-weight: 700; color: var(--text); font-variant-numeric: tabular-nums; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.tier-perf-label { font-size: 11px; color: var(--text-faint); margin-top: 3px; line-height: 1.3; }
.tier-invite {
  display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap;
  margin-top: 16px; padding-top: 14px; border-top: 1px solid color-mix(in srgb, var(--text-faint) 16%, transparent);
}
.tier-invite-label { font-size: 12px; color: var(--text-faint); text-transform: uppercase; letter-spacing: 0.5px; }
.tier-invite-code { display: flex; align-items: center; gap: 8px; }
.tier-invite-code .team-code { font-size: 17px; letter-spacing: 1px; }

/* All-tiers benefits ladder (revealed by "Compare all tiers"). */
.tier-ladder { margin-top: 10px; display: flex; flex-direction: column; gap: 8px; }
.tier-ladder.is-collapsed { display: none; }
.tier-rung {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 14px; border-radius: var(--radius-md); background: var(--bg-elev-1); border: 1px solid transparent;
}
.tier-rung:not(.is-current):not(.is-achieved) { opacity: 0.78; }
.tier-rung.is-current {
  border-color: color-mix(in srgb, var(--accent) 55%, transparent);
  background: color-mix(in srgb, var(--accent) 8%, var(--bg-elev-1));
}
.tier-rung-main { flex: 1 1 auto; min-width: 0; }
.tier-rung-name { display: flex; align-items: center; gap: 8px; font-weight: 600; color: var(--text); }
.tier-rung-req { font-size: 12px; color: var(--text-faint); margin-top: 3px; }
.tier-rung-tag {
  font-size: 11px; font-weight: 700; color: var(--accent);
  background: color-mix(in srgb, var(--accent) 16%, transparent); padding: 1px 8px; border-radius: 999px;
}
.tier-rung-mark { display: inline-flex; }
.tier-rung-mark .material-symbols-rounded { font-size: 16px; }
.tier-rung-mark.is-done { color: var(--ok); }
.tier-rung-mark.is-locked { color: var(--text-faint); }
.tier-rung-rates { display: flex; gap: 14px; flex: none; }
.tier-rung-rate { text-align: right; line-height: 1.12; }
.tier-rung-rate strong { display: block; font-size: 15px; font-weight: 700; color: var(--text); font-variant-numeric: tabular-nums; }
.tier-rung-rate span { font-size: 10.5px; text-transform: uppercase; letter-spacing: 0.04em; color: var(--text-faint); }

/* ===== Daily dividend pool: one cohesive bounded section ===== */
.pool-section { background: var(--bg-elev-1); border-radius: var(--radius-lg); overflow: hidden; }
.pool-hero {
  position: relative; overflow: hidden; padding: 20px 22px;
  background: linear-gradient(150deg, color-mix(in srgb, var(--accent-2) 22%, var(--bg-elev-2)), var(--bg-elev-2) 72%);
}
.pool-hero-glow {
  position: absolute; top: -40%; right: -18%; width: 260px; height: 260px; border-radius: 50%;
  background: radial-gradient(circle, color-mix(in srgb, var(--accent) 32%, transparent), transparent 70%); pointer-events: none;
}
.pool-hero-label {
  position: relative; display: inline-flex; align-items: center; gap: 7px;
  font-size: 12.5px; font-weight: 600; letter-spacing: 0.5px; text-transform: uppercase; color: var(--text-dim);
}
.pool-hero-label .material-symbols-rounded { font-size: 18px; }
.pool-hero-amount {
  position: relative; font-family: var(--font-display); font-size: 40px; font-weight: 700; line-height: 1.05; margin-top: 8px;
  background: var(--grad-h); -webkit-background-clip: text; background-clip: text; color: transparent;
}
.pool-hero-sub { position: relative; font-size: 12.5px; color: var(--text-dim); margin-top: 6px; }
.pool-block { padding: 14px 16px 2px; }
.pool-block-cap { font-size: 11.5px; font-weight: 600; letter-spacing: 0.5px; text-transform: uppercase; color: var(--text-faint); margin-bottom: 10px; }
.pool-rows { display: flex; flex-direction: column; gap: 6px; }
.pool-row { display: flex; align-items: center; gap: 12px; padding: 10px 12px; border-radius: var(--radius-sm); background: var(--bg-elev-2); }
.pool-row-icon {
  display: inline-flex; align-items: center; justify-content: center; flex: none;
  width: 32px; height: 32px; border-radius: var(--radius-tile); background: var(--bg-elev-3); color: var(--text-faint);
}
.pool-row-icon .material-symbols-rounded { font-size: 18px; }
/* Qualified vs locked is carried by the check/lock icon shape, not colour — keep it
   monochrome so the section reads as one calm surface. */
.pool-row-icon.is-qualified { background: color-mix(in srgb, var(--accent) 16%, var(--bg-elev-2)); color: var(--accent); }
.pool-row-main { flex: 1 1 auto; min-width: 0; }
.pool-row-title { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; font-size: 14px; font-weight: 500; color: var(--text); }
.pool-row .earnings-type { background: var(--bg-elev-3); }
.pool-row-sub { font-size: 12px; color: var(--text-faint); margin-top: 2px; }
.pool-row-fig { text-align: right; flex: none; }
/* Pool amounts are figures, not signed ledger movements — keep them neutral text. */
.pool-row-amount { font-size: 14px; font-weight: 600; color: var(--text); font-variant-numeric: tabular-nums; }
.pool-row-note { font-size: 11.5px; color: var(--text-faint); margin-top: 2px; }
.pool-dash { display: flex; gap: 8px; }
.pool-stat { flex: 1 1 0; min-width: 0; background: var(--bg-elev-2); border-radius: var(--radius-sm); padding: 13px 10px; text-align: center; }
/* "Today" is the live figure — emphasise it with the neutral theme accent, not colour. */
.pool-stat.is-accent { background: color-mix(in srgb, var(--accent) 12%, var(--bg-elev-2)); }
.pool-stat-value {
  font-size: clamp(15px, 4.4vw, 21px); font-weight: 700; color: var(--text); font-variant-numeric: tabular-nums;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.pool-stat-label { font-size: 11.5px; color: var(--text-faint); margin-top: 4px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* "How it works" disclosure — rules + requirements, collapsed by default. */
.pool-learn-wrap { padding: 8px 16px 14px; }
.pool-learn {
  display: inline-flex; align-items: center; gap: 5px; padding: 4px 2px;
  background: none; border: none; cursor: pointer; font: inherit; font-size: 12.5px; font-weight: 600; color: var(--accent);
}
.pool-learn:hover { opacity: 0.85; }
.pool-learn-chev { font-size: 18px; transition: transform 0.2s var(--ease); }
.pool-learn.is-open .pool-learn-chev { transform: rotate(180deg); }
.pool-details.is-collapsed { display: none; }
.pool-details { margin-top: 8px; }
.pool-details p { font-size: 12px; color: var(--text-dim); line-height: 1.55; margin: 0 0 8px; }
.pool-details p:last-child { margin-bottom: 0; }

/* "Earnings over time" card — reuses .crm-chart* design with stacked Stream A/B bars. */
/* Extra top room so the max gridline's label clears the section header above it. */
.earn-chart-wrap { padding-top: 22px; }
.earn-chart-head { margin: 22px 0 0; }
.earn-chart-head .earnings-section-label { margin-bottom: 0; }
.earn-bar {
  width: 100%; min-height: 2px; display: flex; flex-direction: column;
  border-radius: 3px 3px 0 0; overflow: hidden; opacity: 0.9; transition: opacity 0.12s var(--ease);
}
.crm-chart-col:hover .earn-bar { opacity: 1; }
.earn-bar-seg { width: 100%; }
/* Two income streams distinguished by accent weight, not by hue — keeps the chart in
   the same monochrome system as the rest of the screen. */
.earn-bar-seg.is-commission { background: color-mix(in srgb, var(--accent) 72%, transparent); }
.earn-bar-seg.is-rebate { background: color-mix(in srgb, var(--accent) 34%, transparent); }
.earn-chart-legend { display: flex; gap: 16px; margin-top: 8px; font-size: 11.5px; color: var(--text-dim); }
.earn-legend-dot { display: inline-block; width: 9px; height: 9px; border-radius: 3px; margin-right: 6px; vertical-align: middle; }
.earn-legend-dot.is-commission { background: color-mix(in srgb, var(--accent) 72%, transparent); }
.earn-legend-dot.is-rebate { background: color-mix(in srgb, var(--accent) 34%, transparent); }

/* 3-layer team, grouped into collapsible Layer 1/2/3 sections. */
.team-layers { display: flex; flex-direction: column; gap: 10px; }
.team-layer { background: var(--bg-elev-1); border-radius: var(--radius-md); overflow: hidden; }
.team-layer-head {
  display: flex; align-items: center; gap: 12px; width: 100%;
  padding: 12px 14px; background: transparent; border: none; color: inherit; font: inherit; text-align: left; cursor: pointer;
}
/* Layer badges are just labels (the row also says "Layer 1/2/3") — one neutral
   treatment for all, no per-layer colour coding. */
.team-layer-pill {
  display: inline-flex; align-items: center; justify-content: center; flex: none;
  width: 30px; height: 30px; border-radius: var(--radius-tile); font-weight: 700; font-size: 14px;
  color: var(--text); background: color-mix(in srgb, var(--accent) 12%, var(--bg-elev-2));
}
.team-layer-id { flex: 1 1 auto; min-width: 0; }
.team-layer-name { font-weight: 600; color: var(--text); }
.team-layer-meta { font-size: 12px; color: var(--text-faint); margin-top: 2px; }
.team-layer-chev { font-size: 22px; color: var(--text-faint); transition: transform 0.2s var(--ease); }
.team-layer-body { display: flex; flex-direction: column; gap: 4px; padding: 0 10px 10px; }
.team-layer-body.is-collapsed { display: none; }
.team-layer-more { font-size: 12px; color: var(--text-faint); padding: 8px 6px; }

/* Yield market / buy. */
.earnings-market { background: var(--bg-elev-1); border-radius: var(--radius); padding: 16px 18px; margin-top: 4px; }
.earnings-market-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; margin-bottom: 12px; }
.earnings-market-grid { display: flex; gap: 10px; margin-bottom: 14px; }
.earnings-mini { flex: 1; background: var(--bg-elev-2); border-radius: var(--radius-sm); padding: 10px 12px; text-align: center; min-width: 0; }
.earnings-mini-value { font-size: 15px; font-weight: 700; color: var(--text); font-variant-numeric: tabular-nums; }
.earnings-mini-label { font-size: 11px; color: var(--text-faint); margin-top: 2px; }
.earnings-buy-btn { width: 100%; justify-content: center; display: inline-flex; align-items: center; gap: 7px; }
.earnings-buy-btn .material-symbols-rounded { font-size: 18px; }

/* Ranks: "you're #N" banner. */
.earnings-rank-you {
  font-size: 13px; font-weight: 600; color: var(--accent);
  background: color-mix(in srgb, var(--accent) 12%, var(--bg-elev-1));
  border-radius: var(--radius-sm); padding: 10px 14px; margin-bottom: 8px;
}

/* Error-state retry. */
.earnings-retry-wrap { margin-top: 16px; display: flex; justify-content: center; }

/* ===== Earn: two-pocket rail + reinvest & gacha ===========================
   Builds on the Gemini tokens. The reinvest/gacha surfaces are the one place the
   multi-colour gradient stops (--grad-a/b/c) earn their keep — a "premium pull" accent
   reserved for the locked-funded growth actions, so they read as special vs the calm
   monochrome of the rest of the screen. Rarity hues: common=neutral, rare=blue,
   epic=purple, legendary=gold. */
/* align-items: start (not the grid default stretch) — Cash out can grow taller once its
   withdrawal-progress fold is open without forcing Reinvest to stretch to match. */
.earn-pockets { display: grid; grid-template-columns: 1fr 1fr; align-items: stretch; gap: 10px; margin-top: 14px; }
.earn-pocket {
  display: flex; flex-direction: column; gap: 3px;
  background: var(--bg-elev-2); border-radius: var(--radius-md); padding: 13px 14px 14px;
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--accent) 8%, transparent);
}
.earn-pocket--reinvest {
  background:
    linear-gradient(150deg, color-mix(in srgb, var(--grad-a) 16%, transparent), color-mix(in srgb, var(--grad-b) 16%, transparent)),
    var(--bg-elev-2);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--grad-b) 32%, transparent);
}
/* Row form for Cash out's head, so the Wallet cross-link pill can sit opposite the label
   instead of stacking under it. Reinvest has no pill, so it just uses .earn-pocket-head
   alone (inline-flex, sized to content). */
.earn-pocket-head-row { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.earn-pocket-head {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 11.5px; font-weight: 600; letter-spacing: 0.4px; text-transform: uppercase; color: var(--text-dim);
}
.earn-pocket-head .material-symbols-rounded { font-size: 16px; }
/* Cross-link pill between the two USDT surfaces (Earn ⇄ Wallet) — same shape as the
   Wallet screen's own corner shortcut, so the bridge reads the same from both sides. */
.earn-wallet-pill {
  flex: none; display: inline-flex; align-items: center; gap: 5px;
  padding: 4px 9px 4px 7px; border-radius: 999px;
  border: 1px solid var(--border);
  background: transparent;
  color: var(--text-dim);
  font: inherit; font-size: 11px; font-weight: 600;
  cursor: pointer;
  transition: background 0.15s var(--ease), color 0.15s var(--ease);
}
.earn-wallet-pill:hover { background: var(--bg-elev-1); color: var(--text); }
.earn-wallet-pill .material-symbols-rounded { font-size: 14px; }
/* In-flight withdrawal count riding the pill — the request list itself lives in the
   Wallet's Activity → Withdrawals view the pill opens. */
.earn-wallet-pill-badge {
  min-width: 15px; height: 15px; padding: 0 4px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 999px;
  font-size: 9.5px; font-weight: 800; line-height: 1; font-variant-numeric: tabular-nums;
  color: var(--warn); background: color-mix(in srgb, var(--warn) 18%, transparent);
}
.earn-pocket-amount { font-size: 22px; font-weight: 700; color: var(--text); font-variant-numeric: tabular-nums; line-height: 1.1; }
.earn-pocket-sub { font-size: 11px; color: var(--text-faint); margin-bottom: 10px; min-height: 14px; }
.earn-pocket-btn {
  margin-top: auto; display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  width: 100%; padding: 10px 12px; border: none; border-radius: 999px; cursor: pointer;
  font: inherit; font-size: 13.5px; font-weight: 650;
  background: var(--accent); color: var(--on-accent);
  transition: transform var(--ease) 130ms, opacity var(--ease) 130ms, box-shadow var(--ease) 130ms;
}
.earn-pocket-btn .material-symbols-rounded { font-size: 18px; }
.earn-pocket-btn:not(:disabled):hover { opacity: 0.92; }
.earn-pocket-btn:not(:disabled):active { transform: scale(0.97); }
.earn-pocket-btn:disabled { opacity: 0.4; cursor: default; }
.earn-pocket-btn--alt {
  background: linear-gradient(120deg, var(--grad-a), var(--grad-b) 55%, var(--grad-c)); color: #fff;
  box-shadow: 0 6px 18px -8px color-mix(in srgb, var(--grad-b) 80%, transparent);
}

/* The locked-balance chip pinned top-right in the Reinvest sheet bar. */
.earn-lock-chip {
  display: inline-flex; align-items: center; gap: 5px; padding: 5px 11px; border-radius: 999px;
  font-size: 13px; font-weight: 650; font-variant-numeric: tabular-nums;
  background: color-mix(in srgb, var(--grad-b) 18%, var(--bg-elev-1)); color: var(--text);
}
.earn-lock-chip .material-symbols-rounded { font-size: 15px; color: var(--grad-b); }

/* Reinvest sheet — portrait store-cards (the locked balance lives in the top-bar chip). One
   accent hue PER CARD keeps the palette cohesive (Gemini) while the tier ramp + top-tier glow
   bring the gamified hype. Tier ramp: silver → blue → purple → gold; the Genie agent card is
   the hero and wears the brand gradient (the one multi-colour accent on the screen). */
.reinvest-tab { display: flex; flex-direction: column; }
.reinvest-agent-section { margin-top: 6px; }
/* auto-fit (not auto-fill) — .pack-grid now only wraps the single Buy-a-Genie card, and
   auto-fill reserves as many minmax tracks as geometrically fit regardless of item count,
   so a lone card sat in one ~half-width track with an invisible empty second track eating
   the rest of the row. auto-fit collapses that empty track to 0, letting the card's 1fr
   track take the full row — this is what was silently shrinking it below the pack-rail's
   full-width cards. */
/* 2/3 width, matching .pack-rail .pack-card below so the Buy-a-Genie card and the pack
   cards stay the same size as each other. */
.pack-grid { grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); max-width: 66.6%; }
/* Card packs — a horizontal rail, not a wrapped grid: the most-promoted (top-tier) pack
   leads leftmost, the rest are a swipe away. No bleed/negative-margin trick — the rail
   stays inset exactly like .store-grid above it, so cards line up at the same edges
   (a bled rail computed its 100%-width cards against a slightly different box, which is
   what was throwing the two cards off by a few px). */
.pack-rail {
  display: flex; gap: 12px;
  overflow-x: auto; overscroll-behavior-x: contain;
  scroll-snap-type: x proximity;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}
.pack-rail::-webkit-scrollbar { display: none; }
/* 2/3 of the rail's width — matches .pack-grid's cap on the Buy-a-Genie card above (same
   fraction of the same container width, so both stay the same size). The remaining third
   (minus the gap) peeks the next card at the edge, inviting a swipe. */
.pack-rail .pack-card { flex: 0 0 66.6%; scroll-snap-align: start; }
.pack-card {
  --pack: #9aa0a6; gap: 8px;
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--pack) 22%, transparent);
}
.pack-card--t1 { --pack: #9aa0a6; }
.pack-card--t2 { --pack: #38bdf8; }
.pack-card--t3 { --pack: #c084fc; }
.pack-card--t4 { --pack: #ffce5a; }
/* Top tier = the jackpot pack: brighter ring + a soft outer glow. */
.pack-card.is-top { box-shadow: inset 0 0 0 1.5px color-mix(in srgb, var(--pack) 65%, transparent), 0 0 34px -14px var(--pack); }
.pack-emblem {
  display: inline-flex; align-items: center; justify-content: center; width: 40px; height: 40px; border-radius: var(--radius-md);
  background: color-mix(in srgb, var(--pack) 20%, var(--bg-elev-2)); color: var(--pack);
}
.pack-emblem .material-symbols-rounded { font-size: 22px; }
.pack-name { font-size: 14px; font-weight: 700; color: var(--text); }
/* "N-card pack" — signals the booster-pack hand size under the pack name. */
.pack-slots { font-size: 11px; font-weight: 600; color: var(--gtc-accent, var(--accent)); letter-spacing: 0.2px; margin-top: -1px; }
.pack-badge { background: var(--pack); color: #0a0b0d; }
/* Featured odds — dim text with tier-hue dots (no per-rarity colour rainbow). */
/* Free-pull grants — gift chips above the store, each opens its pack for free. Brand-gradient
   so they read as a reward, distinct from the frosted paid pack cards. */
.gacha-grants { display: flex; flex-wrap: wrap; gap: 8px; margin: 0 0 14px; }
.gacha-grant {
  display: inline-flex; align-items: center; gap: 9px; padding: 8px 12px; border: 0; cursor: pointer;
  border-radius: 14px; color: #fff; text-align: left;
  background: linear-gradient(135deg, #0036ff, #c600ff);
  box-shadow: 0 6px 16px -8px rgba(120, 40, 255, 0.7);
  transition: transform 0.12s ease, filter 0.12s ease;
}
.gacha-grant:hover { filter: brightness(1.06); }
.gacha-grant:active { transform: translateY(1px); }
.gacha-grant:disabled { opacity: 0.55; cursor: default; filter: none; transform: none; }
.gacha-grant-ic { display: inline-flex; }
.gacha-grant-ic .material-symbols-rounded { font-size: 22px; }
.gacha-grant-body { display: flex; flex-direction: column; min-width: 0; line-height: 1.2; }
.gacha-grant-title { font-size: 12.5px; font-weight: 800; }
.gacha-grant-reason { font-size: 10.5px; font-weight: 600; opacity: 0.85; }
.gacha-grant-open {
  margin-left: 4px; font-size: 11px; font-weight: 800; letter-spacing: 0.3px; text-transform: uppercase;
  background: rgba(255, 255, 255, 0.2); border-radius: 999px; padding: 3px 9px;
}
.pack-odds { display: flex; flex-wrap: wrap; gap: 4px 10px; margin: 0 0 2px; font-size: 11.5px; color: var(--text-dim); }
.pack-odd { display: inline-flex; align-items: center; gap: 5px; }
.pack-odd-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--pack); }
.pack-odd-pct { color: var(--text-faint); font-variant-numeric: tabular-nums; }
/* Tier-tinted CTA: a calm tint for entry tiers, a solid fill on the top tier (extra pop). */
.pack-card .store-buy {
  background: color-mix(in srgb, var(--pack) 20%, var(--bg-elev-2)); color: var(--pack);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--pack) 42%, transparent);
}
.pack-card.is-top .store-buy { background: var(--pack); color: #0a0b0d; box-shadow: none; }
.pack-card .store-buy:disabled { opacity: 0.5; }
/* The Genie agent card — the hero purchase, so it wears the brand gradient.
   Scoped to .pack-card so it can't leak into the agent-switcher dropdown,
   whose rows also use the .agent-card class. */
.pack-card.agent-card { box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--grad-b) 34%, transparent); }
.pack-card.agent-card .pack-emblem { background: linear-gradient(135deg, var(--grad-a), var(--grad-b), var(--grad-c)); color: #fff; }
.pack-card.agent-card .store-buy { background: linear-gradient(120deg, var(--grad-a), var(--grad-b) 55%, var(--grad-c)); color: #fff; box-shadow: none; }
.agent-card .store-buy:disabled { opacity: 0.5; }
.agent-tag { font-size: 11.5px; color: var(--text-faint); line-height: 1.4; margin: 0 0 2px; }

/* Upgrade card collection (Wallet screen's Cards tab) — a fixed 2-up grid of collectible
   tiles styled like the gacha reveal card itself (rarity-tinted border, dark radial
   interior, a glowing circular icon as the "art"), just shrunk down and static — so a card
   in your collection visually matches the moment you won it, not a generic list row.
   Fixed 2 columns per the design brief (not auto-fit) — a lone tile stays half-width,
   left-aligned, rather than stretching to fill the row. */
/* minmax(0,1fr) — NOT plain 1fr — so the columns can shrink below the cards' min-content
   instead of blowing the grid wider than its container (which let the mobile Wallet scroll
   sideways). The page then only ever scrolls vertically. */
.card-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; }
@media (max-width: 720px) { .card-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.card-tile {
  --card-accent: #9aa0a6;
  position: relative;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 7px;
  /* Same proportions as the actual gacha reveal card (.gacha-spinner is 300×416) — width
     comes from the 3-up grid column, height follows the ratio (grows past it if content
     needs more, never shrinks below it), so a tile reads as a scaled-down replica, not a
     generic square box. */
  aspect-ratio: 300 / 416;
  padding: 16px 10px 12px;
  border-radius: var(--radius-lg);
  border: 2px solid transparent;
  background:
    radial-gradient(circle at 50% 38%, color-mix(in srgb, var(--card-accent) 20%, #0a0b0d), #0a0b0d 78%) padding-box,
    linear-gradient(140deg, var(--card-accent), color-mix(in srgb, var(--card-accent) 55%, #000) 50%, var(--card-accent)) border-box;
  box-shadow: 0 14px 28px -14px rgba(0, 0, 0, 0.6), 0 0 22px -12px var(--card-accent);
}
.card-tile--mid { --card-accent: #ffce5a; }
.card-tile--high { --card-accent: #c084fc; }
.card-tile-head { position: absolute; top: 10px; left: 11px; right: 11px; display: flex; align-items: center; justify-content: space-between; }
.card-tile-rank { font-size: 10.5px; font-weight: 800; letter-spacing: 1px; color: var(--card-accent); }
.card-tile-gem { display: inline-flex; color: var(--card-accent); filter: drop-shadow(0 0 4px var(--card-accent)); }
.card-tile-gem .material-symbols-rounded { font-size: 13px; }
/* Progress-toward-next-star chip in the tile head — a target for the collection. */
.card-tile-prog {
  font-size: 10px; font-weight: 800; font-variant-numeric: tabular-nums; letter-spacing: 0.2px;
  color: var(--card-accent); background: color-mix(in srgb, var(--card-accent) 15%, transparent);
  border-radius: 999px; padding: 2px 7px;
}
.card-tile-prog.is-ready { color: #fff; background: var(--card-accent); }
.card-tile-icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 48px; height: 48px; margin-top: 6px; border-radius: 50%; color: #fff;
  background: color-mix(in srgb, var(--card-accent) 18%, rgba(0, 0, 0, 0.5));
  box-shadow: inset 0 0 0 1.5px color-mix(in srgb, var(--card-accent) 55%, transparent), 0 0 18px -4px var(--card-accent);
}
.card-tile-icon .material-symbols-rounded { font-size: 26px; filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.5)); }
/* Upgrade card art: the same upgrade.svg used in the gacha reveal, scaled for the collectible
   tile (a mini replica of the reveal card) instead of the old glyph-in-a-circle. */
.card-tile-art { display: block; width: 120px; height: 120px; margin: 6px 0 2px; filter: drop-shadow(0 4px 12px rgba(0, 0, 0, 0.5)); }
.card-tile-count { font-size: 12.5px; font-weight: 700; color: rgba(255, 255, 255, 0.82); }
/* Same explainer copy as the reveal card / old list row — always visible, not a hover-only
   title attribute, so what the card is FOR doesn't require discovering a tooltip. */
.card-tile-desc { font-size: 11.5px; line-height: 1.42; text-align: center; color: rgba(255, 255, 255, 0.64); }
/* The general outcome of an upgrade — accent-tinted so it reads as the "why". */
.card-tile-result { font-size: 11.5px; line-height: 1.42; text-align: center; font-weight: 600; margin-top: 5px; color: color-mix(in srgb, var(--card-accent) 82%, #fff); }
.card-tile-prog {
  font-size: 10.5px; font-weight: 700; font-variant-numeric: tabular-nums; color: rgba(255, 255, 255, 0.62);
  background: rgba(255, 255, 255, 0.1); border-radius: 999px; padding: 3px 10px;
}
.card-tile-prog.is-ready { color: #0a0b0d; background: var(--card-accent); font-weight: 800; }

/* Gacha card (Wallet → Cards) — an openable .card-tile mirroring the gacha reveal's card BACK
   (the mystery card + white Superpower wordmark). Each PACK TIER gets its own colour palette via
   --pack, matching the Store/Reinvest pack-card hues (t1 silver → t4 gold): a tier-hued shimmer
   over a deep base + a tier glow, so a Cosmic pack reads distinctly from a free pull at a glance. */
.card-tile--gacha {
  --pack: #9aa0a6; /* default = Free pull / tier 1 */
  cursor: pointer; font: inherit; text-align: center;
  -webkit-appearance: none; appearance: none;
  border: 2px solid color-mix(in srgb, var(--pack) 60%, transparent);
  background: linear-gradient(135deg,
    color-mix(in srgb, var(--pack) 58%, #16102a),
    color-mix(in srgb, var(--pack) 30%, #100a1e) 54%,
    color-mix(in srgb, var(--pack) 64%, #1d1436) 100%);
  background-size: 200% 200%;
  animation: buy-card-aurora 9s ease-in-out infinite;
  box-shadow: 0 14px 28px -14px rgba(0, 0, 0, 0.6), 0 0 26px -12px var(--pack);
  transition: transform 0.12s var(--ease), filter 0.12s var(--ease);
}
/* Per-tier palette (same hues as .pack-card--t1..t4 in the Store/Reinvest packs). */
.card-tile--gacha.gacha-t1 { --pack: #9aa0a6; }
.card-tile--gacha.gacha-t2 { --pack: #38bdf8; }
.card-tile--gacha.gacha-t3 { --pack: #c084fc; }
.card-tile--gacha.gacha-t4 { --pack: #ffce5a; box-shadow: 0 14px 28px -14px rgba(0, 0, 0, 0.6), 0 0 34px -10px var(--pack); }
.card-tile--gacha:hover { filter: brightness(1.06); }
.card-tile--gacha:active { transform: translateY(1px); }
.card-tile--gacha:disabled { opacity: 0.55; cursor: default; }
.card-tile--gacha .card-tile-rank { color: #fff; }
.card-tile--gacha .card-tile-gem { color: #fff; filter: drop-shadow(0 0 4px rgba(255, 255, 255, 0.6)); }
/* Superpower wordmark emblem — matches .gacha-back-emblem / .gacha-back-logo on the reveal. */
.gacha-tile-emblem {
  display: flex; align-items: center; justify-content: center;
  width: 62%; aspect-ratio: 1 / 1; border-radius: 50%;
  background: radial-gradient(circle, rgba(0, 0, 0, 0.12) 30%, transparent 66%);
}
.gacha-tile-logo { width: 92%; opacity: 0.94; filter: brightness(0) invert(1) drop-shadow(0 0 12px rgba(255, 255, 255, 0.35)); }
/* "What's inside" loot overview — tiny frosted chips under the emblem teasing the drop CATEGORIES
   (upgrade cards / Credits / rare agent). Keep the emblem full-size (the wordmark is the hero); the
   loot chips tuck under it. */
.card-tile--gacha:has(.gacha-loot) .gacha-tile-emblem { width: 64%; }
/* Card layout: emblem+loot form one bottom-aligned block at the top, the price sits vertically
   centred, and the CTA pins to the bottom — so price + CTA land at the SAME height on every card no
   matter how many loot chips a pack shows. */
.card-tile--gacha { justify-content: space-between; }
.gacha-tile-body {
  display: flex; flex-direction: column; align-items: center; justify-content: flex-end;
  gap: 8px; width: 100%; padding-top: 14px;
}
.gacha-loot { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 4px 5px; padding: 0 2px; }
.gacha-loot-chip {
  display: inline-flex; align-items: center; gap: 2.5px;
  font-size: 9px; font-weight: 700; line-height: 1; white-space: nowrap;
  color: rgba(255, 255, 255, 0.92);
  background: rgba(0, 0, 0, 0.28); border-radius: 999px; padding: 2.5px 7px 2.5px 5px;
}
.gacha-loot-chip .material-symbols-rounded { font-size: 11px; opacity: 0.95; }
/* Fungible stack count (×N) — white + bold so a stacked pack reads at a glance, like the star-up ×N. */
.card-tile--gacha .card-tile-count { color: #fff; font-weight: 800; font-size: 15px; text-shadow: 0 1px 3px rgba(0, 0, 0, 0.4); }
/* Store version: the Power price sits where the ×N stack count does on a Wallet card. */
.gacha-tile-price { color: #fff; font-weight: 800; font-size: 15px; text-shadow: 0 1px 3px rgba(0, 0, 0, 0.4); }
.gacha-tile-price .cur-icon { font-size: 17px; }
/* Reinvest version: a lock + $ price (opened with locked earnings, not Power). */
.gacha-tile-price--lock { display: inline-flex; align-items: center; gap: 4px; }
.gacha-tile-price--lock .material-symbols-rounded { font-size: 14px; opacity: 0.85; }
/* Reinvest sheet: the gacha packs wrap in a 2-col grid (like the Shop on mobile) — the sheet is
   ≤480px, so 2-up keeps the cards a good size (2+1 for the three packs). */
.reinvest-pack-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }

/* Store currency card (Power / Credits) — SAME layout as the Gacha card: an absolute head
   (name + a currency gem, top-right), the amount as the centred hero (where the Gacha logo
   sits), then a chip + price + white CTA. Reuses the .card-tile gradient/glow, themed via
   --card-accent (Power = electric blue, Credits = gold). */
.card-tile--store {
  cursor: pointer; font: inherit; -webkit-appearance: none; appearance: none;
  container-type: inline-size; /* size the hero amount to the card width (cqw) so long numbers never truncate */
  transition: transform 0.12s var(--ease), filter 0.12s var(--ease);
}
.card-tile--store.is-top { box-shadow: 0 14px 28px -14px rgba(0, 0, 0, 0.6), 0 0 36px -10px var(--card-accent); }
.card-tile--store:hover { filter: brightness(1.07); }
.card-tile--store:active { transform: translateY(1px); }
.card-tile--store .card-tile-rank { color: rgba(255, 255, 255, 0.72); }
.card-tile--store .card-tile-gem { color: var(--card-accent); filter: drop-shadow(0 0 4px color-mix(in srgb, var(--card-accent) 55%, transparent)); }
/* "Best value" sits BOTTOM-CENTER, in the empty band below the centred CTA — top-right (image
   22/24) collided with the pack name. A ribbon-style pill anchored to the card's lower edge. */
.card-tile--store .store-badge {
  top: auto; right: auto; bottom: 10px; left: 50%; transform: translateX(-50%);
  background: var(--card-accent); color: #0a0b0d;
}
/* Hero occupies the EXACT footprint of the gacha card's emblem (62% width, 1:1) — same box, so
   the price + Buy below it land at the identical positions as the gacha card's. */
.store-hero { width: 62%; aspect-ratio: 1 / 1; margin: 0 auto; display: grid; place-items: center; }
/* The amount is a single unbroken unit sized to the card width — big on desktop, shrinking on
   narrow cards so even ◉3,000 fits without truncating. */
.store-hero .cur { font-weight: 800; color: #fff; white-space: nowrap; max-width: 100%; }
.store-hero .cur-val { font-size: min(44px, 21cqw); line-height: 1; }
.store-hero .cur-icon { font-size: min(30px, 15cqw); color: var(--card-accent); }
.card-tile--store .store-price { color: #fff; }
.card-tile--store .store-price .cur { color: #fff; }
.card-tile--store .store-price .cur-icon { color: var(--card-accent); font-size: 15px; }
/* Discount / bonus chip floats at TOP-CENTER (in the empty band under the name row), out of the
   flow so it never shifts the number/button. */
.store-chip {
  position: absolute; top: 34px; left: 50%; transform: translateX(-50%);
  font-size: 11px; font-weight: 800; white-space: nowrap;
  color: color-mix(in srgb, var(--card-accent) 82%, #fff);
  background: color-mix(in srgb, var(--card-accent) 16%, transparent);
  border-radius: 999px; padding: 3px 11px;
}
.card-tile-open {
  margin-top: 6px; font-size: 12px; font-weight: 800; letter-spacing: 0.3px;
  padding: 6px 18px; border-radius: 999px;
  color: #1a1030; background: #fff; box-shadow: 0 6px 16px -8px rgba(0, 0, 0, 0.5);
}
@media (prefers-reduced-motion: reduce) { .card-tile--gacha { animation: none; } }

/* Star-up strip on a yield agent card — ONE loud number (the relative yield jump) with
   the star target under it and an x/x cards pill. The same strip in both states: lit
   (gradient, tappable) when a full card set is held, muted .is-locked otherwise. */
.yield-card-starup {
  display: flex; align-items: center; gap: 11px; width: 100%; margin-top: 10px;
  padding: 10px 12px; border: none; border-radius: var(--radius-md); cursor: pointer; font: inherit; text-align: left; color: #fff;
  background: linear-gradient(120deg, var(--grad-a), var(--grad-b) 55%, var(--grad-c));
  box-shadow: 0 6px 18px -10px color-mix(in srgb, var(--grad-b) 90%, transparent);
  transition: transform var(--ease) 130ms, filter var(--ease) 130ms;
}
.yield-card-starup:hover { filter: brightness(1.06); }
.yield-card-starup:active { transform: scale(0.985); }
.starup-emblem {
  flex: none; display: inline-flex; align-items: center; justify-content: center; width: 28px; height: 28px;
  border-radius: 50%; background: rgba(255, 255, 255, 0.18);
}
.starup-emblem .material-symbols-rounded { font-size: 18px; }
.starup-body { display: flex; flex-direction: column; min-width: 0; flex: 1; }
.starup-headline { font-size: 16.5px; font-weight: 800; font-variant-numeric: tabular-nums; line-height: 1.15; letter-spacing: 0.1px; }
.starup-sub { font-size: 11px; font-weight: 500; opacity: 0.85; margin-top: 1px; }
/* Card progress fill under the headline — thin, so "almost there" reads at a glance. */
.starup-bar {
  margin-top: 5px; height: 4px; border-radius: 999px; overflow: hidden;
  background: rgba(0, 0, 0, 0.24);
}
.starup-bar-fill {
  display: block; height: 100%; border-radius: 999px;
  background: rgba(255, 255, 255, 0.9); transition: width 0.5s ease;
}
.starup-bar.is-full .starup-bar-fill { background: #fff; box-shadow: 0 0 8px rgba(255, 255, 255, 0.7); }
.yield-card-starup.is-locked .starup-bar { background: color-mix(in srgb, var(--text) 8%, transparent); }
.yield-card-starup.is-locked .starup-bar-fill { background: color-mix(in srgb, var(--text) 34%, transparent); box-shadow: none; }
/* x/x cards pill — frosted dark so it reads on the gradient; dimmer when locked. */
.starup-prog {
  flex: none; font-size: 12px; font-weight: 800; font-variant-numeric: tabular-nums;
  color: #fff; background: rgba(0, 0, 0, 0.28); border-radius: 999px; padding: 4px 10px;
}
/* Locked variant: the full card set isn't held yet — same layout, non-interactive,
   flat elevation; the pill shows how far along the set is. */
.yield-card-starup.is-locked {
  cursor: default; color: var(--text-dim);
  background: var(--bg-elev-2); box-shadow: none;
}
.yield-card-starup.is-locked:hover { filter: none; }
.yield-card-starup.is-locked:active { transform: none; }
.yield-card-starup.is-locked .starup-emblem { background: color-mix(in srgb, var(--text) 9%, transparent); color: var(--text-faint); }
.yield-card-starup.is-locked .starup-sub { color: var(--text-faint); opacity: 1; }
.yield-card-starup.is-locked .starup-prog {
  color: var(--text-dim); background: color-mix(in srgb, var(--text) 9%, transparent);
}

/* Trial banner (v53): reinvest/gacha agents earn LOCKED scrip only until the first fee is
   paid. Warm amber "gated — unlock me" treatment, deliberately distinct from the brand-
   gradient star-up strip so it reads as a state to resolve, not a reward. The whole strip is
   the subscribe CTA (paying the fee clears the trial → cashable USDT + weekly credits switch on). */
.yield-trial {
  display: flex; align-items: center; gap: 11px; width: 100%; margin-top: 10px;
  padding: 10px 12px; border-radius: var(--radius-md); cursor: pointer; font: inherit; text-align: left;
  color: var(--text);
  border: 1px solid color-mix(in srgb, var(--warn) 45%, transparent);
  background: color-mix(in srgb, var(--warn) 12%, var(--bg-elev-1));
  transition: transform var(--ease) 130ms, filter var(--ease) 130ms;
}
.yield-trial:hover { filter: brightness(1.04); }
.yield-trial:active { transform: scale(0.985); }
.yield-trial-emblem {
  flex: none; display: inline-flex; align-items: center; justify-content: center; width: 28px; height: 28px;
  border-radius: 50%; background: color-mix(in srgb, var(--warn) 22%, transparent); color: var(--warn);
}
.yield-trial-emblem .material-symbols-rounded { font-size: 18px; }
.yield-trial-body { display: flex; flex-direction: column; min-width: 0; flex: 1; }
.yield-trial-headline { font-size: 14px; font-weight: 750; line-height: 1.15; color: var(--text); }
.yield-trial-sub { font-size: 11px; font-weight: 500; color: var(--text-dim); margin-top: 1px; }
/* Power cost to unlock — a gradient pill mirroring the extend CTA's spend affordance. */
.yield-trial-cost {
  flex: none; display: inline-flex; align-items: center; gap: 3px; font-size: 12.5px; font-weight: 800;
  font-variant-numeric: tabular-nums; color: var(--on-accent); border-radius: 999px; padding: 5px 11px;
  background: var(--grad);
}
.yield-trial-cost .material-symbols-rounded { font-size: 15px; }

/* Upline (sponsor) card on the Referral tab. */
.upline-card { display: flex; align-items: center; gap: 12px; background: var(--bg-elev-1); border-radius: var(--radius-md); padding: 13px 15px; margin-bottom: 12px; }
.upline-avatar {
  flex: none; display: inline-flex; align-items: center; justify-content: center; width: 38px; height: 38px; border-radius: 50%;
  background: color-mix(in srgb, var(--accent) 14%, var(--bg-elev-2)); color: var(--accent);
}
.upline-avatar .material-symbols-rounded { font-size: 21px; }
.upline-main { min-width: 0; flex: 1; }
.upline-label { font-size: 11px; font-weight: 600; letter-spacing: 0.4px; text-transform: uppercase; color: var(--text-faint); }
.upline-name { font-size: 14.5px; font-weight: 650; color: var(--text); margin-top: 1px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.upline-tag { flex: none; font-size: 11px; font-weight: 600; color: var(--text-dim); padding: 3px 10px; border-radius: 999px; background: var(--bg-elev-2); }

/* ===== Gacha reveal: swipe-up → flashy spin/flip → prize (the dopamine moment) ===== */
.gacha-stage {
  /* Above the reinvest/yield slide-in sheet (z 1100) + nav menus (1300/1400) — the reveal
     is a full-screen takeover moment, nothing should sit over it. */
  position: fixed; inset: 0; z-index: 1500; overflow: hidden; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 20px;
  /* Dark theatrical takeover (theme-independent) so the card, rays + particles all glow. The
     backdrop is near-opaque + heavily blurred so the earn page behind dissolves into a soft
     vignette (a lighter blur let the hero card bleed through as an obvious rectangle). */
  background:
    radial-gradient(circle at 50% 50%, color-mix(in srgb, var(--grad-b) 40%, transparent), transparent 66%),
    rgba(7, 8, 11, 0.95);
  /* Light blur only — the 0.95-opaque backdrop already hides the page, and a large full-screen
     backdrop-filter re-composites every frame behind the animating card (a real FPS cost). */
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px); opacity: 0; transition: opacity 220ms var(--ease);
  touch-action: none; user-select: none; -webkit-user-select: none;
}
.gacha-stage.is-open { opacity: 1; }
.gacha-stage.flash::before {
  content: ""; position: absolute; inset: 0; background: #fff; opacity: 0; pointer-events: none;
  animation: gacha-flash 720ms var(--ease) forwards;
}
@keyframes gacha-flash { 0% { opacity: 0; } 10% { opacity: 0.6; } 100% { opacity: 0; } }
/* Reveal impact: the whole card jolts (screen-shake feel) and the prize icon punches in. */
.gacha-stage.shake .gacha-card-wrap { animation: gacha-shake 520ms var(--ease); }
@keyframes gacha-shake {
  0% { transform: translate(0, 0) rotate(0deg); }
  12% { transform: translate(-10px, 6px) rotate(-1.6deg); }
  26% { transform: translate(9px, -7px) rotate(1.4deg); }
  40% { transform: translate(-7px, 5px) rotate(-1deg); }
  56% { transform: translate(6px, -4px) rotate(0.8deg); }
  72% { transform: translate(-4px, 3px) rotate(-0.5deg); }
  88% { transform: translate(2px, -1px) rotate(0.2deg); }
  100% { transform: translate(0, 0) rotate(0deg); }
}
.gacha-stage.is-revealed .gacha-reveal-icon { animation: gacha-pop 540ms var(--ease); }
@keyframes gacha-pop { 0% { transform: scale(1); } 32% { transform: scale(1.3); } 66% { transform: scale(0.94); } 100% { transform: scale(1); } }

.gacha-card-wrap { position: relative; z-index: 1; perspective: 1200px; cursor: grab; touch-action: none; }
.gacha-card-wrap:active { cursor: grabbing; }
/* The spinner rotates BOTH stacked cards as one plane; we crossfade mystery→prize at the
   edge-on midpoint (no preserve-3d / backface-visibility — those are fragile and a `filter`
   silently breaks them). Spin ends at 720° (= upright) so the prize text never mirrors. */
/* 1.5× bigger (was 196×264) so the prize reads like a real collectible card. */
.gacha-spinner { --glow: rgba(255, 255, 255, 0.9); position: relative; width: 300px; height: 416px; animation: gacha-float 3s ease-in-out infinite; }
.gacha-spinner.is-spinning { animation: gacha-spin 1s var(--ease) forwards; }
.gacha-stage.is-revealed .gacha-spinner { animation: none; transform: none; }
/* BorderGlow (reactbits.dev/components/border-glow) — a bright arc that travels around the
   card's border, autoplaying. Masked conic gradient = border ring only; drop-shadow = bloom.
   The glow tints to the prize value once revealed (stays white on a common pull). */
@property --gborder { syntax: "<angle>"; inherits: false; initial-value: 0deg; }
.gacha-spinner::before {
  content: ""; position: absolute; inset: -3px; z-index: 5; pointer-events: none;
  border-radius: calc(var(--radius-lg) + 3px); padding: 3px;
  background: conic-gradient(from var(--gborder), transparent 52%, var(--glow) 76%, #fff 82%, var(--glow) 88%, transparent 96%);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor; mask-composite: exclude;
  filter: drop-shadow(0 0 6px var(--glow));
  animation: gborder-spin 3s linear infinite;
}
@keyframes gborder-spin { to { --gborder: 360deg; } }
.gacha-stage--rare.is-revealed .gacha-spinner { --glow: #7dd3fc; }
.gacha-stage--epic.is-revealed .gacha-spinner { --glow: #e879f9; }
.gacha-stage--legendary.is-revealed .gacha-spinner { --glow: #ffce5a; }
@keyframes gacha-float { 0%, 100% { transform: translateY(0) rotateY(0deg); } 50% { transform: translateY(-10px) rotateY(0deg); } }
@keyframes gacha-spin { 0% { transform: rotateY(0deg) scale(0.92); } 60% { transform: rotateY(540deg) scale(1.16); } 100% { transform: rotateY(720deg) scale(1); } }
.gacha-card {
  position: absolute; inset: 0; border-radius: var(--radius-lg); overflow: hidden;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 8px; text-align: center;
  box-shadow: 0 30px 56px -14px rgba(0, 0, 0, 0.65); transition: opacity 180ms linear;
}
/* Pre-reveal mystery card: the default agent-card look (the store buy-card's animated aurora
   gradient) with the translucent LetterGlitch matrix (a `.gtc-glitch` canvas) over it. The 3px
   border matches the glow ring + the revealed prize card's border. */
.gacha-card--back {
  opacity: 1; border: 3px solid rgba(255, 255, 255, 0.55);
  background: linear-gradient(125deg, var(--grad-a), var(--grad-b) 42%, var(--grad-c) 72%, var(--grad-a) 100%);
  background-size: 240% 240%;
  box-shadow: 0 30px 56px -14px rgba(0, 0, 0, 0.65);
  animation: buy-card-aurora 9s ease-in-out infinite;
}
.gacha-stage.show-front .gacha-card--back { opacity: 0; }
.gacha-stage.show-front .gacha-card--front { opacity: 1; }
/* Glyph alpha lives in the colours (≈30% white); the canvas itself stays fully opaque. */
.gtc-glitch { position: absolute; inset: 0; z-index: 0; opacity: 1; }
/* Superpower wordmark over a very soft scrim (dimmed — no hard black circle).
   The logo art is a DARK wordmark → brightness(0) invert(1) makes it white (matches .buy-card-logo). */
.gacha-back-emblem {
  position: relative; z-index: 1; display: flex; align-items: center; justify-content: center;
  width: 64%; aspect-ratio: 1 / 1; border-radius: 50%;
  background: radial-gradient(circle, rgba(0, 0, 0, 0.1) 30%, transparent 66%);
}
.gacha-back-logo { width: 82%; opacity: 0.92; filter: brightness(0) invert(1) drop-shadow(0 0 12px rgba(255, 255, 255, 0.3)); }
.gacha-shimmer {
  position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(115deg, transparent 36%, rgba(255, 255, 255, 0.4) 50%, transparent 64%);
  transform: translateX(-120%); animation: gacha-sheen 2.4s var(--ease) infinite;
}
@keyframes gacha-sheen { 0% { transform: translateX(-120%); } 55%, 100% { transform: translateX(120%); } }

/* ----- Prize as a collectible (Pokémon-style) trading card ----- */
/* One per-rarity accent var drives the holographic border, gem, art glow, and icon tint. */
.gacha-card--front {
  --gtc-border: linear-gradient(140deg, #e2e8f0, #94a3b8 50%, #e2e8f0);
  --gtc-accent: #b8c2cf;
  opacity: 0; align-items: stretch; padding: 11px; border: 3px solid transparent;
  /* Dark rarity-tinted interior so the full-bleed pixels glow over it (screen blend). */
  background:
    radial-gradient(circle at 50% 42%, color-mix(in srgb, var(--gtc-accent) 18%, #0a0b0d), #0a0b0d 80%) padding-box,
    var(--gtc-border) border-box;
  box-shadow: 0 30px 56px -14px rgba(0, 0, 0, 0.65);
}
/* Radiating light shafts behind the card — a canvas burst (earnings.ui.ts createRays) whose
   rays vary in LENGTH + WIDTH so they fill the surrounding space, esp. on desktop. The burst
   is value-tinted + slow-spun in JS; this radial mask dissolves the far ends into the dark
   before the viewport edges (no hard rectangle / no edge-to-edge "hyperspace" wall). */
.gacha-rays {
  position: absolute; inset: 0; z-index: 0; opacity: 0; pointer-events: none;
  transition: opacity 700ms var(--ease);
  -webkit-mask: radial-gradient(circle at 50% 50%, #000 30%, transparent 72%);
  mask: radial-gradient(circle at 50% 50%, #000 30%, transparent 72%);
}
.gacha-rays.is-on { opacity: 1; }
.gtc-art-glow {
  position: absolute; inset: 0; z-index: 1; margin: auto; width: 62%; height: 46%; border-radius: 50%;
  background: radial-gradient(circle, color-mix(in srgb, var(--gtc-accent) 55%, transparent), transparent 70%); filter: blur(16px);
}
/* Light-pillar card background (reactbits.dev/backgrounds/light-pillar, reimplemented in CSS
   to avoid a Three.js dependency): a value-tinted vertical beam with a slow volumetric shimmer,
   revealed with the prize. Deliberately DIM (screen blend + low-opacity layers) so it never
   competes with the icon / prize text above it (z-index 2). */
.gtc-pillar {
  position: absolute; inset: 0; z-index: 0; overflow: hidden; pointer-events: none;
  border-radius: inherit; opacity: 0; transition: opacity 700ms var(--ease);
  mix-blend-mode: screen; --pillar: var(--gtc-accent);
}
.gacha-stage.is-revealed .gtc-pillar { opacity: 1; }
/* the beam: bright-top → value → dark-bottom, with a soft column falloff to the card edges */
.gtc-pillar::before {
  content: ""; position: absolute; left: 50%; top: -22%; bottom: -22%; width: 78%;
  transform: translateX(-50%);
  background: linear-gradient(180deg,
    color-mix(in srgb, var(--pillar) 55%, #fff) 0%,
    var(--pillar) 46%,
    color-mix(in srgb, var(--pillar) 50%, #000) 100%);
  -webkit-mask: radial-gradient(56% 94% at 50% 46%, #000 6%, rgba(0, 0, 0, 0.4) 40%, transparent 74%);
  mask: radial-gradient(56% 94% at 50% 46%, #000 6%, rgba(0, 0, 0, 0.4) 40%, transparent 74%);
  filter: blur(16px); opacity: 0.4;
}
/* slow volumetric shimmer drifting up the beam */
.gtc-pillar::after {
  content: ""; position: absolute; left: 50%; top: 0; bottom: 0; width: 78%;
  transform: translateX(-50%);
  background: linear-gradient(180deg, transparent 0%, rgba(255, 255, 255, 0.85) 50%, transparent 100%);
  background-repeat: no-repeat; background-size: 100% 42%; background-position: 50% 50%;
  -webkit-mask: linear-gradient(90deg, transparent, #000 50%, transparent);
  mask: linear-gradient(90deg, transparent, #000 50%, transparent);
  filter: blur(12px); opacity: 0.22;
  animation: gtc-pillar-flow 6s ease-in-out infinite;
}
@keyframes gtc-pillar-flow { 0% { background-position: 50% 128%; } 100% { background-position: 50% -28%; } }
/* Prismatic-burst card background (reactbits.dev/backgrounds/prismatic-burst via the shared
   WebGL2 port in prismaticBurst.ts) — agent-prize cards only: tier-tinted rays radiating out
   from behind the mascot, revealed with the prize. Replaces the pillar on those cards. The
   canvas clears to opaque black, so screen-blend it like the pillar: black is neutral under
   screen, leaving the card's rarity-tinted interior visible with the rays added on top. */
.gtc-burst {
  position: absolute; inset: 0; z-index: 0; overflow: hidden; pointer-events: none;
  border-radius: inherit; opacity: 0; transition: opacity 700ms var(--ease);
  mix-blend-mode: screen;
}
.gacha-stage.is-revealed .gtc-burst { opacity: 1; }
/* Scrim over the ray field: dims the top (rarity chip + name) and bottom (description)
   bands so the text stays legible, while the centre — behind the mascot — stays hot.
   Painted INSIDE the screen-blended host, so darkening here just fades the rays out. */
.gtc-burst::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(0, 0, 0, 0.62), transparent 34%, transparent 60%, rgba(0, 0, 0, 0.68));
}
/* The minted agent's live mascot, where the icon medallion sits on other prizes. Sized so
   the resting ball (~48% of the short side) reads close to the 100px medallion while keeping
   the headroom the reference jump/celebrate arcs need. */
.gtc-mascot { display: block; width: 172px; height: 172px; }
/* Currency prize art — the branded animated SVGs (credit coin / power bolt / XP badge),
   free-floating like the agent card's mascot rather than boxed in the icon medallion. */
.gtc-prize-img { display: block; width: 116px; height: 116px; filter: drop-shadow(0 6px 18px rgba(0, 0, 0, 0.45)); }
/* The upgrade card's crown/star pop (upgrade.svg) — its artwork sits smaller inside a
   500x500 viewBox than the currency icons, so it gets a larger box to match their weight. */
.gtc-prize-img--upgrade { width: 168px; height: 168px; }
.gtc-foil {
  position: absolute; inset: 0; z-index: 4; pointer-events: none; border-radius: var(--radius-lg);
  background: linear-gradient(115deg, transparent 42%, rgba(255, 255, 255, 0.14) 49%, transparent 56%);
  transform: translateX(-120%); animation: gacha-sheen 3s ease-in-out infinite;
}
/* Prize CONTENT — its own layer, hidden until the card lands (the shake), then it pops in.
   Three rows: NAME centered in the top half, ICON dead-centre, DESCRIPTION in the bottom
   half. The rarity chip is pinned to the top corners, out of the row flow. */
.gtc-content {
  position: relative; z-index: 2; flex: 1; width: 100%;
  display: grid; grid-template-rows: 1fr auto 1fr; align-items: center; justify-items: center;
  opacity: 0; transition: opacity 260ms var(--ease);
}
.gacha-stage.is-revealed .gtc-content { opacity: 1; }
.gtc-header { position: absolute; top: 0; left: 0; right: 0; z-index: 1; display: flex; align-items: center; justify-content: space-between; padding: 1px 3px; }
.gacha-card--front .gacha-reveal-rarity { font-size: 11px; font-weight: 800; letter-spacing: 1.6px; text-transform: uppercase; color: var(--gtc-accent); }
.gtc-gem { display: inline-flex; color: var(--gtc-accent); filter: drop-shadow(0 0 6px var(--gtc-accent)); }
.gtc-gem .material-symbols-rounded { font-size: 19px; }
/* NAME — the card's headline, centred in the top half. Theme-independent light: the card is
   always dark, so the theme --text token would vanish against it. */
.gtc-name { align-self: center; text-align: center; padding: 0 8px; font-size: 25px; font-weight: 800; line-height: 1.15; letter-spacing: -0.3px; color: #f4f6fb; }
/* ICON — dead-centre of the card. */
.gtc-icon-wrap { display: flex; align-items: center; justify-content: center; }
.gacha-card--front .gacha-reveal-icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 100px; height: 100px; margin: 0; border-radius: 50%; color: #fff;
  background: color-mix(in srgb, var(--gtc-accent) 16%, rgba(0, 0, 0, 0.5));
  box-shadow: inset 0 0 0 1.5px color-mix(in srgb, var(--gtc-accent) 60%, transparent), 0 0 30px -4px var(--gtc-accent);
}
.gacha-card--front .gacha-reveal-icon .material-symbols-rounded { font-size: 56px; filter: drop-shadow(0 2px 6px rgba(0, 0, 0, 0.5)); }
/* DESCRIPTION — one-sentence use case, centred in the bottom half. */
.gtc-desc { align-self: center; text-align: center; max-width: 90%; font-size: 12px; line-height: 1.45; color: rgba(255, 255, 255, 0.62); }
/* Card-progress line on a card reveal — "7/9 to ★4 · name" (or a "ready" call-out). Frosted
   pill in the card accent so the win means something on the spot. */
.gtc-progress {
  align-self: center; margin-top: 8px; padding: 4px 11px; border-radius: 999px;
  font-size: 11.5px; font-weight: 700; font-variant-numeric: tabular-nums; letter-spacing: 0.1px;
  color: #fff; background: rgba(255, 255, 255, 0.14); border: 1px solid rgba(255, 255, 255, 0.22);
}
.gtc-progress.is-ready { background: color-mix(in srgb, var(--gtc-accent, #38bdf8) 34%, transparent); border-color: transparent; }
/* Rarity → accent var + outer glow (icon gold-fills on legendary). */
.gacha-stage--rare .gacha-card--front { --gtc-border: linear-gradient(140deg, #7dd3fc, #0ea5e9 50%, #7dd3fc); --gtc-accent: #38bdf8; box-shadow: 0 30px 56px -14px rgba(0, 0, 0, 0.65), 0 0 48px -8px #0ea5e9; }
.gacha-stage--epic .gacha-card--front { --gtc-border: linear-gradient(140deg, #e879f9, #a855f7 50%, #e879f9); --gtc-accent: #c084fc; box-shadow: 0 30px 56px -14px rgba(0, 0, 0, 0.65), 0 0 54px -6px #a855f7; }
.gacha-stage--legendary .gacha-card--front { --gtc-border: linear-gradient(140deg, #fde047, #f5a623 50%, #fde047); --gtc-accent: #ffce5a; box-shadow: 0 30px 56px -14px rgba(0, 0, 0, 0.65), 0 0 72px -6px #ffce5a; }
.gacha-stage--legendary .gacha-card--front .gacha-reveal-icon { background: linear-gradient(135deg, #ffce5a, #f5a623); color: #1a1400; }
/* Hints. */
.gacha-hint, .gacha-continue { position: relative; z-index: 1; }
.gacha-hint { display: inline-flex; flex-direction: column; align-items: center; gap: 1px; color: rgba(255, 255, 255, 0.82); font-size: 13px; font-weight: 600; }
.gacha-hint-arrow { font-size: 26px !important; color: #fff; animation: gacha-bob 1.2s var(--ease) infinite; }
@keyframes gacha-bob { 0%, 100% { transform: translateY(0); opacity: 0.65; } 50% { transform: translateY(-8px); opacity: 1; } }
.gacha-continue { font-size: 12px; color: rgba(255, 255, 255, 0.6); opacity: 0; transition: opacity 240ms var(--ease); }
.gacha-stage.is-revealed .gacha-continue { opacity: 1; }
.gacha-stage.is-revealing .gacha-hint, .gacha-stage.is-revealed .gacha-hint { display: none; }
/* Booster-pack progress dots — one per card in the hand; fills as each is flipped. */
.gacha-progress { position: relative; z-index: 1; display: inline-flex; gap: 7px; align-items: center; }
.gacha-dot { width: 7px; height: 7px; border-radius: 50%; background: rgba(255, 255, 255, 0.22); transition: background 220ms var(--ease), transform 220ms var(--ease); }
.gacha-dot.is-done { background: #fff; transform: scale(1.15); }
/* Confetti on reveal reuses the shared new-agent-deploy shower (fireConfetti / .confetti-canvas). */

/* ===== Star-up confirm — an agent card: name/star head, the mascot idling over a
   prismatic-burst backdrop, the three stats the upgrade moves (+% gains in green),
   and Cancel / Upgrade (x/x). The burst canvas fills the card behind everything. ===== */
.upg-overlay {
  /* Above the Yield sheet (z 1100) it's launched from — matches .confirm-overlay (1400). */
  position: fixed; inset: 0; z-index: 1500; display: flex; align-items: center; justify-content: center; padding: 20px;
  background: color-mix(in srgb, var(--bg) 70%, transparent); backdrop-filter: blur(5px);
  opacity: 0; transition: opacity 200ms var(--ease);
}
.upg-overlay.is-open { opacity: 1; }
.upg-card {
  position: relative; overflow: hidden;
  /* Same footprint + radius + throw as the gacha prize card (300×416) so the two
     card moments in the reinvest loop read as one family. */
  width: 300px; height: 416px; max-width: 100%;
  display: flex; flex-direction: column;
  border-radius: var(--radius-lg); padding: 16px;
  /* Near-black base so the burst's additive rays carry the card's color story. */
  background: #08080c;
  box-shadow: 0 30px 56px -14px rgba(0, 0, 0, 0.65), inset 0 0 0 1.5px rgba(255, 255, 255, 0.14);
  transform: translateY(12px) scale(0.96); opacity: 0; transition: transform 280ms var(--ease), opacity 200ms var(--ease);
}
.upg-overlay.is-open .upg-card { transform: none; opacity: 1; }
/* Success beat 1 — crescendo shake: barely a tremor at first, vibrant by the end
   (amplitude + tilt grow through the keyframes; ends mid-throw, hidden by the flash). */
.upg-card.is-shaking { animation: upg-shake-card 500ms linear; }
@keyframes upg-shake-card {
  0% { transform: translate(0, 0) rotate(0deg); }
  15% { transform: translate(-0.5px, 0.5px) rotate(-0.1deg); }
  30% { transform: translate(1px, -1px) rotate(0.15deg); }
  45% { transform: translate(-2px, 1.5px) rotate(-0.3deg); }
  60% { transform: translate(3px, -2.5px) rotate(0.5deg); }
  72% { transform: translate(-4.5px, 3.5px) rotate(-0.8deg); }
  84% { transform: translate(6px, -4.5px) rotate(1.1deg); }
  92% { transform: translate(-7px, 5px) rotate(-1.3deg); }
  100% { transform: translate(7px, -5px) rotate(1.4deg); }
}
/* Success beat 2 — the card bounces up and spins a full turn, landing upright
   (360° = upright, so the face never ends mirrored). Perspective comes from the
   overlay so the spin reads as 3D. */
.upg-overlay { perspective: 1200px; }
.upg-card.is-spinning { animation: upg-card-spin 750ms var(--ease); }
@keyframes upg-card-spin {
  0% { transform: rotateY(0deg) translateY(0) scale(1); }
  45% { transform: rotateY(200deg) translateY(-16px) scale(1.1); }
  100% { transform: rotateY(360deg) translateY(0) scale(1); }
}
/* Well dimmed — an ambient glow behind the mascot, not a light show; the mascot
   + stats stay the brightest things on the card. On upgrade success it flares
   to full brightness (.is-bright + a live intensity/speed bump) to celebrate. */
.upg-burst { position: absolute; inset: 0; pointer-events: none; opacity: 0.5; transition: opacity 600ms var(--ease); }
.upg-burst.is-bright { opacity: 1; }
.upg-card-head { position: relative; z-index: 1; display: flex; align-items: center; justify-content: space-between; gap: 10px; color: #fff; }
.upg-card-name {
  font-family: var(--font-display); font-size: 18px; font-weight: 600;
  text-shadow: 0 1px 8px rgba(0, 0, 0, 0.45);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.upg-star-slot { display: inline-flex; flex: none; }
/* Star glaze — when the badge steps up: a scale pop plus a shine sweeping across it. */
.upg-star-glaze { position: relative; overflow: hidden; border-radius: 999px; animation: upg-star-pop 620ms var(--ease); }
.upg-star-glaze::after {
  content: ""; position: absolute; inset: -40%;
  background: linear-gradient(115deg, transparent 32%, rgba(255, 255, 255, 0.95) 50%, transparent 68%);
  transform: translateX(-130%); animation: upg-star-shine 900ms var(--ease) 140ms forwards;
}
@keyframes upg-star-pop { 0% { transform: scale(1); } 35% { transform: scale(1.4); } 70% { transform: scale(0.94); } 100% { transform: scale(1); } }
@keyframes upg-star-shine { to { transform: translateX(130%); } }
/* The mascot floats over the burst's bright core; its canvas is transparent.
   80% of the stage (not full-bleed) so the card keeps air around it. */
.upg-stage { position: relative; z-index: 1; flex: 1; min-height: 0; }
.upg-mascot { position: absolute; inset: 0; margin: auto; display: block; width: 80%; height: 80%; cursor: pointer; }
/* Stat tiles — Gemini-style hierarchy: the display-face number leads, the green
   gain chip is the second read, the label whispers. Perspective is for the
   post-upgrade flip, where each tile turns edge-on and lands on its new value. */
.upg-stats { position: relative; z-index: 1; display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 6px; perspective: 640px; }
.upg-stat.is-flipping { animation: upg-stat-flip 460ms var(--ease); }
@keyframes upg-stat-flip { 0% { transform: rotateX(0deg); } 50% { transform: rotateX(92deg); } 100% { transform: rotateX(0deg); } }
.upg-stat {
  display: flex; flex-direction: column; align-items: center; gap: 3px; padding: 10px 4px 8px;
  border-radius: var(--radius-md); text-align: center; color: #fff;
  background: rgba(0, 0, 0, 0.45); backdrop-filter: blur(3px);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.09);
}
.upg-stat-value { font-family: var(--font-display); font-size: 17px; font-weight: 700; font-variant-numeric: tabular-nums; line-height: 1.1; }
.upg-stat-delta {
  font-size: 11.5px; font-weight: 800; font-variant-numeric: tabular-nums; color: var(--ok);
  background: color-mix(in srgb, var(--ok) 16%, transparent); border-radius: 999px; padding: 1.5px 8px;
}
.upg-stat-label { font-size: 10px; color: rgba(255, 255, 255, 0.6); }
/* Placeholder delta (previewStarUp) — reserves the chip's height so a stat with no % gain still
   lines its value/label up with the others. */
.upg-stat-delta--ghost { visibility: hidden; }
/* Preview-only bits (previewStarUp): a subtitle under the name + a card-progress bar above the
   actions. Reuse the ceremony's card chrome; these just fill the "not ready yet" state. */
.upg-preview-sub {
  position: relative; z-index: 1; text-align: center; margin: -2px 0 8px;
  font-size: 12.5px; font-weight: 700; letter-spacing: 0.2px;
  color: color-mix(in srgb, var(--grad-b) 60%, #fff);
}
.upg-prog { position: relative; z-index: 1; margin-top: 12px; }
.upg-prog-bar { height: 8px; border-radius: 999px; background: var(--bg-elev-3); overflow: hidden; }
.upg-prog-fill { display: block; height: 100%; border-radius: 999px; background: linear-gradient(90deg, var(--grad-a), var(--grad-b) 55%, var(--grad-c)); transition: width 0.3s var(--ease); }
.upg-prog-label { margin-top: 7px; text-align: center; font-size: 12px; font-weight: 700; font-variant-numeric: tabular-nums; color: var(--text-dim); }
/* Clear breathing room between the progress message and the action buttons (they were crowded). */
.upg-prog + .upg-actions { margin-top: 18px; }
.upg-actions { position: relative; z-index: 1; display: flex; gap: 8px; margin-top: 12px; }
/* The 300px card leaves ~130px per button — tighten so "Upgrade (x/x)" stays one line. */
.upg-actions .upg-btn { padding: 11px 6px; font-size: 13.5px; white-space: nowrap; }
.upg-actions .upg-btn--go { flex: 1.35; }
/* The screen joins the card's crescendo — same subtle→vibrant ramp, smaller travel. */
.upg-screen-shake { animation: upg-shake-screen 550ms linear both; }
@keyframes upg-shake-screen {
  0% { transform: translate(0, 0); }
  25% { transform: translate(0.5px, -0.5px); }
  45% { transform: translate(-1px, 1px); }
  62% { transform: translate(2px, -1.5px); }
  76% { transform: translate(-3px, 2px); }
  88% { transform: translate(4px, -3px); }
  100% { transform: translate(0, 0); }
}
@media (prefers-reduced-motion: reduce) {
  .upg-card.is-shaking, .upg-card.is-spinning, .upg-screen-shake,
  .upg-star-glaze, .upg-star-glaze::after, .upg-stat.is-flipping { animation: none; }
}
.upg-btn { flex: 1; display: inline-flex; align-items: center; justify-content: center; gap: 6px; padding: 12px; border: none; border-radius: 999px; cursor: pointer; font: inherit; font-size: 14px; font-weight: 650; transition: transform var(--ease) 120ms, filter var(--ease) 120ms; }
.upg-btn:active { transform: scale(0.97); }
.upg-btn--ghost { background: var(--bg-elev-3); color: var(--text); }
.upg-btn--go { background: linear-gradient(120deg, var(--grad-a), var(--grad-b) 55%, var(--grad-c)); color: #fff; }
.upg-btn--go:hover { filter: brightness(1.06); }
.upg-btn--go .material-symbols-rounded { font-size: 18px; }

@media (prefers-reduced-motion: reduce) {
  .gacha-spinner, .gacha-spinner.is-spinning { animation: none; }
  .gacha-spinner::before { animation: none; }
  .gacha-shimmer, .gacha-hint-arrow, .gtc-pillar::after { animation: none; }
  .gacha-stage.flash::before { animation: none; }
  .gacha-stage.shake .gacha-card-wrap { animation: none; }
  .gacha-stage.is-revealed .gacha-reveal-icon { animation: none; }
  .upg-card { transition: opacity 200ms var(--ease); transform: none; }
}
@media (max-width: 480px) { .earn-pockets { grid-template-columns: 1fr; } }

/* Hide the authed app shell until boot.ts confirms the user is signed in. The Tasks
   view is static HTML, so without this it paints for the ~0.5–1s the /api/me check is
   in flight before the sign-in screen comes up (a flash of authenticated content for
   logged-out visitors). index.html sets .is-booting before first paint; boot.ts clears
   it the moment auth passes. visibility (not display) avoids a reflow on reveal. */
.is-booting .layout { visibility: hidden; }

/* ── Post-purchase welcome / "deploying your agent" loading screen ─────────── */
/* Post-purchase reload: hide the app shell until the loading overlay is up, so the
   empty tasks screen never flashes before it (body's var(--bg) shows behind, matching
   the overlay). main.ts clears .is-welcoming the moment showWelcome() runs. */
.is-welcoming .layout { visibility: hidden; }
.welcome-overlay {
  position: fixed;
  inset: 0;
  z-index: 9999;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bg);
  opacity: 1;
  transition: opacity 0.5s var(--ease);
}
.welcome-overlay.done {
  opacity: 0;
  pointer-events: none;
}
.welcome-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
  padding: 24px;
  max-width: 360px;
  text-align: center;
}
.welcome-mark {
  font-size: 56px;
  color: var(--accent);
  font-variation-settings: "FILL" 1, "wght" 500, "GRAD" 0, "opsz" 48;
  animation: welcome-pulse 1.6s var(--ease) infinite;
}
@keyframes welcome-pulse {
  0%, 100% { transform: scale(1); opacity: 0.8; }
  50% { transform: scale(1.12); opacity: 1; }
}
.welcome-title {
  font-family: var(--font-display);
  font-size: 24px;
  font-weight: 600;
  color: var(--text);
}
.welcome-sub {
  font-size: 14px;
  color: var(--text-dim);
  min-height: 20px;
}
.welcome-bar {
  width: 240px;
  height: 6px;
  border-radius: 999px;
  background: var(--bg-elev-2);
  overflow: hidden;
}
.welcome-bar-fill {
  width: 0%;
  height: 100%;
  border-radius: 999px;
  background-color: var(--accent);
  background-image: linear-gradient(90deg, transparent, color-mix(in srgb, var(--bg) 45%, transparent), transparent);
  background-size: 200% 100%;
  transition: width 0.3s var(--ease);
  animation: welcome-shimmer 1.4s linear infinite;
}
@keyframes welcome-shimmer {
  0% { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}
.confetti-canvas {
  position: fixed;
  inset: 0;
  z-index: 10000;
  pointer-events: none;
}
@media (prefers-reduced-motion: reduce) {
  .welcome-mark, .welcome-bar-fill { animation: none; }
}

/* ============================================================================
   Landing page (pre-auth marketing, superpower.io) — landing.ts
   Minimalist, Gemini Material-3. The hero is an abstract WebGL "organic sphere"
   (orb.ts) standing in for the agent; everything else is quiet and spacious.
   Prefixed .lp-*; reuses the design tokens, no landing-only palette.
   ========================================================================== */
html.lp-open, html.lp-open body { overflow: hidden; }

.lp-host {
  position: fixed;
  inset: 0;
  z-index: 3000;
  overflow-y: auto;
  overflow-x: hidden;
  scroll-padding-top: 64px;
  scroll-behavior: smooth;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-ui);
  -webkit-font-smoothing: antialiased;
}
.lp-root { min-height: 100%; display: flex; flex-direction: column; }
.lp-main { position: relative; z-index: 1; display: flex; flex-direction: column; }

/* ---- scroll-driven background (fixed; cross-fades + scales with --bgP) ---- */
.lp-bg { position: fixed; inset: 0; z-index: 0; pointer-events: none; overflow: hidden; }
.lp-bg span { position: absolute; inset: -8%; display: block; will-change: opacity, transform; }
.lp-bg-a {
  opacity: calc(1 - var(--bgP, 0));
  transform: scale(calc(1 + var(--bgP, 0) * 0.22));
  background: radial-gradient(1000px 660px at 50% -10%, color-mix(in srgb, #9b5cff 20%, transparent), transparent 60%);
}
.lp-bg-b {
  opacity: var(--bgP, 0);
  transform: scale(calc(1.22 - var(--bgP, 0) * 0.22));
  background:
    radial-gradient(860px 680px at 12% 6%, color-mix(in srgb, #ff6a1e 24%, transparent), transparent 56%),
    radial-gradient(980px 760px at 90% 94%, color-mix(in srgb, #2f7bff 30%, transparent), transparent 58%);
}

/* ---- nav ---- */
.lp-nav {
  position: sticky;
  top: 0;
  z-index: 30;
  backdrop-filter: saturate(140%) blur(14px);
  background: color-mix(in srgb, var(--bg) 64%, transparent);
  border-bottom: 1px solid transparent;
  transition: border-color 0.2s var(--ease), background 0.2s var(--ease);
}
.lp-nav-stuck { border-bottom-color: var(--border); background: color-mix(in srgb, var(--bg) 86%, transparent); }
.lp-nav-inner { max-width: 1100px; margin: 0 auto; padding: 13px 24px; display: flex; align-items: center; gap: 18px; }
.lp-brand { display: inline-flex; align-items: center; gap: 9px; text-decoration: none; color: var(--text); font-family: var(--font-display); font-weight: 700; font-size: 19px; letter-spacing: -0.3px; }
.lp-mark { font-variation-settings: "FILL" 1, "wght" 500, "GRAD" 0, "opsz" 24; font-size: 24px; }
.lp-mark-grad { background: linear-gradient(135deg, var(--grad-a), var(--grad-b) 55%, var(--grad-c)); -webkit-background-clip: text; background-clip: text; color: transparent; }
.lp-nav-links { display: flex; gap: 4px; }
.lp-nav-links a { color: var(--text-dim); text-decoration: none; font-size: 14px; font-weight: 500; padding: 8px 12px; border-radius: 999px; transition: color 0.15s var(--ease), background 0.15s var(--ease); }
.lp-nav-links a:hover { color: var(--text); background: var(--bg-elev-1); }
.lp-nav-actions { display: flex; align-items: center; gap: 8px; margin-left: auto; }
.lp-icon-btn { display: inline-flex; align-items: center; gap: 5px; height: 38px; padding: 0 12px; border: 1px solid var(--border); background: transparent; color: var(--text-dim); border-radius: 999px; cursor: pointer; font-family: var(--font-ui); font-size: 13px; font-weight: 600; transition: color 0.15s var(--ease), border-color 0.15s var(--ease), background 0.15s var(--ease); }
.lp-icon-btn:hover { color: var(--text); border-color: var(--border-strong); background: var(--bg-elev-1); }
.lp-icon-btn .material-symbols-rounded { font-size: 19px; }

/* ---- buttons ---- */
.lp-btn { display: inline-flex; align-items: center; justify-content: center; gap: 7px; border: 1px solid transparent; border-radius: 999px; padding: 12px 22px; min-height: 44px; font-family: var(--font-ui); font-size: 14.5px; font-weight: 600; cursor: pointer; white-space: nowrap; transition: transform 0.13s var(--ease), filter 0.15s var(--ease), background 0.15s var(--ease), border-color 0.15s var(--ease); }
.lp-btn:active { transform: scale(0.97); }
.lp-btn .material-symbols-rounded { font-size: 19px; }
.lp-btn-primary { background: var(--accent); color: var(--on-accent); }
.lp-btn-primary:hover { filter: brightness(1.08); }
.lp-btn-ghost { background: transparent; color: var(--text); border-color: var(--border-strong); }
.lp-btn-ghost:hover { background: var(--bg-elev-1); }
.lp-btn-lg { min-height: 52px; padding: 15px 28px; font-size: 15.5px; }
.lp-btn-xl { min-height: 58px; padding: 17px 38px; font-size: 17px; }
.lp-btn-sm { min-height: 36px; padding: 8px 16px; font-size: 13px; }
.lp-nav-cta { padding: 9px 18px; min-height: 38px; }
.lp-btn-spotlight {
  color: #fff; border: none;
  background: linear-gradient(120deg, var(--grad-a), var(--grad-b) 52%, var(--grad-c));
  background-size: 180% 180%;
  box-shadow: 0 10px 30px color-mix(in srgb, var(--grad-b) 36%, transparent);
  animation: lp-shift 9s ease-in-out infinite;
}
.lp-btn-spotlight:hover { filter: brightness(1.05); transform: translateY(-1px); }
.lp-btn-spotlight:active { transform: scale(0.98); }

/* ---- shared primitives ---- */
.lp-eyebrow { display: inline-flex; align-items: center; gap: 7px; font-size: 13px; font-weight: 600; letter-spacing: 0.2px; color: var(--text-dim); padding: 7px 14px; border: 1px solid var(--border); border-radius: 999px; background: color-mix(in srgb, var(--bg-elev-1) 70%, transparent); }
.lp-eyebrow .lp-mark { font-size: 17px; }
.lp-eyebrow-center { margin: 0 auto; }
.lp-h1 { margin: 26px 0 0; font-family: var(--font-display); font-weight: 700; font-size: clamp(38px, 6vw, 66px); line-height: 1.03; letter-spacing: -1.6px; color: var(--text); }
.lp-h2 { margin: 16px 0 0; font-family: var(--font-display); font-weight: 700; font-size: clamp(27px, 3.6vw, 42px); line-height: 1.08; letter-spacing: -0.8px; color: var(--text); }
.lp-h2-center { text-align: center; }
.lp-lede { margin: 18px 0 0; max-width: 50ch; font-size: clamp(16px, 1.5vw, 18.5px); line-height: 1.6; color: var(--text-dim); }
.lp-lede-center { margin-left: auto; margin-right: auto; text-align: center; }

/* ---- the organic-sphere orb ---- */
.lp-orb { position: relative; display: grid; place-items: center; }
/* Hero orb is a big, immersive backdrop the copy overlays (absolute-centered). */
/* The hero orb scales up + fades as you scroll (you "dive into" it) via --heroP. */
.lp-orb-hero { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%) scale(calc(1 + var(--heroP, 0) * 1.45)); opacity: calc(1 - var(--heroP, 0) * 1.15); width: min(820px, 96vw, 90vh); aspect-ratio: 1; z-index: 0; pointer-events: none; will-change: transform, opacity; }
.lp-orb-portal { width: min(620px, 82vw, 58vh); aspect-ratio: 1; margin: 0 auto 2px; }
.lp-orb-canvas { position: relative; z-index: 1; width: 100%; height: 100%; display: block; }
/* Faint ambient behind the canvas; the orb's own WebGL bloom carries the glow. */
.lp-orb-halo {
  position: absolute; inset: 2%; z-index: 0; border-radius: 50%;
  background: radial-gradient(closest-side,
    color-mix(in srgb, #2f74ff 30%, transparent),
    color-mix(in srgb, #ff5a24 12%, transparent) 56%,
    transparent 72%);
  filter: blur(46px);
  opacity: 0.5;
  animation: lp-breathe 7s ease-in-out infinite;
}
/* CSS fallback sphere — only when WebGL is unavailable (.is-fallback set by JS) */
.lp-orb-fallback { display: none; }
.lp-orb.is-fallback .lp-orb-canvas { display: none; }
.lp-orb.is-fallback .lp-orb-fallback {
  display: block; position: absolute; z-index: 1; inset: 12%; border-radius: 50%;
  background:
    radial-gradient(circle at 36% 28%, #cde6ff 0%, transparent 38%),
    conic-gradient(from 210deg, var(--grad-a), var(--grad-b) 40%, var(--grad-c) 66%, var(--grad-a));
  box-shadow: inset -16px -22px 40px rgba(0,0,0,0.4), 0 20px 60px color-mix(in srgb, var(--grad-b) 40%, transparent);
  filter: saturate(1.05);
  animation: lp-spin 18s linear infinite;
}

/* ---- hero: copy overlays the orb, sitting in its dark hollow center ---- */
.lp-hero {
  position: relative; width: 100%; margin: 0 auto;
  min-height: 100svh;
  padding: 84px 24px 64px;
  display: grid; place-items: center; text-align: center; overflow: hidden;
}
.lp-hero-copy { position: relative; z-index: 2; display: flex; flex-direction: column; align-items: center; max-width: 540px; transform: translateY(calc(var(--heroP, 0) * -40px)) scale(calc(1 - var(--heroP, 0) * 0.08)); opacity: calc(1 - var(--heroP, 0) * 1.55); will-change: transform, opacity; }
/* Theme-aware scrim so the headline stays legible over the orb's bright ribbons. */
.lp-hero-copy::before {
  content: ""; position: absolute; z-index: -1; inset: -44% -16%;
  background: radial-gradient(ellipse 60% 54% at 50% 50%,
    color-mix(in srgb, var(--bg) 92%, transparent) 0%,
    color-mix(in srgb, var(--bg) 80%, transparent) 44%,
    transparent 76%);
}
.lp-hero-copy .lp-h1, .lp-hero-copy .lp-lede { text-shadow: 0 2px 26px color-mix(in srgb, var(--bg) 78%, transparent); }
.lp-cta-row { display: flex; flex-wrap: wrap; justify-content: center; gap: 12px; margin-top: 30px; }
.lp-scroll-hint {
  position: absolute; bottom: 22px; left: 50%; transform: translateX(-50%);
  display: grid; place-items: center; width: 40px; height: 40px; border-radius: 50%;
  border: 1px solid var(--border); background: color-mix(in srgb, var(--bg-elev-1) 70%, transparent);
  color: var(--text-faint); cursor: pointer; transition: color 0.15s var(--ease), border-color 0.15s var(--ease);
  animation: lp-bob 2.4s ease-in-out infinite;
}
.lp-scroll-hint:hover { color: var(--text); border-color: var(--border-strong); }
.lp-scroll-hint .material-symbols-rounded { font-size: 24px; }

.lp-section-head { display: flex; flex-direction: column; align-items: center; text-align: center; max-width: 760px; margin: 0 auto; }

/* ---- what is Genie + how it delivers value (narrative + Works/Learns/Earns) ---- */
.lp-what { max-width: 1100px; width: 100%; margin: 0 auto; padding: clamp(72px, 11vw, 140px) 24px clamp(56px, 9vw, 110px); display: flex; flex-direction: column; align-items: center; scroll-margin-top: 72px; }
/* Scrubbed entrance: the section scales + fades UP into focus as you scroll in
   (fallback 1 = fully visible, so reduced-motion / no-JS shows it normally). */
.lp-what .lp-section-head, .lp-what .lp-values {
  transform: scale(calc(0.78 + var(--whatP, 1) * 0.22));
  opacity: calc(var(--whatP, 1) * 1.15 - 0.15);
  transform-origin: center center;
  will-change: transform, opacity;
}
.lp-values { list-style: none; margin: clamp(40px, 6vw, 64px) 0 0; padding: 0; display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; width: 100%; }
.lp-value { position: relative; padding: 30px 26px 28px; border: 1px solid var(--border); border-radius: var(--radius-lg); background: color-mix(in srgb, var(--bg-elev) 55%, transparent); transition: border-color 0.2s var(--ease), transform 0.2s var(--ease), background 0.2s var(--ease); }
.lp-value:hover { border-color: var(--border-strong); transform: translateY(-3px); background: var(--bg-elev); }
.lp-value-n { position: absolute; top: 22px; right: 24px; font-family: var(--font-display); font-weight: 700; font-size: 13px; color: var(--text-faint); font-variant-numeric: tabular-nums; }
.lp-value-icon { font-size: 34px; font-variation-settings: "FILL" 1, "wght" 500; background: linear-gradient(135deg, var(--grad-a), var(--grad-b) 55%, var(--grad-c)); -webkit-background-clip: text; background-clip: text; color: transparent; }
.lp-value-kicker { margin: 16px 0 0; font-family: var(--font-display); font-weight: 700; font-size: 21px; letter-spacing: -0.3px; color: var(--text); }
.lp-value-body { margin: 9px 0 0; font-size: 14.5px; line-height: 1.55; color: var(--text-dim); }

/* ---- closing CTA ---- */
.lp-portal { position: relative; width: 100%; padding: clamp(64px, 10vw, 130px) 24px clamp(72px, 11vw, 150px); display: flex; flex-direction: column; align-items: center; text-align: center; scroll-margin-top: 64px; }
.lp-portal-inner { position: relative; z-index: 2; display: flex; flex-direction: column; align-items: center; max-width: 640px; }
.lp-portal .lp-btn-xl { margin-top: 30px; }

/* ---- footer ---- */
.lp-footer { border-top: 1px solid var(--border); }
.lp-footer-grid { max-width: 1100px; margin: 0 auto; padding: clamp(40px, 5vw, 60px) 24px clamp(24px, 3vw, 32px); display: grid; grid-template-columns: 1.6fr 1fr 1fr 1fr; gap: 28px; }
.lp-footer-tag { margin: 12px 0 0; color: var(--text-faint); font-size: 13.5px; max-width: 28ch; line-height: 1.5; }
.lp-footer-tag-strong { color: var(--text); font-weight: 600; margin-top: 6px; }
.lp-footer-col h4 { margin: 0 0 12px; font-size: 13px; font-weight: 600; color: var(--text); }
.lp-footer-col a { display: block; color: var(--text-faint); text-decoration: none; font-size: 13.5px; padding: 5px 0; transition: color 0.15s var(--ease); }
.lp-footer-col a:hover { color: var(--text); }
.lp-footer-base { max-width: 1100px; margin: 0 auto; padding: 16px 24px 28px; border-top: 1px solid var(--border); display: flex; align-items: center; justify-content: space-between; gap: 12px; color: var(--text-faint); font-size: 13px; }

/* ---- reveal on scroll (fade + scale-in) ---- */
.lp-host [data-reveal] { opacity: 0; transform: translateY(28px) scale(0.965); transition: opacity 0.7s var(--ease), transform 0.7s var(--ease); will-change: opacity, transform; }
.lp-host [data-reveal].in { opacity: 1; transform: none; }

/* ---- keyframes ---- */
@keyframes lp-shift { 0%, 100% { background-position: 0% 50%; } 50% { background-position: 100% 50%; } }
@keyframes lp-breathe { 0%, 100% { opacity: 0.6; transform: scale(0.97); } 50% { opacity: 0.95; transform: scale(1.03); } }
@keyframes lp-bob { 0%, 100% { transform: translateX(-50%) translateY(0); } 50% { transform: translateX(-50%) translateY(5px); } }
@keyframes lp-spin { to { transform: rotate(360deg); } }

/* ---- responsive ---- */
@media (max-width: 900px) {
  .lp-values { grid-template-columns: 1fr; max-width: 460px; margin-left: auto; margin-right: auto; gap: 16px; }
}
@media (max-width: 860px) { .lp-nav-links { display: none; } }
@media (max-width: 600px) {
  .lp-nav-inner { padding: 11px 16px; }
  .lp-hero, .lp-what, .lp-portal { padding-left: 16px; padding-right: 16px; }
  /* immersive full-bleed orb on phones (bleeds past the edges) */
  .lp-orb-hero { width: min(680px, 138vw); top: 46%; }
  .lp-h1 { font-size: clamp(34px, 11vw, 46px); }
  .lp-footer-grid { grid-template-columns: 1fr 1fr; padding-left: 16px; padding-right: 16px; }
  .lp-footer-brand { grid-column: 1 / -1; }
  .lp-cta-row .lp-btn { flex: 1 1 auto; }
  .lp-btn-xl { width: 100%; }
  .lp-lang-label { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  .lp-host { scroll-behavior: auto; }
  .lp-host [data-reveal] { opacity: 1; transform: none; transition: none; }
  .lp-orb-halo, .lp-btn-spotlight, .lp-scroll-hint, .lp-orb.is-fallback .lp-orb-fallback { animation: none; }
  /* hold the scroll-driven scale/fade static (JS also stops setting --heroP/--bgP) */
  .lp-orb-hero { transform: translate(-50%, -50%) !important; opacity: 1 !important; }
  .lp-hero-copy { transform: none !important; opacity: 1 !important; }
  .lp-bg-a { opacity: 1 !important; transform: none !important; }
  .lp-bg-b { opacity: 0 !important; }
  .lp-what .lp-section-head, .lp-what .lp-values { transform: none !important; opacity: 1 !important; }
}

/* ---- login modal overlays the landing (kept mounted behind as a blurred backdrop) ---- */
html.lp-login-open .auth-overlay {
  z-index: 3500;
  background: color-mix(in srgb, var(--bg) 52%, transparent);
  -webkit-backdrop-filter: saturate(130%) blur(11px);
  backdrop-filter: saturate(130%) blur(11px);
  animation: lp-fade-in 0.28s var(--ease);
}
html.lp-login-open .auth-card { animation: lp-card-in 0.34s var(--ease); }
@keyframes lp-fade-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes lp-card-in { from { opacity: 0; transform: translateY(14px) scale(0.96); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) {
  html.lp-login-open .auth-overlay, html.lp-login-open .auth-card { animation: none; }
}

/* ---- mascot rage-tap explode: full-screen companion effects (mascotExplodeFx.ts) ----
   The mascot's own WebGL scene stays self-contained to its canvas; these three
   pieces are what make the home hero's explode read as hitting the WHOLE
   screen instead: a full-viewport flash, a shake on the entire page, and a
   shower of blocky "pixel" confetti. z-index sits above every other overlay
   (the highest prior in this file is the welcome/confetti overlay at 10000). */
.mascot-explode-flash {
  position: fixed;
  inset: 0;
  z-index: 10500;
  background: #fff;
  pointer-events: none;
  animation: mascot-explode-flash-pop 550ms ease-out forwards;
}
@keyframes mascot-explode-flash-pop {
  0% { opacity: 0; }
  10% { opacity: 1; }
  100% { opacity: 0; }
}

/* Shakes the whole page (not just the mascot's own head) — applied to <body>
   so every fixed-position element (composer, nav, banners…) rattles together
   as one rigid unit instead of the shake being scoped to a sub-tree. */
.mascot-explode-shake { animation: mascot-explode-shake 600ms cubic-bezier(0.36, 0.07, 0.19, 0.97) both; }
@keyframes mascot-explode-shake {
  10%, 90% { transform: translate3d(-2px, 0, 0); }
  20%, 80% { transform: translate3d(5px, -3px, 0); }
  30%, 50%, 70% { transform: translate3d(-10px, 5px, 0); }
  40%, 60% { transform: translate3d(10px, -5px, 0); }
  100% { transform: translate3d(0, 0, 0); }
}
@media (prefers-reduced-motion: reduce) {
  .mascot-explode-shake { animation: none; }
}

.mascot-confetti-layer {
  position: fixed;
  inset: 0;
  z-index: 10400;
  overflow: hidden;
  pointer-events: none;
}
/* Plain solid squares, straight fall, no rotation — deliberately blocky/
   "pixel" rather than the fluttering-paper look of the welcome screen's
   rotating rect confetti (welcome.ts's fireConfetti). */
.mascot-confetti-pixel {
  position: absolute;
  top: -12px;
  animation-name: mascot-confetti-fall;
  animation-timing-function: linear;
  animation-fill-mode: forwards;
}
@keyframes mascot-confetti-fall {
  0% { transform: translate(0, 0); opacity: 1; }
  100% { transform: translate(var(--drift, 0px), 110vh); opacity: 0.85; }
}

/* ============================================================================
   Pre-auth CINEMATIC landing (landing.ts). Fully namespaced under `.lp-cine`
   with `lpc-` classes + `#lpc*` ids so nothing here collides with the app's
   global styles. Dark GSAP scroll-film; the mascot is the app's own
   createMascot(). Typography: Inter + JetBrains Mono (loaded in index.html).
   The host sits at z-index 900 — below the Privy auth overlay (z 1000).
   ============================================================================ */
.lp-cine{
  --lpc-bg:#0f0f10;--lpc-ink:#f3f3f4;--lpc-dim:#b9bcc0;--lpc-faint:#83878d;--lpc-line:rgba(255,255,255,.10);
  position:fixed;inset:0;z-index:900;overflow-x:hidden;overflow-y:auto;-webkit-overflow-scrolling:touch;
  color:var(--lpc-ink);font-family:'Inter',system-ui,sans-serif;-webkit-font-smoothing:antialiased;
  background:
    radial-gradient(1100px 720px at 50% 30%, rgba(99,27,255,.16), transparent 60%),
    radial-gradient(820px 620px at 74% 64%, rgba(198,0,255,.10), transparent 60%),
    var(--lpc-bg);
}
.lp-cine *{box-sizing:border-box;margin:0;padding:0}
.lp-cine h1{font-size:clamp(2rem,5.6vw,4.6rem);line-height:1.03;letter-spacing:-.032em;font-weight:700;text-shadow:0 2px 50px rgba(0,0,0,.9)}
.lpc-g{background:linear-gradient(110deg,#4d7bff,#8a6cff 55%,#c600ff);-webkit-background-clip:text;background-clip:text;color:transparent}

.lpc-nav{position:fixed;top:0;left:0;right:0;z-index:40;display:flex;align-items:center;justify-content:space-between;padding:26px 40px}
.lpc-logo{height:34px;filter:brightness(0) invert(1) drop-shadow(0 1px 10px rgba(0,0,0,.5))}
.lpc-nav-r{display:flex;align-items:center;gap:16px}
.lpc-lang{font-family:'JetBrains Mono',monospace;font-size:12px;letter-spacing:.05em;color:var(--lpc-faint);border:1px solid var(--lpc-line);border-radius:100px;padding:7px 12px;cursor:pointer;user-select:none;transition:border-color .2s}
.lpc-lang:hover{border-color:var(--lpc-ink)}
.lpc-lang b{color:var(--lpc-ink);font-weight:700}
.lpc-socials{display:flex;align-items:center;gap:6px}
.lpc-social{display:inline-flex;align-items:center;justify-content:center;width:34px;height:34px;border-radius:100px;color:var(--lpc-dim);text-decoration:none;transition:color .2s,background .2s}
.lpc-social:hover{color:var(--lpc-ink);background:rgba(255,255,255,.07)}
.lpc-social svg{width:18px;height:18px;display:block}

.lpc-scroller{height:500vh;position:relative}
.lpc-stage{position:sticky;top:0;height:100vh;width:100%;overflow:hidden}
.lpc-bg{position:absolute;inset:-10%;z-index:0;opacity:0;background:radial-gradient(1100px 720px at 50% 62%, rgba(66,120,255,.15), transparent 60%)}
.lpc-world{position:absolute;inset:0;z-index:2;will-change:transform}

.lpc-net{position:absolute;inset:0;width:100%;height:100%;overflow:visible;z-index:1}
.lpc-net line{stroke:rgba(150,165,255,.30);stroke-width:1;vector-effect:non-scaling-stroke;stroke-dasharray:2 3;animation:lpc-march 2.4s linear infinite}
@keyframes lpc-march{to{stroke-dashoffset:-5}}

.lpc-agent{position:absolute;transform:translate(-50%,-50%);pointer-events:none;filter:saturate(.62) brightness(.92);transition:filter .7s ease}
.lpc-agent.is-ack{filter:saturate(.95) brightness(1.04)}

#lpcHero{position:absolute;left:50%;top:70%;width:150vmin;height:150vmin;pointer-events:none;z-index:4;filter:saturate(.9) brightness(.96);transition:filter .7s ease}
#lpcHero.is-verified{filter:saturate(1.12) brightness(1.12) drop-shadow(0 0 34px rgba(90,150,255,.55))}

.lpc-ring{position:absolute;left:50%;top:70%;width:15vmin;height:15vmin;transform:translate(-50%,-50%) rotate(-90deg);z-index:3;opacity:0;pointer-events:none}
.lpc-ring circle{fill:none;stroke:#78c8ff;stroke-width:2.4;stroke-linecap:round;filter:drop-shadow(0 0 6px rgba(120,200,255,.85))}

.lpc-beam{position:absolute;left:50%;bottom:32%;width:2px;height:0;transform:translateX(-50%);z-index:18;
  background:linear-gradient(to top,rgba(120,200,255,.12),#7fc4ff);box-shadow:0 0 14px rgba(120,200,255,.9);opacity:0}
.lpc-beam::before{content:"";position:absolute;top:-4px;left:50%;transform:translateX(-50%);width:9px;height:9px;border-radius:50%;background:#cfe6ff;box-shadow:0 0 14px rgba(150,210,255,1),0 0 26px rgba(90,160,255,.7)}
.lpc-hbeam{position:absolute;top:70%;height:2px;width:0;z-index:5;transform:translateY(-50%);opacity:0;box-shadow:0 0 14px rgba(120,200,255,.9)}
.lpc-hbeam.left{right:53%;background:linear-gradient(to left,rgba(120,200,255,.12),#7fc4ff)}
.lpc-hbeam.right{left:53%;background:linear-gradient(to right,rgba(120,200,255,.12),#7fc4ff)}
.lpc-hbeam::after{content:"";position:absolute;top:50%;transform:translateY(-50%);width:9px;height:9px;border-radius:50%;background:#cfe6ff;box-shadow:0 0 14px rgba(150,210,255,1),0 0 26px rgba(90,160,255,.7)}
.lpc-hbeam.left::after{left:-4px}
.lpc-hbeam.right::after{right:-4px}

.lpc-record{position:absolute;left:50%;top:37%;transform:translate(-50%,14px);z-index:22;opacity:0;pointer-events:none;
  width:min(430px,88vw);padding:18px 20px;border-radius:16px;font-family:'JetBrains Mono',monospace;
  background:rgba(18,20,26,.74);backdrop-filter:blur(14px);-webkit-backdrop-filter:blur(14px);
  border:1px solid rgba(255,255,255,.12);box-shadow:0 30px 80px rgba(0,0,0,.55), inset 0 0 0 1px rgba(90,150,255,.08)}
.lpc-record-hd{display:flex;align-items:center;gap:8px;font-size:11px;letter-spacing:.16em;text-transform:uppercase;color:var(--lpc-faint);margin-bottom:15px}
.lpc-record-hd .lpc-chain{margin-left:auto;color:#6b7078;font-weight:700;letter-spacing:.14em;transition:color .4s}
.lpc-record-hd .lpc-chain.on{color:#5aa0ff}
.lpc-record ul{list-style:none;display:grid;gap:12px}
.lpc-record li{display:flex;align-items:center;gap:12px;font-size:13.5px;color:#6b7078;transition:color .4s ease}
.lpc-record li.done{color:#e7e9ee}
.lpc-record .lpc-chk{flex:none;width:18px;height:18px;border-radius:50%;border:1.5px solid #3a3f48;display:grid;place-items:center;transition:.35s ease}
.lpc-record li.done .lpc-chk{background:#22c55e;border-color:#22c55e;box-shadow:0 0 12px rgba(34,197,94,.55)}
.lpc-record .lpc-chk::after{content:"✓";font-size:11px;line-height:1;color:#04210f;opacity:0;transition:opacity .3s ease}
.lpc-record li.done .lpc-chk::after{opacity:1}

.lpc-beat{position:absolute;left:0;right:0;z-index:20;text-align:center;padding:0 8vw;pointer-events:none}
.lpc-heroCopy{top:30%;transform:translateY(-50%)}
.lpc-heroCopy .lpc-cta{pointer-events:auto}
.lpc-problemCopy,.lpc-solutionCopy{top:15%;opacity:0}
#lpcSolutionCopy{top:9%}
#lpcSolutionCopy h1{font-size:clamp(2.4rem,5.2vh,4.6rem);line-height:1.04}
.lpc-eyebrow{font-family:'JetBrains Mono',monospace;font-size:12px;font-weight:700;letter-spacing:.28em;text-transform:uppercase;color:var(--lpc-dim);margin-bottom:26px}
.lpc-heroCopy h1{font-size:clamp(2.4rem,6.4vw,5.4rem);line-height:1.0}
.lpc-heroCopy h1 .lpc-g{background:linear-gradient(110deg,#0036ff,#631bff 52%,#c600ff);-webkit-background-clip:text;background-clip:text;color:transparent}
.lpc-sub{margin:22px auto 0;max-width:50ch;font-size:clamp(1rem,1.5vw,1.2rem);line-height:1.6;color:var(--lpc-dim);text-shadow:0 2px 30px rgba(0,0,0,.9)}
.lpc-cta{display:flex;gap:14px;justify-content:center;margin-top:40px}
.lpc-btn{font-family:'JetBrains Mono',monospace;font-size:.84rem;font-weight:700;letter-spacing:.1em;text-transform:uppercase;padding:14px 24px;border-radius:100px;text-decoration:none;border:0;cursor:pointer;transition:transform .2s,box-shadow .2s,border-color .2s}
.lpc-btn:hover{transform:translateY(-1px)}
.lpc-btn-p{background:#fff;color:#0f0f10}

.lpc-cue{position:fixed;left:50%;bottom:22px;transform:translateX(-50%);z-index:40;font-family:'JetBrains Mono',monospace;font-size:11px;letter-spacing:.3em;color:var(--lpc-faint);text-transform:uppercase;animation:lpc-bob 1.8s ease-in-out infinite}
@keyframes lpc-bob{0%,100%{opacity:.35;transform:translate(-50%,0)}50%{opacity:1;transform:translate(-50%,5px)}}

.lpc-finale{position:relative;z-index:1;min-height:100vh;display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;
  padding:12vh 8vw 11vh;background:radial-gradient(1000px 720px at 50% 42%, rgba(99,27,255,.16), transparent 62%),var(--lpc-bg)}
.lpc-genieWrap{position:relative;width:31vmin;height:31vmin;max-width:260px;max-height:260px;margin-bottom:-14px;will-change:transform}
.lpc-genieWrap::before{content:"";position:absolute;inset:8%;border-radius:50%;z-index:0;
  background:radial-gradient(closest-side, rgba(90,150,255,.34), transparent 72%);filter:blur(4px)}
.lpc-finale canvas{position:relative;z-index:1;width:100%;height:100%;filter:saturate(1.12) brightness(1.1) drop-shadow(0 0 34px rgba(90,150,255,.5))}
.lpc-finale .lpc-eyebrow{margin-bottom:20px}
.lpc-finale h1{max-width:15ch}
.lpc-finale .lpc-sub{max-width:52ch}
.lpc-finale .lpc-cta{margin-top:38px}
.lpc-finale .lpc-btn{padding:16px 30px;font-size:.9rem}

.lpc-bloom{position:absolute;left:50%;top:70%;width:200vmax;height:200vmax;transform:translate(-50%,-50%);border-radius:50%;z-index:36;opacity:0;pointer-events:none;
  background:radial-gradient(closest-side, rgba(244,246,255,.99), rgba(172,140,255,.95) 30%, rgba(99,27,255,.6) 55%, rgba(15,15,16,0) 72%)}
.lpc-stage .lpc-finale{position:absolute;inset:0;min-height:0;z-index:30;opacity:0;pointer-events:none}
.lpc-stage .lpc-finale.is-live{pointer-events:auto}

/* static fallback: no GSAP / prefers-reduced-motion — page reads at rest */
.lp-cine.is-static .lpc-scroller{height:auto}
.lp-cine.is-static .lpc-stage{height:auto;min-height:100vh;overflow:visible;padding:16vh 0}
.lp-cine.is-static .lpc-heroCopy{position:static;transform:none;opacity:1}
.lp-cine.is-static .lpc-problemCopy,.lp-cine.is-static .lpc-solutionCopy{display:none}
.lp-cine.is-static .lpc-cue{display:none}

@media (max-width:640px){
  .lpc-nav{padding:15px 16px}
  .lpc-logo{height:24px}
  .lpc-nav-r{gap:9px}
  .lpc-lang{padding:6px 9px;font-size:10.5px;white-space:nowrap}
  .lpc-socials{gap:2px} .lpc-social{width:30px;height:30px} .lpc-social svg{width:17px;height:17px}
  #lpcHero{width:124vmin;height:124vmin;top:76%}
  .lpc-ring{top:76%} .lpc-hbeam{top:76%} .lpc-bloom{top:76%} .lpc-beam{bottom:24%}
  .lpc-eyebrow{margin-bottom:15px;font-size:10.5px;letter-spacing:.2em}
  .lp-cine h1{font-size:clamp(2rem,8.6vw,2.7rem)}
  .lpc-heroCopy h1{font-size:clamp(2.3rem,10.5vw,3.1rem);line-height:1.03}
  .lpc-sub{font-size:1rem;max-width:30ch;margin-top:18px}
  .lpc-beat{padding:0 6vw}
  .lpc-heroCopy{top:38%}
  .lpc-problemCopy,.lpc-solutionCopy{top:23%}
  #lpcSolutionCopy{top:22%}
  #lpcSolutionCopy h1{font-size:clamp(2rem,8.6vw,2.6rem);line-height:1.05}
  .lpc-cta{flex-direction:column;align-items:center;gap:11px;margin-top:26px}
  .lpc-btn{width:min(300px,84vw);text-align:center;padding:15px 24px}
  .lpc-finale .lpc-btn{padding:15px 24px;font-size:.85rem}
  .lpc-record{width:90vw;padding:16px 18px;top:52%}
  .lpc-record li{font-size:12.5px}
  .lpc-finale{padding:12vh 7vw 12vh}
  .lpc-finale h1{font-size:clamp(2.4rem,12vw,3.4rem)}
  .lpc-finale .lpc-sub{font-size:1rem;max-width:32ch}
  .lpc-cue{bottom:15px}
}
