@import url('https://fonts.googleapis.com/css2?family=Baloo+2:wght@600;700;800&family=Manrope:wght@400;600;700;800&display=swap');

:root {
  --bg: #fdf6ec;
  --bg-elevated: #fffaf2;
  --card: #ffffff;
  --text: #3d3226;
  --text-dim: #8a7a63;
  --on-accent: #2b2118;
  --accent: #ff9d6c;
  --accent-2: #7fb685;
  --danger: #e0665a;
  --success: #6bbf7a;
  --locked: #ede4d4;

  /* chapter theme defaults (overridden per-theme below) */
  --w-1: #fdf1d8;
  --w-2: #ffe0a3;
  --w-3: #e2a640;
  --w-glow: #ffd98a;

  /* Shared RGB channels (no alpha) behind every translucent "glass" panel
     site-wide — topbar/bottom-nav chrome, node labels, Shop/Nourish/
     Convenience section headers and scene washes. Each call site keeps its
     own alpha (rgba(var(--glass-rgb), X)); only the base color swaps here
     and in the dark override below, so every one of those panels goes gray
     in dark mode instead of staying cream. */
  --glass-rgb: 255,250,240;

  /* Translucent "glass" chrome (topbar/bottom-nav) — kept separate from
     --bg/--card since these need their own alpha, not a solid fill. */
  --chrome-glass: rgba(var(--glass-rgb),0.6);
  --chrome-glass-strong: rgba(var(--glass-rgb),0.94);
}

/* Dark mode — overrides just the core UI chrome (backgrounds, text, cards,
   buttons). Deliberately does NOT touch the --w-1/--w-2/--w-3/--w-glow
   per-chapter scenery colors below ([data-theme="garden"] etc.) — those are
   each chapter's own illustrated background art, not part of light/dark.
   Toggled via js/theme.js; set on <html> (not #phone) so it's a completely
   separate attribute/mechanism from the per-view [data-theme] used for
   chapter theming — same attribute name would collide badly otherwise.
   Palette is deliberately cooler/bolder than the light theme's warm cream —
   slate/charcoal base, steel blue instead of soft mint, deeper saturated
   orange/red/green instead of pastel — a bolder, higher-contrast look. */
:root[data-color-scheme="dark"] {
  --bg: #14171c;
  --bg-elevated: #1b1f26;
  --card: #232830;
  --text: #eef1f5;
  --text-dim: #8b93a1;
  --on-accent: #10141a;
  --accent: #ff7a33;
  --accent-2: #3e8ede;
  --danger: #e5483c;
  --success: #2fb673;
  --locked: #2a2e35;
  --glass-rgb: 35,40,48;
  --chrome-glass: rgba(var(--glass-rgb),0.75);
  --chrome-glass-strong: rgba(var(--glass-rgb),0.94);
}
:root[data-color-scheme="dark"] body { background: #0f1216; }

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  height: 100%;
  height: 100dvh; /* accounts for the mobile browser chrome show/hide, unlike 100% */
  overflow: hidden;
  background: #f3e9d8;
  color: var(--text);
  font-family: 'Manrope', system-ui, sans-serif;
  -webkit-tap-highlight-color: transparent;
  overscroll-behavior: none;
  /* Without this, mobile Safari can silently auto-boost/shrink text size in
     narrow flex columns based on its own heuristics — which is exactly what
     made the bottom nav's labels (same font-size in CSS) render at visibly
     different sizes depending on how tightly each one's text fit. */
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

button {
  font-family: inherit;
  border: none;
  background: none;
  color: inherit;
  cursor: pointer;
}

h1, h2, h3, .display {
  font-family: 'Baloo 2', system-ui, sans-serif;
  letter-spacing: 0.01em;
}

#phone {
  max-width: 480px;
  height: 100%;
  margin: 0 auto;
  background: var(--bg);
  display: flex;
  flex-direction: column;
  position: relative;
  box-shadow: 0 0 60px rgba(61,50,38,0.18);
  overflow: hidden;
  /* Establishes #phone as the containing block for position:fixed
     descendants (sheets, celebration modal, toast) — without this, those
     overlays anchor to the browser viewport instead of the phone frame on
     any screen wider than the phone itself. */
  transform: translateZ(0);
}

/* Persistent, non-scrolling backdrop — recolors per active chapter while the
   path content scrolls transparently on top, for a soft depth feel. */
#realm-backdrop {
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  background: radial-gradient(140% 90% at 50% 0%, var(--w-2) 0%, var(--w-1) 100%);
  transition: background 0.7s ease;
}

/* Dark mode: the per-chapter --w-1/--w-2 pastels (cream, pale gold, etc.)
   stay as-is for in-content accents (buttons, node borders, banners — see the
   comment on the dark palette above), but this full-bleed backdrop is a
   different case — a bright cream wash behind dark cards reads as broken,
   not intentional, so it swaps to a neutral dark gray instead. */
:root[data-color-scheme="dark"] #realm-backdrop {
  background: radial-gradient(140% 90% at 50% 0%, #2f343c 0%, #1a1d22 100%);
}

.topbar, .world-tabs, #main-view, .bottom-nav {
  position: relative;
  z-index: 1;
}

@media (min-width: 481px) {
  body { display: flex; justify-content: center; align-items: center; padding: 24px 0; }
  #phone {
    width: auto;
    height: min(844px, 90vh);
    aspect-ratio: 390 / 844;
    max-width: 480px;
    border-radius: 44px;
    border: 1px solid rgba(61,50,38,0.08);
  }
}

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

.topbar {
  padding: calc(14px + env(safe-area-inset-top)) 16px 10px;
  display: flex;
  align-items: center;
  gap: 8px;
  z-index: 20;
  flex-shrink: 0;
  background: var(--chrome-glass);
}

.level-badge {
  width: 38px;
  height: 38px;
  border-radius: 50%;
  background: conic-gradient(var(--accent) calc(var(--pct) * 1%), var(--locked) 0);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  position: relative;
  cursor: pointer;
}

.level-badge::after {
  content: attr(data-level);
  width: 31px;
  height: 31px;
  border-radius: 50%;
  background: var(--bg-elevated);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: 'Baloo 2', sans-serif;
  font-weight: 800;
  font-size: 12px;
}

.xp-block { flex: 1; min-width: 0; }

.xp-row {
  display: flex;
  justify-content: space-between;
  gap: 6px;
  font-size: 10px;
  color: var(--text-dim);
  margin-bottom: 4px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  white-space: nowrap;
}

.xp-bar-track {
  height: 8px;
  border-radius: 5px;
  background: var(--locked);
  overflow: hidden;
}

.xp-bar-fill {
  height: 100%;
  border-radius: 5px;
  background: linear-gradient(90deg, var(--accent-2), var(--accent));
  transition: width 0.5s cubic-bezier(.2,.9,.3,1.2);
}

.gems-pill {
  position: relative;
  display: flex;
  align-items: center;
  gap: 3px;
  flex-shrink: 0;
  font-weight: 800;
  font-size: 13px;
  padding: 5px 8px;
  border-radius: 999px;
  background: linear-gradient(135deg, #dbeaff, #b8d4ff);
  color: #2f4d8a;
  box-shadow: 0 2px 8px rgba(61,50,38,0.08);
}

/* Gem-gain animation — a handful of gem glyphs fly IN from scattered points
   and land in the pill (which pulses on impact), then a single "+N" pops up
   with the combined total. Played once per store action, everywhere gems
   are earned in the app. */
.gems-pill.is-gaining { animation: gemPillPulse 0.42s ease-out; }
@keyframes gemPillPulse {
  0% { transform: scale(1); }
  35% { transform: scale(1.22); box-shadow: 0 0 0 6px rgba(255,214,104,0.35), 0 2px 8px rgba(61,50,38,0.08); }
  100% { transform: scale(1); }
}

.gem-gain-float {
  position: absolute;
  left: 50%;
  top: -2px;
  transform: translate(-50%, 0);
  font-weight: 800;
  font-size: 13px;
  color: #1f6b2c;
  background: #eaffea;
  padding: 2px 8px;
  border-radius: 999px;
  box-shadow: 0 2px 6px rgba(0,0,0,0.18);
  pointer-events: none;
  white-space: nowrap;
  animation: gemFloatUp 1s ease-out forwards;
  z-index: 30;
}
@keyframes gemFloatUp {
  0% { opacity: 0; transform: translate(-50%, 6px) scale(0.8); }
  15% { opacity: 1; transform: translate(-50%, -6px) scale(1.05); }
  75% { opacity: 1; transform: translate(-50%, -30px) scale(1); }
  100% { opacity: 0; transform: translate(-50%, -42px) scale(0.95); }
}

/* Each particle starts out at its own scattered (--dx, --dy) offset and
   flies INTO the pill's center, shrinking away as it "lands" — the opposite
   direction of a burst, so it reads as gems arriving, not sparks flung away. */
.gem-burst-particle {
  position: absolute;
  left: 50%;
  top: 50%;
  font-size: 15px;
  pointer-events: none;
  animation: gemFlyIn 0.48s cubic-bezier(.3,.1,.4,1) forwards;
  z-index: 29;
}
@keyframes gemFlyIn {
  0% { opacity: 0; transform: translate(-50%, -50%) translate(var(--dx), var(--dy)) scale(0.5) rotate(0deg); }
  18% { opacity: 1; }
  70% { opacity: 1; transform: translate(-50%, -50%) translate(calc(var(--dx) * 0.22), calc(var(--dy) * 0.22)) scale(1.05) rotate(140deg); }
  100% { opacity: 0; transform: translate(-50%, -50%) translate(0, 0) scale(0.35) rotate(200deg); }
}

.streak-wrap { position: relative; flex-shrink: 0; }

.streak-pill {
  display: flex;
  align-items: center;
  gap: 3px;
  font-weight: 800;
  font-size: 13px;
  padding: 5px 8px;
  border-radius: 999px;
  background: var(--card);
  box-shadow: 0 2px 8px rgba(61,50,38,0.08);
  cursor: pointer;
  transition: transform 0.15s ease, box-shadow 0.15s ease;
}
.streak-pill:active { transform: scale(0.94); }

.profile-btn {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 20px;
  flex-shrink: 0;
  background: var(--card);
  box-shadow: 0 2px 8px rgba(61,50,38,0.08);
  transition: transform 0.15s, box-shadow 0.15s;
}
.profile-btn:active { transform: scale(0.94); }
.profile-btn.is-active { box-shadow: 0 0 0 2px var(--accent), 0 2px 10px rgba(61,50,38,0.14); }

.streak-popover {
  position: absolute;
  top: calc(100% + 8px);
  /* Anchored to the trigger's own right edge rather than centered — the
     streak pill sits near the right end of the topbar (just before the
     profile button), so centering or left-anchoring a 253px-wide popover
     on it would run past the phone frame's *right* edge instead, clipping
     the calendar. Right-anchoring only needs room to the left, which a
     trigger this far right always has plenty of. */
  right: 0;
  width: 253px;
  background: var(--bg-elevated);
  border-radius: 16px;
  padding: 14px;
  box-shadow: 0 8px 24px rgba(61,50,38,0.2);
  z-index: 30;
  opacity: 0;
  transform: translateY(-6px);
  pointer-events: none;
  transition: opacity 0.15s ease, transform 0.15s ease;
}

.streak-popover.is-open {
  opacity: 1;
  transform: translateY(0);
  pointer-events: auto;
}

.streak-cal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-weight: 800;
  font-size: 13px;
  margin-bottom: 8px;
}
.cal-nav-btn {
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: var(--locked);
  color: var(--text);
  font-size: 14px;
  font-weight: 800;
  line-height: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
.cal-nav-btn:active { transform: scale(0.9); }
.cal-nav-btn:disabled { opacity: 0.35; }

.streak-cal-grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 4px;
}

.cal-weekday {
  font-size: 10px;
  color: var(--text-dim);
  text-align: center;
  font-weight: 700;
}

.cal-day {
  aspect-ratio: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 11px;
  color: var(--text);
  border-radius: 50%;
}

.cal-day.is-blank { visibility: hidden; }

.cal-day.is-active {
  background: var(--accent);
  color: var(--on-accent);
  font-weight: 800;
}

.cal-day.is-today { box-shadow: 0 0 0 2px var(--accent-2); }

.streak-cal-stats {
  display: flex;
  justify-content: space-between;
  margin-top: 10px;
  font-size: 11px;
  color: var(--text-dim);
}

.streak-cal-stats b { color: var(--text); }

.streak-cal-mult {
  font-weight: 800;
  color: var(--accent);
  white-space: nowrap;
}

/* ---------------- Chapter tabs ---------------- */

.world-tabs {
  display: flex;
  gap: 8px;
  padding: 4px 14px 14px;
  overflow-x: auto;
  scrollbar-width: none;
  /* Fades the trailing edge so a chapter strip with more chapters off-screen
     (there are 22 total, only 3-4 fit at once) visibly hints "scroll for
     more" instead of just looking like it stops — masks the tabs' own alpha
     rather than painting a gradient overlay, so it blends correctly against
     the chrome behind it in both themes without hardcoding a color. */
  -webkit-mask-image: linear-gradient(to right, black calc(100% - 32px), transparent 100%);
  mask-image: linear-gradient(to right, black calc(100% - 32px), transparent 100%);
}
.world-tabs::-webkit-scrollbar { display: none; }

.world-tab {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 8px 14px;
  border-radius: 999px;
  background: var(--card);
  color: var(--text-dim);
  font-weight: 700;
  font-size: 13px;
  white-space: nowrap;
  border: 1px solid rgba(61,50,38,0.08);
  transition: all 0.2s ease;
}

.world-tab.is-active {
  background: linear-gradient(135deg, var(--w-2), var(--w-1));
  color: var(--text);
  border-color: var(--w-3);
  box-shadow: 0 0 16px -4px var(--w-glow);
}

.world-tab.is-locked {
  opacity: 0.5;
}

/* ---------------- Main view ---------------- */

#main-view {
  position: relative;
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding-bottom: 24px;
}

/* Applied for one animation cycle whenever navigation actually changes what
   #main-view shows (a bottom-nav tab, a world tab, or opening/closing
   Profile) — not on every incidental re-render (logging a set, gaining XP),
   which would make the whole page flash on every unrelated state change. */
#main-view.view-enter { animation: viewEnter 0.32s cubic-bezier(.2,.8,.3,1); }
@keyframes viewEnter {
  from { opacity: 0; transform: translateY(10px) scale(0.99); }
  to { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  #main-view.view-enter { animation: none; }
}

/* ---------------- Coming-soon chapter page ---------------- */

.coming-soon-page {
  min-height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 40px 32px;
}

.coming-soon-page .emblem {
  font-size: 48px;
  display: block;
  margin-bottom: 10px;
  filter: drop-shadow(0 0 16px var(--w-glow));
}

.coming-soon-page h2 { margin: 0 0 4px; font-size: 24px; }
.coming-soon-page .subtitle { color: var(--text-dim); font-size: 14px; font-style: italic; margin: 0 0 14px; }
.coming-soon-page .coming-soon-copy { color: var(--text-dim); font-size: 13px; line-height: 1.6; max-width: 260px; margin-top: 18px; }

/* ---------------- Decorative scenery layer (used by the chapter backdrop) ----
   A full-bleed, hand-illustrated scene per chapter (see decorArt() in
   path.js) plus drifting fog and an ambient particle system on top. */

.scenery-layer {
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
}

.scenery { position: absolute; }

.scene-art { position: absolute; inset: 0; width: 100%; height: 100%; }

/* The ground render is dense and high-contrast, and the path nodes, labels
   and banner sit directly on top of it. Rather than washing the whole scene
   out (which destroys the detail), this stays light — legibility is bought
   back with the text halos further down instead. */
.ground-scrim {
  inset: 0;
  background:
    radial-gradient(ellipse at 50% 40%, rgba(0, 0, 0, 0) 48%, rgba(38, 28, 16, 0.26) 100%),
    linear-gradient(var(--w-1), var(--w-1));
  opacity: 0.16;
}

/* Foreground copy sits on busy, detailed terrain. The banner and each node
   label sit on their own frosted plate (below) for guaranteed contrast; the
   coming-soon page has no such plate, so it still leans on a soft halo. */
.coming-soon-page h2,
.coming-soon-page .subtitle {
  text-shadow:
    0 1px 2px rgba(255, 250, 240, 0.95),
    0 0 8px rgba(255, 250, 240, 0.85),
    0 0 16px rgba(255, 250, 240, 0.6);
}

/* Ambient particles — position/size/timing are set inline per span (see
   particleField() in path.js); this just supplies the drift/fall/twinkle
   motion per kind. */
.particle-field { inset: 0; }
.particle {
  position: absolute;
  color: var(--w-3);
  opacity: 0.55;
  line-height: 1;
}

/* Overhead camera: things travel ACROSS the ground rather than falling down
   the screen, so every motion here is lateral drift. */
.p-firefly {
  animation-name: pCross, pTwinkle;
  animation-timing-function: linear, ease-in-out;
  animation-iteration-count: infinite;
  color: #ffd76a;
  text-shadow: 0 0 6px rgba(255, 215, 106, 0.8);
}
.p-bee {
  animation: pBuzz ease-in-out infinite;
  color: #3a2c14;
  font-weight: 900;
}
.p-seed, .p-dust, .p-snow { animation: pCross linear infinite; }
.p-petal, .p-leaf { animation: pTumble linear infinite; }
.p-butterfly { animation: pFlutter ease-in-out infinite; }

@keyframes pTwinkle {
  0%, 100% { opacity: 0.2; }
  50% { opacity: 0.85; }
}
/* Carried across the frame by the breeze. */
@keyframes pCross {
  0% { transform: translate(-30px, 0); opacity: 0; }
  15% { opacity: 0.7; }
  85% { opacity: 0.7; }
  100% { transform: translate(90px, 26px); opacity: 0; }
}
@keyframes pTumble {
  0% { transform: translate(-24px, 0) rotate(0deg); opacity: 0; }
  15% { opacity: 0.85; }
  85% { opacity: 0.85; }
  100% { transform: translate(80px, 34px) rotate(180deg); opacity: 0; }
}
@keyframes pFlutter {
  0% { transform: translate(-20px, 4px) rotate(-8deg); opacity: 0; }
  20% { opacity: 0.9; }
  50% { transform: translate(30px, -16px) rotate(8deg); }
  80% { opacity: 0.9; }
  100% { transform: translate(80px, 10px) rotate(-4deg); opacity: 0; }
}
@keyframes pBuzz {
  0%, 100% { transform: translate(0, 0); opacity: 0.5; }
  25% { transform: translate(14px, -9px); opacity: 0.8; }
  50% { transform: translate(26px, 6px); opacity: 0.6; }
  75% { transform: translate(9px, 14px); opacity: 0.8; }
}

/* Low mist creeping over the ground — Forest and Highlands only. */
.fog-band {
  position: absolute;
  left: -20%;
  width: 140%;
  height: 90px;
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.45), transparent);
  filter: blur(14px);
  animation: fogDrift 26s ease-in-out infinite;
}
@keyframes fogDrift {
  0%, 100% { transform: translateX(0); opacity: 0.4; }
  50% { transform: translateX(8%); opacity: 0.7; }
}

@media (prefers-reduced-motion: reduce) {
  .particle, .fog-band { animation: none !important; }
}

.world-banner {
  position: relative;
  z-index: 3;
  margin: 14px 18px 22px;
  padding: 18px 20px 20px;
  text-align: center;
  background: linear-gradient(180deg, rgba(var(--glass-rgb), 0.94), rgba(var(--glass-rgb), 0.88));
  border: 1px solid rgba(255, 255, 255, 0.6);
  border-radius: 26px;
  backdrop-filter: blur(14px) saturate(1.15);
  -webkit-backdrop-filter: blur(14px) saturate(1.15);
  box-shadow: 0 10px 28px -14px rgba(61, 50, 38, 0.35), inset 0 1px 0 rgba(255, 255, 255, 0.7);
  animation: bannerRise 0.4s cubic-bezier(.2, .8, .3, 1);
}

.world-banner .emblem { font-size: 34px; display: block; margin-bottom: 4px; filter: drop-shadow(0 0 12px var(--w-glow)); }
.world-banner h2 { margin: 0; font-size: 22px; color: var(--w-3); }
.world-banner .subtitle { margin: 2px 0 10px; color: var(--text-dim); font-size: 13px; font-style: italic; }
.world-banner .progress-label { font-size: 12px; color: var(--w-3); font-weight: 700; }

@keyframes bannerRise {
  from { opacity: 0; transform: translateY(-6px) scale(0.98); }
  to { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .world-banner { animation: none; }
}

/* ---------------- Path ---------------- */

.path-wrap {
  position: relative;
  z-index: 1;
  width: 100%;
  padding-top: 10px;
}

/* The full-chapter ground illustration — a normal (non-fixed) child of
   #main-view, positioned absolute against it, so it scrolls in lockstep with
   the banner, trail and nodes rather than sitting behind them as a separate,
   independently-scrolling backdrop. */
.chapter-ground {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 0;
  pointer-events: none;
}

/* Covers a not-yet-unlocked chapter's ground art and every checkpoint node in
   a slowly swirling mist, edge to edge — clicks still reach the nodes
   underneath (so the existing "shake" locked-feedback still works), but
   nothing about the chapter's layout, exercises or milestones is visible
   through it. Sits above .chapter-ground (z-index 0) and .path-wrap's nodes
   (z-index 1) but below .world-banner (z-index 3), so the "locked" messaging
   up top stays legible. Near-opaque (0.9) rather than fully solid — enough
   texture and drift still reads through to look like moving mist instead of
   a flat gray card. */
.chapter-locked-shroud {
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  opacity: 0.9;
  background:
    radial-gradient(circle at 22% 22%, #ffffff 0%, transparent 58%),
    radial-gradient(circle at 78% 12%, #eef3f7 0%, transparent 52%),
    radial-gradient(circle at 38% 68%, #ffffff 0%, transparent 58%),
    radial-gradient(circle at 88% 72%, #e3ebf1 0%, transparent 52%),
    radial-gradient(circle at 8% 88%, #ffffff 0%, transparent 58%),
    linear-gradient(180deg, #e2eaf0, #ccd7df);
  background-size: 170% 170%, 160% 160%, 180% 180%, 165% 165%, 175% 175%, 100% 100%;
  filter: blur(14px);
  animation: mistSwirl 24s ease-in-out infinite;
}
@keyframes mistSwirl {
  0%, 100% { background-position: 0% 0%, 100% 0%, 0% 100%, 100% 100%, 50% 40%, 0 0; }
  50% { background-position: 22% 18%, 78% 24%, 18% 82%, 82% 76%, 60% 45%, 0 0; }
}
@media (prefers-reduced-motion: reduce) {
  .chapter-locked-shroud { animation: none; }
}


.path-node {
  position: absolute;
  transform: translate(-50%, -50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 74px;
}

.node-circle {
  width: 64px;
  height: 64px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 26px;
  background: var(--locked);
  border: 3px solid rgba(61,50,38,0.08);
  position: relative;
  transition: transform 0.15s ease;
  box-shadow: 0 3px 10px rgba(61,50,38,0.1);
}

.path-node.is-milestone .node-circle {
  width: 82px;
  height: 82px;
  font-size: 34px;
  background: radial-gradient(circle at 35% 30%, #fff6df, #ffe9b0);
  border-color: var(--w-3);
}

.path-node.is-finale .node-circle {
  width: 98px;
  height: 98px;
  font-size: 42px;
  background: radial-gradient(circle at 35% 30%, #fff0f4, #ffd7e2);
  border-color: #e0567a;
  border-width: 4px;
}

.path-node.is-finale.is-locked .node-circle { filter: grayscale(0.4); opacity: 0.55; }

.path-node.is-finale.is-active .node-circle {
  animation: pulse-ring-gold 2.2s infinite;
}

.path-node.is-finale .node-label {
  font-size: 13px;
  max-width: 110px;
  color: #e0567a;
}

@keyframes pulse-ring-gold {
  0% { box-shadow: 0 0 0 0 rgba(224, 86, 122, 0.45); }
  70% { box-shadow: 0 0 0 18px transparent; }
  100% { box-shadow: 0 0 0 0 transparent; }
}

.path-node.is-completed .node-circle {
  background: linear-gradient(145deg, var(--w-2), var(--w-1));
  border-color: var(--w-3);
}

.path-node.is-active .node-circle {
  background: linear-gradient(145deg, var(--w-2), var(--w-1));
  border-color: var(--w-3);
  animation: pulse-ring 1.8s infinite;
}

.path-node.is-locked .node-circle { filter: grayscale(0.4); opacity: 0.55; }

.path-node:active .node-circle { transform: scale(0.92); }

.node-label {
  margin-top: 6px;
  padding: 2px 9px;
  border-radius: 999px;
  background: rgba(var(--glass-rgb), 0.78);
  box-shadow: 0 1px 5px rgba(61, 50, 38, 0.1);
  font-size: 11px;
  font-weight: 700;
  text-align: center;
  color: var(--text-dim);
  line-height: 1.3;
  max-width: 96px;
}

.path-node.is-active .node-label, .path-node.is-completed .node-label { color: var(--text); }

.node-badge {
  position: absolute;
  bottom: -4px;
  right: -4px;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: var(--success);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 12px;
  border: 2px solid var(--bg);
}

.node-badge.lock { background: var(--locked); }

@keyframes pulse-ring {
  0% { box-shadow: 0 0 0 0 var(--w-glow); }
  70% { box-shadow: 0 0 0 12px transparent; }
  100% { box-shadow: 0 0 0 0 transparent; }
}

.milestone-badge {
  position: absolute;
  top: -18px;
  font-size: 18px;
}

.finale-badge {
  top: -26px;
  font-size: 26px;
  filter: drop-shadow(0 0 8px rgba(224,86,122,0.5));
}

.act-label {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  white-space: nowrap;
  text-align: center;
  z-index: 2;
}

.act-label span {
  display: inline-block;
  padding: 5px 14px;
  border-radius: 999px;
  background: rgba(255,255,255,0.75);
  border: 1px solid var(--w-3);
  color: var(--w-3);
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  box-shadow: 0 2px 8px rgba(61,50,38,0.08);
}

.finale-label span {
  background: rgba(255,255,255,0.85);
  border-color: #e0567a;
  color: #e0567a;
  box-shadow: 0 0 16px -4px rgba(224,86,122,0.5);
}

/* ---------------- Bottom nav ---------------- */

.bottom-nav {
  display: flex;
  gap: 4px;
  padding: 10px 10px calc(8px + env(safe-area-inset-bottom));
  border-top: 1px solid rgba(61,50,38,0.07);
  background: var(--chrome-glass-strong);
  backdrop-filter: blur(14px);
  position: sticky;
  bottom: 0;
  box-shadow: 0 -6px 18px -12px rgba(61,50,38,0.18);
}

/* Tabs sit directly on the bar itself (no per-tab card/border) — the
   selected state reads through a colored pill behind just the icon,
   closer to a native iOS/Android tab bar than the five bordered boxes this
   used to be, which read more like a row of separate buttons than one
   integrated nav. */
.nav-btn {
  position: relative;
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  padding: 6px 0 5px;
  border-radius: 14px;
  border: none;
  background: transparent;
  font-size: 11px;
  font-weight: 700;
  color: var(--text-dim);
  --nav-shift: 0px;
  transform: translateX(var(--nav-shift));
  transition: color 0.2s ease, transform 0.15s ease;
  -webkit-tap-highlight-color: transparent;
}

/* The two end tabs (Path, Shop) nudged the same distance toward the middle
   — purely a visual balance tweak, the five columns underneath stay equal
   width so touch targets don't change. Capped below the 6px gap between
   columns (see .bottom-nav) — a shift as large as the old 10px pushed the
   translated tab's card visually past its neighbor's edge, reading as an
   overlap even though the two touch targets never actually collided. */
.nav-btn:first-child { --nav-shift: 4px; }
.nav-btn:last-child { --nav-shift: -4px; }

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

/* Gated to real pointers only — on touch, :active has no reliable "release"
   moment, so it can visually stick pressed/lifted until the next tap. */
@media (hover: hover) and (pointer: fine) {
  .nav-btn:active { transform: translateX(var(--nav-shift)) scale(0.94); }
}

.nav-icon {
  font-size: 21px;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 28px;
  border-radius: 12px;
  transition: background 0.2s ease, transform 0.2s ease;
}
.nav-btn.is-active .nav-icon {
  background: rgba(255,157,108,0.18);
  transform: translateY(-1px) scale(1.06);
}

/* Purely a visual nudge — the lightning bolt glyph optically sits a little
   high compared to the other nav icons at this font size. Relative
   positioning shifts it without affecting the label's position below it. */
.nav-btn[data-view="convenience"] .nav-icon { position: relative; top: 2px; }

.nav-label { display: block; letter-spacing: 0.01em; }
.nav-btn.is-active .nav-label { font-weight: 800; }

/* Spiky "NEW" seal on a nav tab — a starburst clip-path oval, not a plain
   pill, so it reads as a sticker rather than a notification count. Popped
   half outside the tab's own top-right corner (negative top) rather than
   tucked inside it — inside the button, a 51px-wide column leaves no room
   between the corner and the centered icon without the two visually
   overlapping; popping the badge up and out clears the icon entirely, the
   way a notification badge sits on a real app icon. */
.nav-badge-new {
  position: absolute;
  top: -9px;
  right: 2px;
  width: 24px;
  height: 15px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: linear-gradient(135deg, #ff7a6b, #e5384f);
  color: #fff;
  font-size: 7.5px;
  font-weight: 900;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  clip-path: polygon(
    50% 4%, 61% 14%, 74% 8%, 78% 21%, 92% 20%, 90% 34%,
    100% 42%, 89% 52%, 100% 62%, 89% 69%, 92% 82%, 78% 80%,
    75% 93%, 61% 87%, 50% 97%, 39% 87%, 25% 93%, 22% 80%,
    8% 82%, 11% 69%, 0% 62%, 11% 52%, 0% 42%, 10% 34%,
    8% 20%, 22% 21%, 26% 8%, 39% 14%
  );
  animation: badgePulse 1.8s ease-in-out infinite;
  pointer-events: none;
}
@keyframes badgePulse {
  0%, 100% { transform: scale(1); }
  50% { transform: scale(1.12); }
}
@media (prefers-reduced-motion: reduce) {
  .nav-badge-new { animation: none; }
}

/* ---------------- Bottom sheet ---------------- */

.sheet-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(61,50,38,0.35);
  z-index: 40;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  animation: fade-in 0.2s ease;
}

@keyframes fade-in { from { opacity: 0; } to { opacity: 1; } }

.sheet {
  width: 100%;
  max-width: 480px;
  background: var(--bg-elevated);
  border-radius: 24px 24px 0 0;
  padding: 20px 20px calc(20px + env(safe-area-inset-bottom));
  max-height: 75vh;
  max-height: 75dvh;
  overflow-y: auto;
  animation: slide-up 0.28s cubic-bezier(.2,.9,.3,1.1);
  border-top: 2px solid var(--w-3);
}

@keyframes slide-up { from { transform: translateY(100%); } to { transform: translateY(0); } }

.sheet-handle {
  width: 40px;
  height: 4px;
  border-radius: 2px;
  background: var(--locked);
  margin: 0 auto 14px;
}

.sheet-header { text-align: center; margin-bottom: 16px; }
.sheet-header .icon { font-size: 36px; }
.sheet-header h3 { margin: 6px 0 2px; }
.sheet-header p { margin: 0; color: var(--text-dim); font-size: 13px; }

/* Opens step-by-step instructions for whatever exercise or activity this
   checkpoint picked — a full-width button of its own right under the name,
   not a small icon easy to miss, so it's the first thing a first-timer sees. */
.how-to-btn {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 12px 14px;
  margin-bottom: 16px;
  border-radius: 14px;
  background: var(--card);
  box-shadow: 0 2px 8px rgba(61,50,38,0.06), 0 0 0 1.5px rgba(255,157,108,0.35);
  text-align: left;
  transition: transform 0.15s ease, box-shadow 0.15s ease;
}
.how-to-btn:active { transform: scale(0.98); }
.how-to-icon { font-size: 22px; flex-shrink: 0; }
.how-to-text { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.how-to-title { font-weight: 800; font-size: 14px; color: var(--text); }
.how-to-sub { font-size: 11.5px; color: var(--text-dim); margin-top: 1px; }
.how-to-chevron { font-size: 18px; color: var(--accent); flex-shrink: 0; }

.instructions-list {
  margin: 0;
  padding-left: 20px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  font-size: 13.5px;
  line-height: 1.5;
}
.instructions-list li { padding-left: 2px; }

/* Locked activity timer — replaces the whole sheet body while a timed
   activity is running. No close button is rendered alongside this (see
   logSheet.js), so Cancel Activity is the only way out. */
.timer-lock-view { text-align: center; padding: 8px 0 4px; }
.timer-lock-icon { font-size: 40px; margin-bottom: 6px; }
.timer-clock {
  font-family: 'Baloo 2', sans-serif;
  font-size: 48px;
  font-weight: 800;
  letter-spacing: 0.02em;
  color: var(--accent);
  margin-bottom: 14px;
}
.timer-progress-track {
  height: 10px;
  border-radius: 6px;
  background: var(--locked);
  overflow: hidden;
  margin-bottom: 18px;
}
.timer-progress-fill {
  height: 100%;
  border-radius: 6px;
  background: linear-gradient(90deg, var(--accent-2), var(--accent));
  transition: width 1s linear;
}
.timer-lock-note { font-size: 12.5px; color: var(--text-dim); line-height: 1.5; margin: 0 0 16px; }
.cancel-activity-btn {
  width: 100%;
  padding: 12px;
  border-radius: 14px;
  background: rgba(200,60,60,0.1);
  color: #b0392f;
  font-weight: 800;
  font-size: 14px;
}
.cancel-activity-btn:active { transform: scale(0.98); }

.confirm-sheet { max-height: none; padding-bottom: calc(20px + env(safe-area-inset-bottom)); }
.confirm-message { margin: 4px 0 20px; text-align: center; font-size: 15px; line-height: 1.5; }
.confirm-actions { display: flex; gap: 10px; align-items: stretch; }
.confirm-actions .secondary-btn, .confirm-actions .log-btn { flex: 1; margin-top: 0; }

.boss-tag {
  display: inline-block;
  margin-top: 8px;
  padding: 3px 10px;
  border-radius: 999px;
  background: rgba(224,102,90,0.12);
  color: var(--danger);
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.08em;
}

.bigboss-tag {
  background: rgba(224,86,122,0.14);
  color: #e0567a;
}

.set-progress {
  display: flex;
  gap: 6px;
  justify-content: center;
  margin-bottom: 18px;
}

.set-dot {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: var(--locked);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 13px;
  font-weight: 800;
}

.set-dot.is-done { background: linear-gradient(145deg, var(--w-2), var(--w-1)); color: var(--text); animation: setDotPop 0.35s cubic-bezier(.3,.7,.4,1.4); }
@keyframes setDotPop { 0% { transform: scale(0.6); } 60% { transform: scale(1.15); } 100% { transform: scale(1); } }

.exercise-picker {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  justify-content: center;
  margin-bottom: 16px;
}

.ex-pill {
  padding: 8px 14px;
  border-radius: 999px;
  background: var(--card);
  color: var(--text-dim);
  font-weight: 700;
  font-size: 13px;
  border: 1px solid rgba(61,50,38,0.08);
  transition: transform 0.15s ease, box-shadow 0.15s ease, background 0.2s ease, color 0.2s ease, border-color 0.2s ease;
}
.ex-pill:active { transform: scale(0.94); }

.ex-pill.is-selected {
  background: linear-gradient(135deg, var(--w-3), var(--w-2));
  color: var(--on-accent);
  border-color: var(--w-3);
  box-shadow: 0 4px 14px -6px var(--w-glow);
}

/* Replaces the old manual exercise/activity-type picker — the system
   decides which one fits the person's survey answers, shown as a plain
   (non-interactive) chip rather than a row of buttons implying a choice. */
.auto-picked-row {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  margin-bottom: 16px;
}
.auto-picked-chip {
  padding: 8px 16px;
  border-radius: 999px;
  background: linear-gradient(135deg, var(--w-3), var(--w-2));
  color: var(--on-accent);
  font-weight: 800;
  font-size: 13px;
  box-shadow: 0 4px 14px -6px var(--w-glow);
}
.auto-picked-note {
  font-size: 11px;
  color: var(--text-dim);
  font-style: italic;
}

.locked-tag {
  display: inline-block;
  margin-top: 8px;
  padding: 3px 10px;
  border-radius: 999px;
  background: rgba(138,122,99,0.14);
  color: var(--text-dim);
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.08em;
}

.locked-preview {
  text-align: center;
  padding: 10px 8px 4px;
}

.locked-preview .lock-icon {
  font-size: 34px;
  opacity: 0.7;
  margin-bottom: 8px;
}

.locked-preview p {
  color: var(--text-dim);
  font-size: 14px;
  margin: 0 0 10px;
}

.locked-preview .locked-target {
  font-size: 12px;
  color: var(--text-dim);
  background: var(--card);
  border-radius: 12px;
  padding: 10px 14px;
  line-height: 1.5;
}

.field-row {
  display: flex;
  gap: 10px;
  margin-bottom: 14px;
}

.field {
  flex: 1;
  background: var(--card);
  border-radius: 14px;
  padding: 10px 12px;
}

.field label {
  display: block;
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-dim);
  font-weight: 700;
  margin-bottom: 4px;
}

.field input {
  width: 100%;
  background: transparent;
  border: none;
  color: var(--text);
  font-size: 20px;
  font-weight: 800;
  font-family: inherit;
}
.field input:focus { outline: none; }

.stepper {
  display: flex;
  align-items: center;
  gap: 8px;
}

/* Replaces the old +/- stepper — this number comes from the survey, not
   from the person tweaking it, so it's shown plainly rather than inside an
   editable control that implies it can be changed. */
.fixed-number {
  font-size: 20px;
  font-weight: 800;
  color: var(--text);
}
.stepper button {
  width: 26px;
  height: 26px;
  border-radius: 8px;
  background: rgba(61,50,38,0.07);
  font-weight: 800;
  font-size: 15px;
  flex-shrink: 0;
  transition: transform 0.12s ease, background 0.15s ease;
}
.stepper button:active { transform: scale(0.88); background: rgba(61,50,38,0.14); }

.xp-preview {
  text-align: center;
  font-size: 12px;
  color: var(--text-dim);
  margin-bottom: 14px;
}
.xp-preview b { color: var(--accent); }

.log-btn {
  width: 100%;
  padding: 15px;
  border-radius: 16px;
  background: linear-gradient(135deg, var(--w-3), var(--w-2));
  color: var(--on-accent);
  font-weight: 800;
  font-size: 16px;
  text-align: center;
  box-shadow: 0 6px 20px -6px var(--w-glow);
  transition: transform 0.15s cubic-bezier(.3,.7,.4,1.4), box-shadow 0.15s ease;
}
.log-btn:active { transform: scale(0.97); box-shadow: 0 3px 12px -6px var(--w-glow); }
.log-btn:disabled { opacity: 0.5; }

.set-history {
  margin-top: 16px;
  border-top: 1px solid rgba(61,50,38,0.08);
  padding-top: 12px;
}
.set-history-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 4px 0;
  animation: rowSlideIn 0.28s ease both;
}
@keyframes rowSlideIn { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: translateY(0); } }
.set-history-main {
  flex: 1;
  min-width: 0;
  display: flex;
  justify-content: space-between;
  font-size: 13px;
  color: var(--text-dim);
}
.set-history-main b { color: var(--text); }

.set-delete-btn {
  flex-shrink: 0;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: rgba(224,102,90,0.12);
  color: var(--danger);
  font-size: 11px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.sheet-close {
  position: absolute;
  top: 16px;
  right: 16px;
  font-size: 18px;
  color: var(--text-dim);
  padding: 6px;
}

/* ---------------- Celebration modal ---------------- */

.celebrate-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(61,50,38,0.5);
  z-index: 60;
  display: flex;
  align-items: center;
  justify-content: center;
  animation: fade-in 0.2s ease;
}

.celebrate-card {
  background: radial-gradient(circle at 50% 0%, var(--w-2), var(--bg-elevated) 70%);
  border: 2px solid var(--w-3);
  border-radius: 24px;
  padding: 32px 26px;
  text-align: center;
  max-width: 320px;
  margin: 0 20px;
  animation: pop-in 0.35s cubic-bezier(.2,.9,.3,1.3);
  box-shadow: 0 12px 60px -10px rgba(61,50,38,0.25);
}

@keyframes pop-in { from { transform: scale(0.7); opacity: 0; } to { transform: scale(1); opacity: 1; } }

.celebrate-card .big-icon { font-size: 56px; display: block; margin-bottom: 8px; animation: bob 1.4s ease-in-out infinite; }
@keyframes bob { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-8px); } }

.celebrate-card h2 { margin: 0 0 6px; font-size: 22px; }
.celebrate-card p { color: var(--text-dim); margin: 0 0 18px; font-size: 14px; }
.celebrate-card .xp-gain { font-size: 26px; font-weight: 800; color: var(--accent); margin-bottom: 18px; }

.celebrate-card.is-legendary {
  border: 3px solid #e0567a;
  box-shadow: 0 0 70px -10px rgba(224,86,122,0.55);
  animation: pop-in 0.35s cubic-bezier(.2,.9,.3,1.3), legendary-glow 2.4s ease-in-out infinite 0.4s;
}

.celebrate-card.is-legendary .big-icon { font-size: 68px; }
.celebrate-card.is-legendary h2 { color: #e0567a; font-size: 26px; }
.celebrate-card.is-legendary .xp-gain { color: #e0567a; font-size: 30px; }

@keyframes legendary-glow {
  0%, 100% { box-shadow: 0 0 70px -10px rgba(224,86,122,0.55); }
  50% { box-shadow: 0 0 95px 0px rgba(224,86,122,0.45); }
}

.celebrate-card.is-levelup {
  background: radial-gradient(circle at 50% 0%, #cdeecb, var(--bg-elevated) 70%);
  border: 3px solid var(--accent-2);
  box-shadow: 0 0 70px -10px rgba(127,182,133,0.5);
  animation: pop-in 0.35s cubic-bezier(.2,.9,.3,1.3), levelup-glow 2.4s ease-in-out infinite 0.4s;
}

.celebrate-card.is-levelup .big-icon {
  font-size: 64px;
  animation: bob 1.4s ease-in-out infinite;
}

.celebrate-card.is-levelup h2 { color: var(--accent-2); font-size: 26px; }

@keyframes levelup-glow {
  0%, 100% { box-shadow: 0 0 70px -10px rgba(127,182,133,0.5); }
  50% { box-shadow: 0 0 95px 0px rgba(127,182,133,0.4); }
}

.celebrate-btn {
  width: 100%;
  padding: 14px;
  border-radius: 14px;
  background: var(--accent);
  color: var(--on-accent);
  font-weight: 800;
}

/* ---------------- Toast ----------------
   The root is the fixed, centered stack; each .toast is a normal flex child,
   so several toasts firing close together (e.g. a Convenience log immediately
   followed by an achievement tier-up) stack vertically instead of overlapping
   illegibly on the same spot. */

#toast-root {
  position: fixed;
  bottom: 90px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 70;
  display: flex;
  flex-direction: column-reverse;
  align-items: center;
  gap: 8px;
  pointer-events: none;
}

.toast {
  background: var(--card);
  color: var(--text);
  padding: 10px 18px;
  border-radius: 18px;
  font-size: 13px;
  font-weight: 700;
  border: 1px solid var(--danger);
  box-shadow: 0 4px 16px rgba(61,50,38,0.15);
  animation: toast-pop 2.2s ease forwards;
  /* Short messages ("Streak Shield purchased!") still read as a single
     rounded line at this radius — longer ones (account-linking messages,
     which name an email and a provider) wrap onto a second line instead of
     running off both edges of the screen the way a forced nowrap pill did. */
  max-width: min(320px, 84vw);
  white-space: normal;
  text-align: center;
  line-height: 1.4;
}

@keyframes toast-pop {
  0% { opacity: 0; transform: translateY(10px); }
  10% { opacity: 1; transform: translateY(0); }
  85% { opacity: 1; }
  100% { opacity: 0; transform: translateY(0); }
}

.shake { animation: shake 0.4s ease; }
@keyframes shake {
  0%, 100% { transform: translate(-50%, -50%); }
  25% { transform: translate(calc(-50% - 6px), -50%); }
  75% { transform: translate(calc(-50% + 6px), -50%); }
}

/* ---------------- Confetti ---------------- */

.confetti-piece {
  position: fixed;
  top: -10px;
  width: 8px;
  height: 8px;
  z-index: 80;
  pointer-events: none;
  animation: confetti-fall linear forwards;
}

@keyframes confetti-fall {
  to { transform: translateY(110vh) rotate(600deg); opacity: 0.3; }
}

/* ---------------- Profile view ---------------- */

.profile-view { padding: 8px 20px 20px; }

.profile-tabs {
  display: flex;
  gap: 6px;
  background: var(--card);
  border-radius: 14px;
  padding: 4px;
  margin-top: 6px;
  box-shadow: 0 2px 8px rgba(61,50,38,0.06);
}

.profile-tab {
  flex: 1;
  padding: 9px 0;
  border-radius: 10px;
  font-weight: 800;
  font-size: 13px;
  color: var(--text-dim);
}

.profile-tab.is-active {
  background: linear-gradient(135deg, var(--accent-2), var(--accent));
  color: var(--on-accent);
}

.profile-hero { text-align: center; padding: 20px 0 10px; }
.profile-ring {
  width: 110px;
  height: 110px;
  border-radius: 50%;
  margin: 0 auto 10px;
  background: conic-gradient(var(--accent) calc(var(--pct) * 1%), var(--locked) 0);
  display: flex;
  align-items: center;
  justify-content: center;
}
.profile-ring-inner {
  width: 92px;
  height: 92px;
  border-radius: 50%;
  background: var(--bg-elevated);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}
.profile-ring-inner .lvl-num { font-family: 'Baloo 2', sans-serif; font-size: 28px; font-weight: 800; }
.profile-ring-inner .lvl-label { font-size: 10px; color: var(--text-dim); text-transform: uppercase; letter-spacing: 0.08em; }

.profile-hero h2 { margin: 4px 0 0; }
.profile-hero .sub { color: var(--text-dim); font-size: 13px; }

.stat-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
  margin: 18px 0;
}

.stat-card {
  background: var(--card);
  border-radius: 16px;
  padding: 14px;
  text-align: center;
  box-shadow: 0 2px 8px rgba(61,50,38,0.06);
}
.stat-card .val { font-size: 22px; font-weight: 800; font-family: 'Baloo 2', sans-serif; color: var(--accent); }
.stat-card .lbl { font-size: 11px; color: var(--text-dim); text-transform: uppercase; letter-spacing: 0.05em; margin-top: 2px; }

.section-title {
  font-size: 13px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-dim);
  font-weight: 800;
  margin: 20px 0 10px;
}

/* Extra breathing room + a plain divider above "Reset All Progress" — keeps
   a genuinely destructive action from sitting shoulder-to-shoulder with
   ordinary account actions like Sign Out, without needing its own heading. */
.danger-zone-divider {
  margin-top: 28px;
  border-top: 1px solid rgba(61,50,38,0.1);
}

.legal-links-row {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 8px;
  margin-top: 14px;
  font-size: 12px;
}
.legal-links-row a { color: var(--text-dim); text-decoration: underline; }
.legal-links-row span { color: var(--text-dim); opacity: 0.6; }

.world-summary-row {
  display: flex;
  align-items: center;
  gap: 12px;
  background: var(--card);
  border-radius: 14px;
  padding: 12px 14px;
  margin-bottom: 8px;
  box-shadow: 0 2px 8px rgba(61,50,38,0.06);
}
.world-summary-row .emblem { font-size: 26px; }
.world-summary-row .info { flex: 1; }
.world-summary-row .info .name { font-weight: 800; font-size: 14px; }
.world-summary-row .info .bar-track { height: 6px; border-radius: 4px; background: var(--locked); margin-top: 6px; overflow: hidden; }
.world-summary-row .info .bar-fill { height: 100%; background: linear-gradient(90deg, var(--accent-2), var(--accent)); }
.world-summary-row .count { font-size: 12px; color: var(--text-dim); font-weight: 700; }

.account-email-row {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  background: var(--card);
  border-radius: 14px;
  padding: 12px 14px;
  margin-bottom: 4px;
  box-shadow: 0 2px 8px rgba(61,50,38,0.06);
}
.account-email-icon { font-size: 16px; }
.account-email-text {
  font-size: 13px;
  font-weight: 600;
  color: var(--text);
  overflow-wrap: anywhere;
}

.theme-toggle-row {
  display: flex;
  align-items: center;
  gap: 10px;
  background: var(--card);
  border-radius: 14px;
  padding: 12px 14px;
  margin-bottom: 8px;
  box-shadow: 0 2px 8px rgba(61,50,38,0.06);
}
.theme-toggle-icon { font-size: 16px; }
.theme-toggle-label { flex: 1; font-size: 13px; font-weight: 600; color: var(--text); }

.theme-switch { position: relative; display: inline-flex; width: 44px; height: 26px; flex-shrink: 0; }
.theme-switch input {
  position: absolute;
  inset: 0;
  opacity: 0;
  margin: 0;
  cursor: pointer;
  z-index: 1;
}
.theme-switch-track {
  position: absolute;
  inset: 0;
  background: var(--locked);
  border-radius: 999px;
  transition: background 0.2s ease;
}
.theme-switch-track::before {
  content: '';
  position: absolute;
  top: 3px;
  left: 3px;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 1px 3px rgba(0,0,0,0.25);
  transition: transform 0.2s ease;
}
.theme-switch input:checked ~ .theme-switch-track { background: var(--accent); }
.theme-switch input:checked ~ .theme-switch-track::before { transform: translateX(18px); }

.secondary-btn {
  display: block;
  width: 100%;
  margin-top: 8px;
  padding: 12px;
  border-radius: 14px;
  background: var(--card);
  color: var(--text);
  font-weight: 700;
  font-size: 13px;
  text-align: center;
  border: 1px solid rgba(61,50,38,0.1);
  box-shadow: 0 2px 8px rgba(61,50,38,0.05);
  transition: transform 0.15s ease, background 0.15s ease;
}
.secondary-btn:active { transform: scale(0.97); background: rgba(61,50,38,0.05); }

.reset-btn {
  width: 100%;
  margin-top: 8px;
  padding: 12px;
  border-radius: 14px;
  background: rgba(224,102,90,0.1);
  color: var(--danger);
  font-weight: 700;
  font-size: 13px;
  border: 1px solid rgba(224,102,90,0.3);
  transition: transform 0.15s ease, background 0.15s ease;
}
.reset-btn:active { transform: scale(0.97); background: rgba(224,102,90,0.18); }

/* ---------------- Coming-soon page (locked chapter tabs) ---------------- */

.coming-soon-tag {
  display: inline-block;
  margin-top: 18px;
  padding: 6px 16px;
  border-radius: 999px;
  background: rgba(255,157,108,0.14);
  border: 1px solid rgba(255,157,108,0.35);
  color: var(--accent);
  font-weight: 800;
  font-size: 12px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

/* ---------------- Shop ---------------- */

.shop-view { position: relative; min-height: 100%; padding: 16px 20px 28px; overflow: hidden; }

.shop-header {
  text-align: center;
  padding: 14px 18px 12px;
  margin: 4px 0 16px;
  border-radius: 22px;
  background: rgba(var(--glass-rgb), 0.82);
  backdrop-filter: blur(6px);
  box-shadow: 0 6px 20px -8px rgba(61,50,38,0.35);
}
.shop-header .emblem { font-size: 34px; display: block; margin-bottom: 4px; }
.shop-header h2 { margin: 0; font-size: 22px; }
.shop-header .subtitle { margin: 2px 0 0; color: var(--text-dim); font-size: 13px; }

/* Section labels sit directly on the Shop's own vibrant illustrated
   background rather than a plain page background — give them the same
   pill backing the rest of the scene-bg pages use for legibility. */
.shop-view .section-title {
  display: inline-block;
  background: rgba(var(--glass-rgb), 0.82);
  padding: 5px 14px;
  border-radius: 999px;
  backdrop-filter: blur(4px);
}

.gems-balance {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 14px;
  margin-bottom: 20px;
  border-radius: 16px;
  background: linear-gradient(135deg, #dbeaff, #b8d4ff);
  color: #2f4d8a;
  font-weight: 800;
  font-size: 18px;
  box-shadow: 0 2px 8px rgba(61,50,38,0.08);
}

.shield-card, .chest-card {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 14px 16px;
  margin-bottom: 12px;
  border-radius: 18px;
  background: var(--card);
  box-shadow: 0 2px 8px rgba(61,50,38,0.06);
}

/* Chests get a tighter gap/padding than the Streak Shield card — freeing up
   just enough width for every chest name to fit on one line instead of
   ellipsis-truncating, now that the description below it is a single
   short line instead of a full sentence. */
.chest-card { gap: 10px; padding: 12px; }

/* Unlike the Streak Shield card (fixed one-line copy), a chest's body can
   still vary a little in height — anchoring every child to the top keeps
   the icon, name and buy button pinned to the same spot regardless. */
.chest-card { align-items: flex-start; }
.chest-card .chest-art, .chest-card .chest-buy-btn { margin-top: 1px; }

.shield-icon { font-size: 30px; flex-shrink: 0; }
.shield-body, .chest-body { flex: 1; min-width: 0; }
.shield-name, .chest-name {
  display: flex;
  align-items: center;
  gap: 4px;
  font-weight: 800;
  font-size: 14px;
}
.chest-name { font-size: 13.5px; }
/* The name truncates with an ellipsis as a last resort rather than wrapping
   or spilling past its box into the price pill beside it — the info button
   next to it (flex-shrink: 0) always stays fully visible. With "Chest"
   dropped from every name, this shouldn't actually trigger anymore. */
.chest-name-text {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.chest-info-btn { flex-shrink: 0; }
.shield-desc, .chest-desc { font-size: 12px; color: var(--text-dim); line-height: 1.4; margin-top: 4px; }

.chest-info-btn {
  font-size: 13px;
  color: var(--text-dim);
  line-height: 1;
  transition: color 0.15s ease;
}
.chest-info-btn:hover { color: var(--accent); }

/* A one-time, self-advertising banner for the first-ever 10x pull bonus —
   bigger and louder than a per-chest deal badge since it applies once,
   account-wide, across every chest kind. Removed from the markup outright
   (see shop.js's tenPullPromoHTML) once claimed, rather than left in a
   disabled/greyed state. */
.tenpull-promo-banner {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 14px;
  margin-bottom: 12px;
  border-radius: 18px;
  background: linear-gradient(135deg, #fff3d0, #ffd873 55%, #ffb84d);
  box-shadow: 0 4px 14px -6px rgba(139, 90, 10, 0.45), inset 0 1px 0 rgba(255,255,255,0.6);
}
.tenpull-promo-icon { font-size: 26px; flex-shrink: 0; }
.tenpull-promo-title { font-size: 13px; font-weight: 800; color: #6b4a10; }
.tenpull-promo-sub { font-size: 11.5px; font-weight: 600; color: #7a5a20; line-height: 1.35; margin-top: 2px; }

.chest-qty-toggle { display: flex; gap: 6px; margin-top: 8px; }
.chest-deal-badge {
  display: inline-block;
  margin-top: 6px;
  padding: 3px 9px;
  border-radius: 999px;
  background: linear-gradient(135deg, #ffe9a8, #ffc266);
  color: #6b4a10;
  font-size: 10.5px;
  font-weight: 800;
}
.chest-qty-btn {
  padding: 4px 12px;
  border-radius: 999px;
  background: var(--locked);
  color: var(--text-dim);
  font-weight: 800;
  font-size: 11.5px;
}
.chest-qty-btn.is-selected { background: var(--accent); color: #fff; }
.chest-qty-btn:active { transform: scale(0.94); }

.shield-buy-btn, .chest-buy-btn {
  flex-shrink: 0;
  padding: 9px 14px;
  border-radius: 999px;
  background: linear-gradient(135deg, #dbeaff, #b8d4ff);
  color: #2f4d8a;
  font-weight: 800;
  font-size: 13px;
  transition: transform 0.15s ease, opacity 0.15s ease;
}
.chest-buy-btn { padding: 8px 10px; }
.shield-buy-btn:active, .chest-buy-btn:active { transform: scale(0.95); }
.shield-buy-btn:disabled, .chest-buy-btn:disabled { opacity: 0.45; }

/* Two stacked buy buttons per chest — the ×1 (primary) and a slimmer,
   quieter ×10 bulk-open underneath it. */
.chest-buy-col { flex-shrink: 0; display: flex; flex-direction: column; gap: 5px; align-items: stretch; margin-top: 1px; }
.chest-buy-col .chest-buy-btn { width: 100%; white-space: nowrap; }
.chest-buy-btn-x10 {
  padding: 6px 10px;
  font-size: 11.5px;
  background: rgba(47,77,138,0.1);
  color: #2f4d8a;
  box-shadow: inset 0 0 0 1.5px rgba(47,77,138,0.25);
}

.chest-art {
  width: 68px;
  height: 68px;
  border-radius: 12px;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 4px;
  box-sizing: border-box;
  font-size: 22px;
  box-shadow: inset 0 0 0 1px rgba(255,255,255,0.3);
}

/* The one real-money chest gets a gold ring so it visually reads as a
   different kind of purchase from the gem-priced ones next to it. */
.chest-card.is-real-money { box-shadow: 0 0 0 1.5px #e8c93f, 0 2px 8px rgba(61,50,38,0.06); }
.chest-buy-btn.is-real-money {
  /* Horizontal (90deg), not diagonal — a diagonal gradient inside a level
     pill read as the whole button being tilted. */
  background: linear-gradient(90deg, #ffe9a8, #e8c93f);
  color: #6b5313;
}

.gem-pack-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-bottom: 12px; }
.gem-pack-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: 6px;
  padding: 14px 10px;
  border-radius: 16px;
  background: var(--card);
  box-shadow: 0 2px 8px rgba(61,50,38,0.06);
}
.gem-pack-icon { font-size: 26px; }
.gem-pack-body { display: flex; flex-direction: column; gap: 2px; }
.gem-pack-amount { font-weight: 800; font-size: 13.5px; }
.gem-pack-bonus { font-size: 11px; font-weight: 800; color: var(--success); }
.gem-pack-card .chest-buy-btn { width: 100%; margin-top: 2px; }

.chests-note {
  margin: 0 0 12px;
  font-size: 11.5px;
  color: var(--text-dim);
  font-style: italic;
}

/* Centered modal for chest odds — distinct from the app's usual bottom
   sheet, since this popup is a small recap rather than a form/flow. */
.modal-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(61,50,38,0.4);
  z-index: 40;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  animation: fade-in 0.2s ease;
}
.modal-card {
  position: relative;
  width: 100%;
  max-width: 360px;
  max-height: 80vh;
  overflow-y: auto;
  background: var(--bg-elevated);
  border-radius: 22px;
  padding: 24px 20px 20px;
  box-shadow: 0 20px 50px rgba(61,50,38,0.35);
  animation: pop-in 0.22s cubic-bezier(.2,.9,.3,1.2);
}
.modal-card h3 { margin: 0 0 6px; text-align: center; font-size: 17px; }
.modal-sub { margin: 0 0 16px; text-align: center; font-size: 12.5px; color: var(--text-dim); line-height: 1.5; }
.modal-close {
  position: absolute;
  top: 14px;
  right: 14px;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: rgba(61,50,38,0.08);
  font-size: 13px;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* ---------------- XP Road ---------------- */

.xp-road-card { max-width: 340px; }

.xp-road-list {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.xp-road-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  border-radius: 12px;
  background: var(--card);
  opacity: 0.55;
}

.xp-road-row.is-passed { opacity: 0.75; }

.xp-road-row.is-current {
  opacity: 1;
  background: linear-gradient(135deg, rgba(255,157,108,0.22), rgba(255,157,108,0.06));
  border: 1px solid var(--accent);
}

.xp-road-badge {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: var(--locked);
  color: var(--text-dim);
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 800;
  font-size: 12px;
  flex-shrink: 0;
}

.xp-road-row.is-passed .xp-road-badge { background: var(--accent); color: var(--on-accent); }
.xp-road-row.is-current .xp-road-badge { background: var(--accent-2); color: var(--on-accent); }

.xp-road-info { flex: 1; min-width: 0; }

.xp-road-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}

.xp-road-xp { font-size: 12px; font-weight: 700; }
.xp-road-gems { font-size: 11px; font-weight: 800; color: #2ea3a3; flex-shrink: 0; }

.xp-road-flower {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-top: 3px;
  font-size: 11px;
  color: var(--text-dim);
}

/* ---------------- Paywall (mock Lotus Premium) ---------------- */

.paywall-price-card {
  text-align: center;
  padding: 16px;
  margin: 4px 0 14px;
  border-radius: 18px;
  background: linear-gradient(135deg, rgba(255,157,108,0.16), rgba(139,180,120,0.16));
  border: 1.5px solid rgba(255,157,108,0.3);
}
.paywall-price-amount { font-family: 'Baloo 2', sans-serif; font-weight: 800; font-size: 30px; color: var(--accent); }
.paywall-price-amount span { font-size: 14px; font-weight: 700; color: var(--text-dim); }
.paywall-price-note { font-size: 11px; color: var(--text-dim); margin-top: 2px; }

.paywall-perks { list-style: none; margin: 0 auto 16px; padding: 0; display: inline-flex; flex-direction: column; gap: 10px; text-align: left; }
.paywall-perks li { display: flex; align-items: center; gap: 10px; font-size: 13.5px; font-weight: 700; }
.paywall-perk-text { text-align: left; }
.paywall-perk-icon {
  width: 32px;
  height: 32px;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 16px;
  border-radius: 10px;
  background: var(--card);
  box-shadow: 0 2px 6px rgba(61,50,38,0.08);
}

.paywall-subscribe-btn {
  position: relative;
  overflow: hidden;
  width: 100%;
  padding: 15px;
  border-radius: 14px;
  background: linear-gradient(135deg, var(--accent-2), var(--accent));
  color: #fff;
  font-weight: 800;
  font-size: 15px;
  box-shadow: 0 8px 20px -8px rgba(255,157,108,0.6);
}
.paywall-subscribe-btn:active { transform: scale(0.97); }

/* The same diagonal light-sweep used on the Golden Lotus rarity (see
   .rarity-golden::before) — reused here so the Premium button and every
   chapter's opening banner share the one "this is special" shine effect. */
.sheen { position: relative; overflow: hidden; }
.sheen::before {
  content: '';
  position: absolute;
  top: -90%;
  left: -90%;
  width: 26%;
  height: 320%;
  background: linear-gradient(60deg, transparent, rgba(255,255,255,0.85), transparent);
  animation: goldenSweep 2.6s linear infinite;
  pointer-events: none;
}

.paywall-later-btn { width: 100%; padding: 10px; margin-top: 8px; font-size: 13px; font-weight: 700; color: var(--text-dim); }

/* The "Get Premium" entry point itself — shown in Profile and on every Path
   world banner. Gilded, with the same diagonal .sheen sweep as the
   in-modal Subscribe button, so tapping it feels like a continuation of
   the same premium moment rather than a plain link into it. */
.premium-btn {
  position: relative;
  width: 100%;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 16px;
  margin: 14px 0;
  border-radius: 16px;
  background: linear-gradient(135deg, #a8791a, #ffe9a8 45%, #a8791a);
  box-shadow: 0 6px 18px -6px rgba(168,121,26,0.55);
  color: #3d3226;
  text-align: left;
}
.premium-btn > * { position: relative; z-index: 1; }
.premium-btn:active { transform: scale(0.98); }
.premium-btn-icon { font-size: 22px; }
.premium-btn-text { display: flex; flex-direction: column; }
.premium-btn-title { font-weight: 800; font-size: 14px; }
.premium-btn-price { font-size: 11px; opacity: 0.8; }

.premium-badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 8px 14px;
  margin: 14px 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #a8791a, #ffe9a8 45%, #a8791a);
  color: #3d3226;
  font-weight: 800;
  font-size: 13px;
}

.paywall-trust-row {
  display: flex;
  justify-content: center;
  gap: 14px;
  margin-top: 10px;
  font-size: 10.5px;
  font-weight: 700;
  color: var(--text-dim);
}
.paywall-fine-print { font-size: 10px; color: var(--text-dim); line-height: 1.4; margin: 10px 0 0; text-align: center; opacity: 0.85; }
.paywall-fine-print a { color: var(--text-dim); text-decoration: underline; }

/* The mock card-details step — styled to look like a genuine checkout so
   the "official" feel carries through past the price card, even though
   nothing submitted here is real or stored. */
.paywall-pay-header {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 14px;
}
.paywall-pay-back {
  width: 30px;
  height: 30px;
  border-radius: 50%;
  background: var(--card);
  font-size: 18px;
  line-height: 1;
  flex-shrink: 0;
}
.paywall-pay-title { font-weight: 800; font-size: 15px; }
.paywall-pay-summary {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 10px 14px;
  border-radius: 12px;
  background: var(--card);
  font-weight: 700;
  font-size: 13px;
  margin-bottom: 14px;
}
.paywall-pay-form { display: flex; flex-direction: column; gap: 10px; }
.paywall-pay-field { display: flex; flex-direction: column; gap: 4px; font-size: 11.5px; font-weight: 700; color: var(--text-dim); flex: 1; }
.paywall-pay-field .auth-input { width: 100%; }
.paywall-pay-row { display: flex; gap: 8px; }
.paywall-pay-row .paywall-pay-field { min-width: 0; }

.paywall-notif-emblem { font-size: 40px; text-align: center; margin-bottom: 6px; }

.paywall-modal-card { text-align: center; padding-top: 30px; }
.paywall-modal-emblem { font-size: 40px; margin-bottom: 6px; }

/* The full-screen version standing in for Nourish/Convenience until subscribed. */
.paywall-screen {
  position: relative;
  min-height: 100%;
  padding: 40px 22px 24px;
  text-align: center;
  overflow: hidden;
}
.paywall-screen-glow {
  position: absolute;
  top: -80px;
  left: 50%;
  transform: translateX(-50%);
  width: 320px;
  height: 320px;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(255,157,108,0.35), rgba(139,180,120,0.18) 55%, transparent 75%);
  filter: blur(4px);
  pointer-events: none;
}
.paywall-screen-emblem { position: relative; font-size: 52px; margin-bottom: 8px; filter: drop-shadow(0 4px 14px rgba(255,157,108,0.4)); }
.paywall-screen h2 { position: relative; margin: 0 0 4px; font-size: 24px; }
.paywall-screen-tagline { position: relative; color: var(--text-dim); font-size: 13.5px; margin: 0 0 22px; line-height: 1.4; }
.paywall-screen-card {
  position: relative;
  background: var(--bg-elevated);
  border-radius: 22px;
  padding: 22px 20px 18px;
  box-shadow: 0 16px 40px -18px rgba(61,50,38,0.4);
  text-align: left;
}
.paywall-screen-sub { font-size: 13px; color: var(--text-dim); line-height: 1.5; margin: 0 0 16px; text-align: center; }

/* Chest-open reveal — the big centered "what did I get" moment. */
.reveal-card {
  position: relative;
  width: 100%;
  max-width: 320px;
  /* Tints to the pulled flower's rarity color the instant the card exists —
     the one hint given up front, before anything else is shown. */
  background: radial-gradient(circle at 50% 28%, color-mix(in srgb, var(--rarity-color) 35%, #fff), var(--rarity-color));
  color: var(--reveal-text, #3d3226);
  border-radius: 26px;
  padding: 32px 24px 26px;
  text-align: center;
  box-shadow: 0 24px 60px rgba(61,50,38,0.4);
  animation: revealPop 0.45s cubic-bezier(.2,.8,.3,1.2);
  overflow: hidden;
}
.reveal-card.is-spinning { min-height: 240px; display: flex; align-items: center; justify-content: center; }
.reveal-card.is-revealed { animation: revealSettle 0.4s cubic-bezier(.2,.8,.3,1.2); }

/* Shiny — silver with no single flat tone: two close-hued greys blended
   diagonally into each other rather than a plain wash. */
.reveal-card.rarity-shiny {
  background: repeating-linear-gradient(135deg, #f2f6f8 0px, #d7e1e7 26px, #f2f6f8 52px);
}
.multi-reveal-item.rarity-shiny.is-spinning,
.multi-reveal-item.rarity-shiny.is-revealed {
  background: repeating-linear-gradient(135deg, #f2f6f8 0px, #d7e1e7 14px, #f2f6f8 28px);
}
.coll-card.rarity-shiny.is-owned {
  background: repeating-linear-gradient(135deg, #f2f6f8 0px, #d7e1e7 22px, #f2f6f8 44px);
}

/* Mythical — the same seamless two-color-blend idea as Golden (see
   .rarity-golden below), pink at the core fading into a deep navy toward
   the edges, but no sweeping shine — Mythical reads as "rare and unusual,"
   not "actively glowing" the way the one-of-one Golden Lotus does. */
.reveal-card.rarity-mythical {
  background: radial-gradient(circle at 50% 26%, #ffe3f0 0%, #e0507a 42%, #4a3a94 74%, #1c2258 100%);
}
.multi-reveal-item.rarity-mythical.is-spinning,
.multi-reveal-item.rarity-mythical.is-revealed {
  background: radial-gradient(circle at 50% 26%, #ffe3f0 0%, #e0507a 42%, #4a3a94 74%, #1c2258 100%);
}
.coll-card.rarity-mythical.is-owned {
  background: radial-gradient(circle at 50% 26%, #ffe3f0 0%, #e0507a 42%, #4a3a94 74%, #1c2258 100%);
}

/* Golden — same base yellow as Legendary at its core, but blending outward
   into a soft pink toward the edges (a seamless radial blend, not a hard
   ring), told apart further by a bright, obviously-angled sheen that keeps
   sweeping across it like light catching a polished surface (plus the
   flower icon's own twinkling stars, see flowerData.js). */
.reveal-card.rarity-golden {
  background: radial-gradient(circle at 50% 26%, #fff6d8 0%, #f5da7c 32%, #eeb894 64%, #e9a8bc 100%);
}
.multi-reveal-item.rarity-golden.is-spinning,
.multi-reveal-item.rarity-golden.is-revealed {
  background: radial-gradient(circle at 50% 26%, #fff6d8 0%, #f5da7c 32%, #eeb894 64%, #e9a8bc 100%);
}
.coll-card.rarity-golden.is-owned {
  background: radial-gradient(circle at 50% 26%, #fff6d8 0%, #f5da7c 32%, #eeb894 64%, #e9a8bc 100%);
}
.reveal-card.rarity-golden::before,
.multi-reveal-item.rarity-golden::before,
.coll-card.rarity-golden.is-owned::before {
  content: '';
  position: absolute;
  top: -90%;
  left: -90%;
  width: 26%;
  height: 320%;
  background: linear-gradient(60deg, transparent, rgba(255,255,255,0.95), transparent);
  animation: goldenSweep 1.9s linear infinite;
  pointer-events: none;
}
/* Mythic — my own top tier, above Legendary. Same treatment as Mythical
   above (this app has both names in play across two flower systems) so it
   reads at the same rarity weight. */
.reveal-card.rarity-mythic {
  background: radial-gradient(circle at 50% 26%, #ffe3f0 0%, #e0507a 42%, #4a3a94 74%, #1c2258 100%);
}
.multi-reveal-item.rarity-mythic.is-spinning,
.multi-reveal-item.rarity-mythic.is-revealed {
  background: radial-gradient(circle at 50% 26%, #ffe3f0 0%, #e0507a 42%, #4a3a94 74%, #1c2258 100%);
}
.coll-card.rarity-mythic.is-owned {
  background: radial-gradient(circle at 50% 26%, #ffe3f0 0%, #e0507a 42%, #4a3a94 74%, #1c2258 100%);
}

/* Bloomed — the friendliest, least-rare alt-skin line (deliberately calmer
   than Shiny/Golden): the flower's own real colors, just inverted, so it
   reads as a distinct "negative" variant rather than another shine effect. */
.coll-card.rarity-bloomed.is-owned .coll-card-icon svg,
.reveal-card.rarity-bloomed .reveal-icon svg,
.reveal-card.rarity-bloomed .reveal-spin-icon svg,
.multi-reveal-item.rarity-bloomed .multi-reveal-icon svg,
.multi-reveal-item.rarity-bloomed .multi-reveal-spin-icon svg {
  filter: invert(1) hue-rotate(180deg);
}
.reveal-card.rarity-bloomed { background: radial-gradient(circle at 50% 28%, color-mix(in srgb, var(--rarity-color) 35%, #fff), var(--rarity-color)); }
.multi-reveal-item.rarity-bloomed.is-spinning,
.multi-reveal-item.rarity-bloomed.is-revealed,
.coll-card.rarity-bloomed.is-owned {
  background: color-mix(in srgb, var(--rarity-color) 35%, #fff);
}

@keyframes goldenSweep {
  from { left: -90%; }
  to { left: 145%; }
}
@keyframes revealSettle {
  0% { transform: scale(0.88); }
  55% { transform: scale(1.05); }
  100% { transform: scale(1); }
}
@keyframes revealPop {
  0% { opacity: 0; transform: scale(0.6) translateY(20px); }
  60% { opacity: 1; }
  100% { opacity: 1; transform: scale(1) translateY(0); }
}

/* The suspense phase — no label at all yet, just the actual flower (not a
   generic disc) spinning about its own vertical axis, shaded down to a dark
   silhouette so its identity stays hidden — the same beat as a Brawl Stars
   skin reveal. */
.reveal-spin-face {
  display: flex;
  align-items: center;
  justify-content: center;
  perspective: 600px;
  animation: spinFace 0.85s linear infinite;
}
@keyframes spinFace {
  from { transform: rotateY(0deg); }
  to { transform: rotateY(360deg); }
}
.reveal-spin-icon { width: 130px; height: 130px; }
.reveal-spin-icon svg {
  width: 100%;
  height: 100%;
  filter: brightness(0.22) grayscale(1) contrast(1.15);
}

.reveal-icon { position: relative; margin: 4px auto 6px; width: 150px; height: 150px; display: flex; align-items: center; justify-content: center; animation: revealIconRise 0.5s 0.1s cubic-bezier(.2,.8,.3,1.2) both; }
@keyframes revealIconRise { from { opacity: 0; transform: translateY(14px) scale(0.85); } to { opacity: 1; transform: translateY(0) scale(1); } }
.reveal-icon svg { width: 100%; height: 100%; }
/* A bare emoji (the miss 🥀) inherits the tiny default font-size otherwise —
   this fills the same 150px icon slot a flower SVG would. */
.reveal-miss-emoji { font-size: 96px; line-height: 1; }

/* ×10 batch summary — a small grid of the new blooms found. */
.batch-grid { position: relative; display: flex; flex-wrap: wrap; justify-content: center; gap: 10px 14px; margin: 6px auto 14px; max-width: 280px; }
.batch-grid-item { display: flex; flex-direction: column; align-items: center; width: 60px; }
.batch-grid-icon { width: 48px; height: 48px; display: flex; align-items: center; justify-content: center; }
.batch-grid-icon svg { width: 100%; height: 100%; }
.batch-grid-name { margin-top: 3px; font-size: 10.5px; font-weight: 700; text-align: center; line-height: 1.2; opacity: 0.9; }
.batch-none { position: relative; font-size: 13px; font-weight: 700; margin: 10px auto 16px; opacity: 0.8; max-width: 240px; line-height: 1.4; }

.reveal-rarity { position: relative; font-weight: 800; font-size: 13px; letter-spacing: 0.08em; margin-bottom: 4px; opacity: 0.85; }
.reveal-name { position: relative; font-family: 'Baloo 2', sans-serif; font-weight: 800; font-size: 24px; margin-bottom: 8px; }
.reveal-sub { position: relative; font-size: 13px; font-weight: 700; margin-bottom: 20px; line-height: 1.4; opacity: 0.9; }
.reveal-close-btn {
  position: relative;
  width: 100%;
  padding: 13px;
  border-radius: 14px;
  background: linear-gradient(135deg, var(--accent-2), var(--accent));
  color: #fff;
  font-weight: 800;
  font-size: 15px;
  box-shadow: 0 6px 16px -6px rgba(255,157,108,0.6);
}
.reveal-close-btn:active { transform: scale(0.97); }

.golden-fanfare-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 40px 26px 30px;
}
.golden-fanfare-title {
  position: relative;
  font-family: 'Baloo 2', sans-serif;
  font-weight: 800;
  font-size: 26px;
  margin-bottom: 14px;
  text-align: center;
}
.golden-fanfare-sub {
  position: relative;
  font-size: 15px;
  font-weight: 700;
  line-height: 1.5;
  text-align: center;
  margin-bottom: 24px;
}

/* x10 pull — every result at once in a grid, instead of ten sequential spins. */
.multi-reveal-card {
  position: relative;
  width: 100%;
  max-width: 400px;
  max-height: 82vh;
  overflow-y: auto;
  background: var(--bg-elevated);
  border-radius: 24px;
  padding: 22px 18px 20px;
  text-align: center;
  box-shadow: 0 24px 60px rgba(61,50,38,0.4);
  animation: revealPop 0.4s cubic-bezier(.2,.8,.3,1.2);
}
.multi-reveal-card h3 { margin: 0 0 4px; font-size: 19px; }
.multi-reveal-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 10px;
  margin: 16px 0 18px;
}
/* The card scrolls internally (max-height: 82vh) when 10 results run long —
   pin the close button to the bottom of that scroll area instead of letting
   it scroll away or get clipped by the card's own bottom edge. */
.multi-reveal-card > .reveal-close-btn {
  position: sticky;
  bottom: 0;
  margin-top: 4px;
}
.multi-reveal-item {
  position: relative;
  min-width: 0;
  /* Shared min-height across both spinning and revealed states — without
     this, the revealed state (icon + name + tag, sometimes a 2-line name)
     is naturally taller than the spinning state's single centered icon,
     so the whole grid visibly jumped in size the instant every card
     flipped over. */
  min-height: 134px;
  border: 1.5px solid transparent;
  border-radius: 14px;
  background: var(--card);
  color: var(--reveal-text, inherit);
  padding: 10px 6px;
  overflow: hidden;
  animation: revealIconRise 0.4s cubic-bezier(.2,.8,.3,1.2) both;
}
.multi-reveal-item.is-spinning {
  display: flex;
  align-items: center;
  justify-content: center;
  background: radial-gradient(circle at 50% 28%, color-mix(in srgb, var(--rarity-color) 35%, #fff), var(--rarity-color));
}
.multi-reveal-item.is-revealed {
  display: flex;
  flex-direction: column;
  justify-content: center;
  border-color: color-mix(in srgb, var(--rarity-color) 60%, #000);
  background: radial-gradient(circle at 50% 22%, color-mix(in srgb, var(--rarity-color) 35%, #fff), var(--rarity-color));
  animation: revealSettle 0.35s cubic-bezier(.2,.8,.3,1.2);
}
.multi-reveal-item.is-revealed .multi-reveal-icon {
  background: radial-gradient(circle, rgba(255,255,255,0.55), rgba(255,255,255,0) 70%);
  border-radius: 50%;
}
.multi-reveal-spin-face {
  display: flex;
  align-items: center;
  justify-content: center;
  perspective: 400px;
  animation: spinFace 0.85s linear infinite;
}
.multi-reveal-spin-icon { width: 52px; height: 52px; }
.multi-reveal-spin-icon svg {
  width: 100%;
  height: 100%;
  filter: brightness(0.22) grayscale(1) contrast(1.15);
}
.multi-reveal-icon { width: 52px; height: 52px; margin: 0 auto; }
.multi-reveal-icon svg { width: 100%; height: 100%; }
.multi-reveal-name { font-weight: 800; font-size: 11px; margin-top: 2px; line-height: 1.25; }
.multi-reveal-tag { font-size: 8.5px; font-weight: 800; letter-spacing: 0.05em; margin-top: 2px; }
.multi-reveal-dup { font-size: 10px; font-weight: 700; margin-top: 2px; opacity: 0.9; }
.multi-reveal-tag { opacity: 0.85; }

.odds-list { display: flex; flex-direction: column; gap: 6px; }
.odds-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  border-radius: 12px;
  background: var(--card);
}
.odds-icon { font-size: 14px; flex-shrink: 0; }
.odds-name { flex: 1; font-weight: 700; font-size: 13px; }
.odds-count { font-weight: 600; color: var(--text-dim); }
.odds-pct { font-weight: 800; font-size: 13px; color: var(--success); text-align: right; display: flex; flex-direction: column; }
.odds-each { font-weight: 600; font-size: 10px; color: var(--text-dim); }

/* ---------------- My Collection ---------------- */

.coll-view { padding: 16px 20px 28px; }

.coll-header { text-align: center; margin-bottom: 10px; }
.coll-header .emblem { font-size: 34px; display: block; margin-bottom: 4px; }
.coll-header h2 { margin: 0; font-size: 22px; }
.coll-header .subtitle { margin: 2px 0 0; color: var(--text-dim); font-size: 13px; }

.coll-progress {
  text-align: center;
  font-weight: 800;
  color: var(--text-dim);
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  margin-bottom: 16px;
}

.coll-equipped-banner {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 14px 10px 10px;
  margin-bottom: 18px;
  border-radius: 14px;
  background: var(--card);
  box-shadow: 0 2px 8px rgba(61,50,38,0.08);
}
/* Reuses .coll-card's rarity-fill backgrounds (including the Shiny stripe,
   Golden shine-sweep and Mythical blend) at swatch size instead of
   duplicating them — the equipped flower should look exactly like its card
   in the grid below, just smaller. */
.coll-equipped-swatch.coll-card {
  flex-shrink: 0;
  width: 52px;
  height: 52px;
  padding: 0;
  margin: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 12px;
  box-shadow: none;
}
.coll-equipped-swatch svg { width: 40px; height: 40px; }
.coll-equipped-info { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.coll-equipped-label { font-size: 10.5px; font-weight: 800; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-dim); }
.coll-equipped-name { font-size: 14px; font-weight: 800; }
.coll-equipped-boost { font-weight: 700; color: var(--accent); }

.coll-tier-title {
  font-weight: 800;
  font-size: 13px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  margin: 18px 2px 10px;
}
.coll-tier-title:first-of-type { margin-top: 0; }
.coll-tier-title span { color: var(--text-dim); font-weight: 700; text-transform: none; letter-spacing: normal; }

.coll-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin-bottom: 4px; }

.coll-card {
  position: relative;
  background: var(--card);
  border-radius: 16px;
  padding: 14px;
  display: flex;
  flex-direction: column;
  gap: 6px;
  border: 1.5px solid transparent;
  box-shadow: 0 2px 8px rgba(61,50,38,0.06);
  overflow: hidden;
}
.coll-card.is-locked { opacity: 0.65; }

/* Owned cards are filled with their rarity's own color — the same radial
   tint (and, for Shiny/Golden, the same blended-stripe / shine-sweep
   treatment) used on the chest reveal cards, rather than a plain white
   card with just a colored border. */
.coll-card.is-owned {
  background: radial-gradient(circle at 50% 22%, color-mix(in srgb, var(--rarity-color) 35%, #fff), var(--rarity-color));
  color: var(--reveal-text, inherit);
  border-color: color-mix(in srgb, var(--rarity-color) 60%, #000);
}
.coll-card.is-owned .coll-card-boost { color: var(--reveal-text, inherit); opacity: 0.9; }

.coll-card-top { display: flex; justify-content: space-between; align-items: center; }
.coll-lock { font-size: 13px; opacity: 0.6; }
.coll-tag { position: relative; font-size: 10px; font-weight: 800; letter-spacing: 0.06em; color: var(--text-dim); text-transform: uppercase; }

.coll-card-icon { position: relative; text-align: center; margin: 4px 0; display: flex; justify-content: center; }
.coll-card-icon svg { width: 56px; height: 56px; }
.coll-card.is-locked .coll-card-icon { font-size: 30px; opacity: 0.4; filter: grayscale(1); }

.coll-card-name { position: relative; font-weight: 800; font-size: 13px; text-align: center; }
.coll-card-desc { font-size: 11px; color: var(--text-dim); text-align: center; line-height: 1.35; }
.coll-card-boost { position: relative; font-size: 11px; font-weight: 700; color: var(--accent); text-align: center; }

.coll-equip-btn {
  margin-top: auto;
  padding: 7px;
  border-radius: 10px;
  background: var(--bg-elevated);
  /* Fixed, not inherited — this button's own background is always the same
     near-white regardless of the card's rarity color, so it needs its own
     readable text color rather than picking up --reveal-text from the
     colored card behind it (which was invisible against this button on
     rarities whose reveal-text is white, like Mythical/Golden). */
  color: var(--text);
  font-weight: 800;
  font-size: 12px;
  box-shadow: 0 1px 4px rgba(61,50,38,0.1);
}
.coll-equip-btn:active { transform: scale(0.96); }
.coll-equip-btn.is-equipped {
  background: linear-gradient(135deg, #ffe9a8, #ffd668);
  color: #6b5313;
}

/* Achievements list (profile) */
.ach-list { display: flex; flex-direction: column; gap: 10px; padding: 4px 20px 24px; }
.ach-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 14px;
  border-radius: 16px;
  background: var(--card);
  box-shadow: 0 2px 8px rgba(61,50,38,0.06);
  opacity: 0.62;
  filter: grayscale(0.5);
}
.ach-row.is-earned { opacity: 1; filter: none; border: 1.5px solid var(--accent); }
.ach-icon {
  font-size: 24px;
  width: 44px;
  height: 44px;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bg-elevated);
  border-radius: 12px;
}
.ach-body { flex: 1; min-width: 0; }
.ach-name { font-weight: 800; font-size: 14px; }
.ach-desc { font-size: 11.5px; color: var(--text-dim); margin: 2px 0 5px; line-height: 1.35; }
.ach-reward { flex-shrink: 0; text-align: right; line-height: 1.1; }
.ach-xp { font-family: 'Baloo 2', sans-serif; font-weight: 800; font-size: 18px; color: var(--accent); }
.ach-xp-lbl { font-size: 10px; font-weight: 800; color: var(--accent); margin-left: 1px; }
.ach-earned-tag {
  display: block;
  margin-top: 4px;
  font-size: 10px;
  font-weight: 800;
  color: #4d7a57;
}

/* Tiered achievements (Achievements tab only) */
.ach-tiered { align-items: flex-start; padding-top: 14px; padding-bottom: 14px; }
.ach-tiered .ach-icon { margin-top: 2px; }

.tier-badge {
  display: inline-block;
  margin-left: 6px;
  font-size: 10px;
  font-weight: 800;
  color: var(--accent);
  background: rgba(255,157,108,0.16);
  padding: 2px 7px;
  border-radius: 999px;
  vertical-align: middle;
}

.tier-pips { display: flex; gap: 6px; margin: 7px 0 8px; }

.tier-pip {
  width: 22px;
  height: 22px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 10px;
  font-weight: 800;
  flex-shrink: 0;
  background: var(--locked);
  color: var(--text-dim);
}
.tier-pip.is-done { background: var(--accent); color: var(--on-accent); }
.tier-pip.is-next { background: var(--bg-elevated); border: 2px solid var(--accent); color: var(--accent); }
.tier-pip.is-locked { opacity: 0.6; }

.tier-progress-track {
  height: 6px;
  border-radius: 4px;
  background: var(--locked);
  overflow: hidden;
  margin-bottom: 5px;
}
.tier-progress-fill {
  height: 100%;
  border-radius: 4px;
  background: var(--accent);
  transition: width 0.4s ease;
}
.tier-progress-label { font-size: 11px; color: var(--text-dim); font-weight: 700; }

/* With five tabs, every button must claim exactly 1/5 of the bar — a long
   label (like "My Collection") mustn't force nowrap and spill past its own
   equal-width column into its neighbors', which is what actually made the
   bar read as unevenly split. Wrapping to two lines keeps it inside its own
   flex-basis-0 column instead. */
.bottom-nav .nav-btn {
  flex: 1 1 0;
  min-width: 0;
  font-size: 9.5px;
  padding-left: 1px;
  padding-right: 1px;
}
.bottom-nav .nav-btn span:last-child {
  display: block;
  width: 100%;
  white-space: normal;
  /* A single long word (e.g. "Convenience") should wrap as a whole rather
     than splitting mid-word — break-word was hyphenating it into
     "Convenien-ce", which read as a rendering glitch, not a real word wrap. */
  word-break: keep-all;
  overflow-wrap: normal;
  line-height: 1.15;
}

/* ---------------- Nourish (food tracker) ---------------- */

.dining-view { position: relative; min-height: 100%; padding: 8px 20px 24px; overflow: hidden; }

/* A decorative scene sits behind the Nourish/Convenience content — a wash
   on top keeps it subtle enough that the white cards in front stay easy to
   read rather than fighting a busy illustration for attention. */
.scene-bg {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
}
.scene-bg::after {
  content: '';
  position: absolute;
  inset: 0;
  background: rgba(var(--glass-rgb), 0.2);
}
/* Nourish/Convenience specifically get a stronger wash — their scenes were
   legible but made text sitting directly on them (outside the solid white
   cards) harder to read at a glance. Shop's darker misty-pond backdrop
   keeps the lighter default wash so it doesn't wash out its own mood. */
.dining-view .scene-bg::after {
  background: rgba(var(--glass-rgb), 0.5);
}
.view-content { position: relative; z-index: 1; }

.dining-header {
  text-align: center;
  padding: 14px 18px 12px;
  margin: 4px 0 10px;
  border-radius: 22px;
  background: rgba(var(--glass-rgb), 0.82);
  backdrop-filter: blur(6px);
  box-shadow: 0 6px 20px -8px rgba(61,50,38,0.35);
}
.dining-header .emblem { font-size: 34px; display: block; margin-bottom: 4px; filter: drop-shadow(0 0 12px var(--accent)); }
.dining-header h2 { margin: 0; }
.dining-header .subtitle { color: var(--text-dim); font-size: 13px; margin: 2px 0 0; }

/* A pill-shaped "speech rectangle" behind any section label that would
   otherwise sit directly on the busy scene background. */
.scene-label-panel {
  display: inline-block;
  padding: 6px 16px;
  border-radius: 999px;
  background: rgba(var(--glass-rgb), 0.82);
  backdrop-filter: blur(6px);
  box-shadow: 0 4px 14px -6px rgba(61,50,38,0.3);
}

.swaps-wrap { position: relative; margin: 4px 0 16px; }

.swaps-trigger {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  background: linear-gradient(135deg, rgba(232,130,158,0.18), rgba(79,173,163,0.18));
  border-radius: 999px;
  padding: 10px 16px;
  font-weight: 800;
  font-size: 13px;
  color: var(--text);
  box-shadow: 0 2px 8px rgba(61,50,38,0.06);
  border: 1px solid rgba(79,173,163,0.28);
}

.swaps-popover {
  position: absolute;
  top: calc(100% + 8px);
  left: 0;
  right: 0;
  background: linear-gradient(165deg, #fff6f8, #f2fbfa);
  border-radius: 16px;
  padding: 14px;
  box-shadow: 0 8px 24px rgba(61,50,38,0.2);
  z-index: 30;
  max-height: 280px;
  overflow-y: auto;
  opacity: 0;
  transform: translateY(-6px);
  pointer-events: none;
  transition: opacity 0.15s ease, transform 0.15s ease;
}

.swaps-popover.is-open {
  opacity: 1;
  transform: translateY(0);
  pointer-events: auto;
}

.swaps-popover-header {
  text-align: center;
  font-weight: 800;
  font-size: 13px;
  margin-bottom: 10px;
  color: var(--accent);
}

.swaps-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.swap-row {
  padding-bottom: 10px;
  border-bottom: 1px solid rgba(79,173,163,0.18);
}

.swap-row:last-child { border-bottom: none; padding-bottom: 0; }

.swap-pair {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
  font-size: 12px;
  font-weight: 800;
}

.swap-from { color: var(--text-dim); text-decoration: line-through; }
.swap-arrow { color: var(--text-dim); }
.swap-to { color: var(--accent-2); }

.swap-note {
  font-size: 11px;
  color: var(--text-dim);
  margin-top: 2px;
}

.dining-totals {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 8px;
  margin: 18px 0 22px;
}

.dining-stat {
  background: var(--card);
  border-radius: 14px;
  padding: 12px 6px;
  text-align: center;
  box-shadow: 0 2px 8px rgba(61,50,38,0.06);
}
.dining-stat .val { font-size: 17px; font-weight: 800; font-family: 'Baloo 2', sans-serif; color: var(--accent); }
.dining-stat .lbl { font-size: 10px; color: var(--text-dim); text-transform: uppercase; letter-spacing: 0.04em; margin-top: 2px; }

.meal-group {
  margin-bottom: 14px;
  padding: 12px;
  border-radius: 16px;
  background: rgba(var(--glass-rgb), 0.72);
  backdrop-filter: blur(4px);
}

.meal-group-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-weight: 800;
  font-size: 14px;
  margin-bottom: 8px;
}

.meal-add-btn {
  font-size: 12px;
  font-weight: 800;
  color: #fff6ee;
  background: linear-gradient(135deg, #ff9d6c, #e8672f);
  padding: 5px 12px;
  border-radius: 999px;
  box-shadow: 0 1px 5px rgba(179,64,15,0.4);
}

.meal-empty {
  color: var(--text-dim);
  font-size: 12px;
  font-style: italic;
  padding: 10px 4px;
}

.meal-row {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  background: var(--card);
  border-radius: 12px;
  padding: 12px 14px;
  margin-bottom: 6px;
  text-align: left;
  box-shadow: 0 2px 8px rgba(61,50,38,0.05);
}

.meal-row-name { font-weight: 700; font-size: 13px; }
.meal-row-cals { font-size: 12px; color: var(--text-dim); font-weight: 700; flex-shrink: 0; margin-left: 10px; }

.calc-hint {
  text-align: center;
  font-size: 11px;
  color: var(--text-dim);
  margin: -6px 0 14px;
}

.save-preset-check {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  color: var(--text-dim);
  margin-bottom: 16px;
  padding: 0 2px;
}
.save-preset-check input { width: 16px; height: 16px; }

.idea-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-bottom: 16px;
}

.idea-card {
  background: var(--card);
  border-radius: 14px;
  padding: 10px 14px;
  text-align: left;
  transition: transform 0.15s ease, box-shadow 0.15s ease;
}
.idea-card:active { transform: scale(0.97); }

.idea-name { font-weight: 800; font-size: 13px; }
.idea-prep { font-size: 11px; color: var(--text-dim); margin-top: 2px; line-height: 1.4; }
.idea-macros { font-size: 11px; color: var(--accent); font-weight: 700; margin-top: 4px; }

.swap-tip {
  text-align: center;
  font-size: 11px;
  color: var(--text-dim);
  font-style: italic;
  margin: -6px 0 14px;
}

/* ---------------- Guide (placeholder demo videos) ---------------- */

.guide-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
  margin-bottom: 8px;
}

.guide-card {
  background: var(--card);
  border-radius: 14px;
  overflow: hidden;
  box-shadow: 0 2px 8px rgba(61,50,38,0.06);
}

.guide-video-placeholder {
  aspect-ratio: 16 / 10;
  background: linear-gradient(135deg, var(--w-2), var(--w-1));
  display: flex;
  align-items: center;
  justify-content: center;
}

.guide-play-icon {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: rgba(255,255,255,0.85);
  color: var(--text);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 14px;
  padding-left: 2px;
}

.guide-card-label {
  padding: 8px 10px;
  font-size: 12px;
  font-weight: 700;
  color: var(--text);
}

/* ---------------- Convenience (on-the-go) ---------------- */

.conv-posture-list { display: flex; flex-direction: column; gap: 10px; }

.conv-posture {
  display: flex;
  align-items: center;
  gap: 14px;
  width: 100%;
  text-align: left;
  padding: 16px;
  border-radius: 16px;
  background: var(--card);
  box-shadow: 0 2px 8px rgba(61,50,38,0.06);
  border: 1.5px solid transparent;
  transition: transform 0.15s, box-shadow 0.15s, border-color 0.15s;
}
.conv-posture:hover { border-color: rgba(255,157,108,0.45); box-shadow: 0 6px 16px rgba(61,50,38,0.1); }
.conv-posture:active { transform: scale(0.985); }

.conv-posture-icon {
  font-size: 26px;
  width: 48px;
  height: 48px;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bg-elevated);
  border-radius: 14px;
}
.conv-posture-text { display: flex; flex-direction: column; gap: 2px; flex: 1; min-width: 0; }
.conv-posture-label { font-weight: 800; font-size: 16px; }
.conv-posture-blurb { font-size: 12.5px; color: var(--text-dim); line-height: 1.4; }
.conv-chevron { font-size: 24px; color: var(--text-dim); flex-shrink: 0; line-height: 1; }

.conv-back {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-weight: 800;
  font-size: 13px;
  color: var(--accent);
  padding: 4px 0 10px;
}

.conv-list-panel {
  padding: 10px 14px 14px;
  margin-bottom: 14px;
  border-radius: 18px;
  background: rgba(var(--glass-rgb), 0.82);
  backdrop-filter: blur(6px);
  box-shadow: 0 6px 20px -8px rgba(61,50,38,0.35);
}
.conv-list-head { display: flex; align-items: center; gap: 12px; margin-bottom: 0; }
.conv-list-icon {
  font-size: 26px;
  width: 52px;
  height: 52px;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bg-elevated);
  border-radius: 16px;
}
.conv-list-title { font-family: 'Baloo 2', sans-serif; font-size: 22px; font-weight: 800; line-height: 1.1; }
.conv-list-sub { font-size: 12.5px; color: var(--text-dim); margin-top: 2px; }

.conv-ex-list { display: flex; flex-direction: column; gap: 10px; }
.conv-ex {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 14px;
  border-radius: 16px;
  background: var(--card);
  box-shadow: 0 2px 8px rgba(61,50,38,0.06);
}
.conv-ex-icon {
  font-size: 22px;
  width: 40px;
  height: 40px;
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bg-elevated);
  border-radius: 12px;
}
.conv-ex-body { flex: 1; min-width: 0; }
.conv-ex-name { font-weight: 800; font-size: 15px; margin-bottom: 3px; }
.conv-ex-how { font-size: 13px; color: var(--text); line-height: 1.5; opacity: 0.85; }
.conv-ex-tip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  margin-top: 8px;
  font-size: 11.5px;
  font-weight: 700;
  color: #5e8a68;
  background: rgba(127,182,133,0.16);
  padding: 4px 9px;
  border-radius: 999px;
}

/* Shares one right-aligned column with the "Logged Nx" badge above it, so
   both line up flush with the same right margin instead of the badge
   trailing off wherever the name text happens to end. */
.conv-ex-action {
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 6px;
}

.conv-ex-count {
  font-size: 10.5px;
  font-weight: 700;
  color: var(--text-dim);
  background: var(--locked);
  padding: 2px 7px;
  border-radius: 999px;
}

/* Toned down from an earlier, showier gradient+shadow treatment — same
   light-touch style as .meal-add-btn, just enough polish without stealing
   attention from the exercise itself. */
.conv-log-btn {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1px;
  padding: 8px 10px;
  border-radius: 12px;
  background: linear-gradient(135deg, #ff9d6c, #e8672f);
  color: #fff6ee;
  font-weight: 800;
  font-size: 11px;
  line-height: 1.1;
  box-shadow: 0 1px 5px rgba(179,64,15,0.35);
  transition: transform 0.12s;
}
.conv-log-btn span {
  font-size: 8.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  opacity: 0.85;
}
.conv-log-btn:active { transform: scale(0.94); }

.conv-posture-list, .conv-ex-list, .conv-list-head { animation: convFade 0.3s ease both; }
@keyframes convFade { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }

/* ---------------- Chapter theme variants ---------------- */

[data-theme="garden"] {
  --w-1: #fdf1d8;
  --w-2: #ffe0a3;
  --w-3: #e2a640;
  --w-glow: #ffd98a;
}

[data-theme="meadow"] {
  --w-1: #f9f5da;
  --w-2: #e8dd8a;
  --w-3: #b8a83a;
  --w-glow: #e8dd8a;
}

[data-theme="orchard"] {
  --w-1: #eef7e0;
  --w-2: #bfe28f;
  --w-3: #5a9c3e;
  --w-glow: #a8dc7a;
}

[data-theme="forest"] {
  --w-1: #e3ede0;
  --w-2: #9dc79a;
  --w-3: #3f7d4f;
  --w-glow: #7fbf8a;
}

[data-theme="hillside"] {
  --w-1: #fbe6d8;
  --w-2: #f0b17e;
  --w-3: #c96b3a;
  --w-glow: #f2a35f;
}

[data-theme="coast"] {
  --w-1: #e0f3f5;
  --w-2: #a8dde0;
  --w-3: #3f9aa0;
  --w-glow: #7fd4d8;
}

[data-theme="highlands"] {
  --w-1: #eee9f5;
  --w-2: #c9b8e0;
  --w-3: #7a5fa0;
  --w-glow: #b39ddb;
}

[data-theme="dawn"] {
  --w-1: #fff0dc;
  --w-2: #ffcf8a;
  --w-3: #e8823c;
  --w-glow: #ffb066;
}

[data-theme="grove"] {
  --w-1: #f3f0d8;
  --w-2: #cfe0a0;
  --w-3: #5f8536;
  --w-glow: #9cc260;
}

[data-theme="river"] {
  --w-1: #e3f0e0;
  --w-2: #a8d0c8;
  --w-3: #3f8fa0;
  --w-glow: #6fc4d4;
}

[data-theme="aurora"] {
  --w-1: #eef2f7;
  --w-2: #b8cbe0;
  --w-3: #6a5a9c;
  --w-glow: #7ec8ff;
}

[data-theme="evergreen"] {
  --w-1: #eef4f0;
  --w-2: #b8d4c4;
  --w-3: #2d6248;
  --w-glow: #5fa888;
}

[data-theme="prairie"] {
  --w-1: #f9f3d8;
  --w-2: #e0cf7a;
  --w-3: #a88a2e;
  --w-glow: #e0c04a;
}

[data-theme="canyon"] {
  --w-1: #fce8dc;
  --w-2: #e8a878;
  --w-3: #b8562e;
  --w-glow: #e07a42;
}

[data-theme="brook"] {
  --w-1: #e6f0e4;
  --w-2: #a8cfa0;
  --w-3: #4a8a5c;
  --w-glow: #7fc494;
}

[data-theme="lake"] {
  --w-1: #e2eff5;
  --w-2: #9cc9dc;
  --w-3: #3a7a9c;
  --w-glow: #6bb4d4;
}

[data-theme="oasis"] {
  --w-1: #f5f0d8;
  --w-2: #d4c478;
  --w-3: #7a9c3e;
  --w-glow: #a8c94e;
}

[data-theme="dunes"] {
  --w-1: #faf0da;
  --w-2: #e8cf94;
  --w-3: #c9963f;
  --w-glow: #e8b45f;
}

[data-theme="tundra"] {
  --w-1: #eef4f5;
  --w-2: #c4d8d8;
  --w-3: #6a8c8a;
  --w-glow: #9cc4c0;
}

[data-theme="rainforest"] {
  --w-1: #e2f0e0;
  --w-2: #8fc48a;
  --w-3: #2a7a3a;
  --w-glow: #4fb050;
}

[data-theme="glacier"] {
  --w-1: #eef7fa;
  --w-2: #b8e0ec;
  --w-3: #4a94ac;
  --w-glow: #7fd0e4;
}

[data-theme="lotus"] {
  --w-1: #ffe9ec;
  --w-2: #ffb3c6;
  --w-3: #e0567a;
  --w-glow: #ff8aa8;
}

/* ---------------- Onboarding ---------------- */

.onboard-overlay {
  position: absolute;
  inset: 0;
  z-index: 50;
  background: linear-gradient(160deg, #fff3e0, #fdf6ec);
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 32px 26px;
  overflow-y: auto;
}

.onboard-dots {
  display: flex;
  justify-content: center;
  gap: 6px;
  margin-bottom: 18px;
}

.onboard-dots span {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--locked);
}

.onboard-dots span.is-active {
  background: var(--accent);
  box-shadow: 0 0 8px var(--accent);
}

.onboard-hero {
  text-align: center;
  margin-bottom: 34px;
}

.onboard-icon {
  font-size: 52px;
  display: block;
  margin-bottom: 12px;
  filter: drop-shadow(0 0 16px var(--accent));
}

.onboard-logo {
  width: 150px;
  height: auto;
  display: block;
  margin: 0 auto 12px;
  filter: drop-shadow(0 4px 16px rgba(224,86,122,0.35));
}

.onboard-hero h1 {
  font-size: 30px;
  margin: 0 0 12px;
  letter-spacing: 0.02em;
}

.onboard-hero p {
  color: var(--text-dim);
  font-size: 14px;
  line-height: 1.6;
  max-width: 280px;
  margin: 0 auto;
}

.onboard-overlay h2 {
  text-align: center;
  font-size: 20px;
  margin: 0 0 6px;
}

.onboard-sub {
  text-align: center;
  color: var(--text-dim);
  font-size: 13px;
  margin: 0 0 22px;
}

.onboard-btn {
  width: 100%;
  padding: 15px;
  border-radius: 16px;
  background: linear-gradient(135deg, var(--accent-2), var(--accent));
  color: var(--on-accent);
  font-weight: 800;
  font-size: 16px;
  margin-top: 8px;
}
.onboard-btn:active { transform: scale(0.98); }

.onboard-skip {
  width: 100%;
  padding: 12px;
  margin-top: 10px;
  color: var(--text-dim);
  font-weight: 700;
  font-size: 13px;
}

.focus-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-bottom: 22px;
}

.focus-card {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 14px;
  border-radius: 16px;
  background: var(--card);
  border: 2px solid transparent;
  text-align: left;
  box-shadow: 0 2px 8px rgba(61,50,38,0.06);
}

.focus-card.is-selected {
  border-color: var(--accent);
  background: rgba(255,157,108,0.1);
}

.focus-icon { font-size: 28px; flex-shrink: 0; }
.focus-label { font-weight: 800; font-size: 15px; }
.focus-desc { font-size: 12px; color: var(--text-dim); margin-top: 2px; }

/* ---------------- Auth flow (splash → sign in → app) ---------------- */

/* The overlay becomes a plain positioned stage; the active screen fills it and
   owns its own padding + scroll, so screens can swap without layout jump. */
.auth-overlay { padding: 0; }

.onboard-screen {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 32px 26px;
  overflow-y: auto;
}
.auth-screen {
  justify-content: flex-start;
  padding-top: 40px;
  padding-bottom: 28px;
}

/* Whole-panel enter/exit for the splash <-> auth swap. Kept subtle so the
   per-item stagger below can carry the vertical motion without fighting it. */
.onboard-screen.is-entering { animation: obEnter 0.5s cubic-bezier(0.2, 0.85, 0.25, 1) both; }
.onboard-screen.is-exiting  { animation: obExit 0.36s ease forwards; pointer-events: none; }

@keyframes obEnter { from { opacity: 0; transform: scale(0.99); } to { opacity: 1; transform: none; } }
@keyframes obExit  { to   { opacity: 0; transform: translateY(-26px) scale(0.965); filter: blur(6px); } }

/* Staggered rise-in for each auth control. */
.auth-stagger > * { animation: obRise 0.5s cubic-bezier(0.2, 0.85, 0.25, 1) both; animation-delay: calc(var(--i, 0) * 55ms + 90ms); }
@keyframes obRise { from { opacity: 0; transform: translateY(15px); } to { opacity: 1; transform: none; } }

.auth-head { text-align: center; margin-bottom: 20px; }
.auth-logo {
  width: 64px;
  height: auto;
  display: block;
  margin: 0 auto 12px;
  filter: drop-shadow(0 4px 14px rgba(224, 86, 122, 0.3));
}
.auth-title { font-family: 'Baloo 2', system-ui, sans-serif; font-size: 24px; margin: 0 0 6px; }
.auth-sub { color: var(--text-dim); font-size: 13px; margin: 0; line-height: 1.5; }

.auth-social { display: flex; flex-direction: column; gap: 10px; margin-bottom: 18px; }
.social-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  width: 100%;
  padding: 13px;
  border-radius: 14px;
  background: var(--card);
  border: 1.5px solid #eadfce;
  font-weight: 700;
  font-size: 14.5px;
  color: var(--text);
  box-shadow: 0 2px 6px rgba(61, 50, 38, 0.05);
  transition: transform 0.15s, box-shadow 0.15s, border-color 0.15s;
}
.social-btn:hover { border-color: #ddd0ba; box-shadow: 0 4px 12px rgba(61, 50, 38, 0.08); }
.social-btn:active { transform: scale(0.98); }
.social-btn svg { flex-shrink: 0; }

/* Apple's own guidelines want its button in black with white text/mark —
   this is the standard "Sign in with Apple" appearance. */
.social-btn-apple {
  background: #000;
  border-color: #000;
  color: #fff;
}
.social-btn-apple:hover { border-color: #000; background: #111; }

.auth-divider {
  display: flex;
  align-items: center;
  gap: 12px;
  color: var(--text-dim);
  font-size: 12px;
  margin: 4px 0 16px;
}
.auth-divider::before,
.auth-divider::after { content: ''; flex: 1; height: 1px; background: #eadfce; }

/* ---------------- Survey (onboarding + Profile "Retake Survey") ---------------- */

.survey-dots { display: flex; justify-content: center; gap: 6px; margin-bottom: 14px; }
.survey-dot { width: 7px; height: 7px; border-radius: 50%; background: #eadfce; }
.survey-dot.is-active { background: var(--accent); width: 18px; border-radius: 4px; }

.survey-list { display: flex; flex-direction: column; gap: 10px; margin-bottom: 18px; }

.survey-card {
  display: flex;
  align-items: center;
  gap: 14px;
  width: 100%;
  text-align: left;
  padding: 14px 16px;
  border-radius: 16px;
  background: var(--card);
  box-shadow: 0 2px 8px rgba(61,50,38,0.06);
  border: 1.5px solid transparent;
  transition: transform 0.15s, box-shadow 0.15s, border-color 0.15s;
}
.survey-card:active { transform: scale(0.985); }
.survey-card.is-selected { border-color: var(--accent); background: rgba(255,157,108,0.1); box-shadow: 0 4px 14px -6px rgba(255,157,108,0.4); }

.survey-card-icon { font-size: 24px; width: 42px; height: 42px; flex-shrink: 0; display: flex; align-items: center; justify-content: center; background: var(--bg-elevated); border-radius: 13px; }
.survey-card-copy { display: flex; flex-direction: column; gap: 2px; flex: 1; min-width: 0; }
.survey-card-label { font-weight: 800; font-size: 15px; }
.survey-card-desc { font-size: 12px; color: var(--text-dim); line-height: 1.35; }

.survey-summary-hero { font-size: 44px; text-align: center; margin-bottom: 6px; }
.survey-summary-list { display: flex; flex-wrap: wrap; gap: 8px; justify-content: center; margin-bottom: 18px; }
.survey-chip {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 8px 13px;
  border-radius: 999px;
  background: var(--card);
  font-size: 12.5px;
  font-weight: 700;
  box-shadow: 0 2px 6px rgba(61,50,38,0.06);
}
.survey-chip .chip-icon { font-size: 14px; }

/* Weekly availability step — a segmented same/custom toggle, then one or two
   category blocks (free time / travel time), each either "I'm not sure" or
   a list of from-to time ranges plus an "add another time" button. */
.avail-same-fields { display: flex; flex-direction: column; gap: 14px; margin-bottom: 4px; }

.avail-category {
  background: var(--card);
  border-radius: 14px;
  padding: 12px;
}
.avail-category-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 8px;
}
.avail-category-title { font-weight: 800; font-size: 13.5px; }
.avail-unsure-toggle {
  display: flex;
  align-items: center;
  gap: 5px;
  font-size: 11.5px;
  font-weight: 700;
  color: var(--text-dim);
  white-space: nowrap;
}
.avail-unsure-toggle input { width: 14px; height: 14px; }

.avail-range-list { display: flex; flex-direction: column; gap: 8px; margin-bottom: 8px; }
.avail-range-row {
  display: flex;
  align-items: center;
  gap: 8px;
}
.avail-range-row .auth-input {
  flex: 1;
  min-width: 0;
  width: auto;
  border: 1.5px solid #eadfce;
  border-radius: 9px;
  padding: 7px 6px;
  font-family: inherit;
  font-size: 12.5px;
  background: var(--bg-elevated);
}
.avail-range-sep { font-size: 11.5px; font-weight: 700; color: var(--text-dim); flex-shrink: 0; }
.avail-range-remove {
  flex-shrink: 0;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: var(--bg-elevated);
  color: var(--text-dim);
  font-size: 11px;
  line-height: 1;
}
.avail-add-range {
  font-size: 12px;
  font-weight: 800;
  color: var(--accent);
}

.avail-day-list { display: flex; flex-direction: column; gap: 14px; margin-bottom: 4px; }
.avail-day-block {
  border-radius: 14px;
  padding: 10px 0 2px;
  border-top: 1.5px solid #eee0cc;
}
.avail-day-block:first-child { border-top: none; padding-top: 0; }
.avail-day-name { font-weight: 800; font-size: 13px; margin-bottom: 8px; }
.avail-day-block .avail-category { background: var(--bg-elevated); margin-bottom: 8px; }

.auth-seg {
  display: flex;
  background: #f1e7d6;
  border-radius: 12px;
  padding: 4px;
  margin-bottom: 12px;
}
.auth-seg button {
  flex: 1;
  padding: 9px;
  border-radius: 9px;
  font-weight: 700;
  font-size: 13px;
  color: var(--text-dim);
  transition: background 0.2s, color 0.2s, box-shadow 0.2s;
}
.auth-seg button.is-active { background: var(--card); color: var(--text); box-shadow: 0 1px 4px rgba(61, 50, 38, 0.1); }

.auth-input {
  width: 100%;
  padding: 14px 15px;
  border-radius: 13px;
  border: 1.5px solid #eadfce;
  background: var(--bg-elevated);
  font-family: inherit;
  font-size: 15px;
  color: var(--text);
  margin-bottom: 10px;
  transition: border-color 0.2s, box-shadow 0.2s;
}
.auth-input::placeholder { color: #b8a68c; }
.auth-input:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px rgba(255, 157, 108, 0.18); }
.auth-input.shake-input { animation: authShake 0.4s; }

@keyframes authShake {
  0%, 100% { transform: translateX(0); }
  20%, 60% { transform: translateX(-6px); }
  40%, 80% { transform: translateX(6px); }
}

.auth-submit { margin-top: 4px; }

.survey-nav-row {
  display: flex;
  align-items: stretch;
  gap: 10px;
  margin-top: 8px;
}
.survey-nav-row .onboard-btn { margin-top: 0; flex: 1; }

.survey-back-btn {
  padding: 12px 16px;
  border-radius: 16px;
  font-weight: 800;
  font-size: 15px;
  color: var(--text-dim);
  background: var(--card);
  border: 1px solid rgba(61,50,38,0.1);
}
.survey-back-btn:active { transform: scale(0.97); }

/* On the summary screen, the back button stands alone below "Start
   Growing" — a plain centered text link rather than a bordered button. */
.survey-back-btn:not(.survey-back-inline) {
  display: block;
  width: 100%;
  text-align: center;
  margin-top: 10px;
  padding: 6px;
  background: none;
  border: none;
  font-size: 13px;
}

.survey-skip-btn {
  display: block;
  width: 100%;
  text-align: center;
  margin-top: 10px;
  padding: 6px;
  font-size: 13px;
  font-weight: 700;
  color: var(--text-dim);
  text-decoration: underline;
  text-underline-offset: 2px;
}

.auth-switch { text-align: center; font-size: 13px; color: var(--text-dim); margin-top: 16px; }
.auth-switch button { color: var(--accent); font-weight: 800; }

.auth-legal { text-align: center; font-size: 11px; color: var(--text-dim); margin-top: 14px; line-height: 1.5; opacity: 0.85; }

/* Auth -> app: iris the overlay closed while the content sinks away, revealing
   the app that has already been rendered underneath. */
.auth-overlay.is-revealing { animation: overlayIris 0.66s cubic-bezier(0.7, 0, 0.25, 1) forwards; }
@keyframes overlayIris {
  0%   { clip-path: circle(150% at 50% 42%); }
  100% { clip-path: circle(0% at 50% 42%); }
}
.auth-overlay.is-revealing .onboard-screen { animation: screenSink 0.66s ease forwards; }
@keyframes screenSink { to { transform: scale(1.08); opacity: 0; } }

/* The app shell blooms in as the iris opens onto it. */
.app-enter { animation: appArrive 0.75s cubic-bezier(0.2, 0.8, 0.25, 1) both; }
@keyframes appArrive { from { opacity: 0; transform: scale(0.965) translateY(8px); } to { opacity: 1; transform: none; } }

@media (prefers-reduced-motion: reduce) {
  .onboard-screen.is-entering,
  .onboard-screen.is-exiting,
  .auth-stagger > *,
  .auth-overlay.is-revealing,
  .auth-overlay.is-revealing .onboard-screen,
  .app-enter { animation-duration: 0.001s; }
}

