/* ── miniapp/css/unlock.css ─────────────────────────────────────────────────
 * Unlock-onboarding v0.3.
 * Sprint 1 (UNLK-S-2026-05-11): state-class scaffold.
 * Sprint 2 (UNLK-S-2026-05-18): slide-in keyframes, tutorial modal chrome.
 *
 * Surface vocabulary clarification (per design review §4):
 *   - "Unlock surface" ids:   level-card | rewards-screen | mission-tile
 *     (server/lib/unlock-rules.js — shape-of-DOM gating)
 *   - "Tutorial surface" ids: tr | rewards | crash
 *     (server/routes/tutorial.js  — what tutorial demonstrates which game)
 *   These two namespaces stay separate by design.
 *
 * Rules:
 *   1. Every value resolves to a CSS variable from main.css :root.
 *   2. Every animation has a prefers-reduced-motion override.
 *   3. State classes use the body.is-locked-* pattern.
 * ───────────────────────────────────────────────────────────────────────── */

/* ── State gating ─────────────────────────────────────────────────────────── */

/* L2-locked: the Rewards entry point in the header AND the Rewards screen
 * content. Hiding both prevents both navigation-to and rendering-of an
 * empty Rewards surface. The header notif button is the primary entry; the
 * inner-content hides defend against deep-links / back-button navigation.
 * Updated Sprint UNLK-S-2026-05-12 — Daily/Weekly `.reward-row` deleted,
 * `.streak-ladder` renamed to `.streak-calendar`. */
body.is-locked-rewards #rewards-notif-btn,
body.is-locked-rewards .streak-calendar,
body.is-locked-rewards .streak-lapse-warning {
  display: none !important;
}

body.is-locked-mission .mission-tile {
  display: none !important;
}

/* ── Unlock reveal — slide-in animation (sprint 2) ───────────────────────── */

@keyframes unlock-slide-in {
  from { transform: translateY(var(--space-5)); opacity: 0; }
  to   { transform: translateY(0);              opacity: 1; }
}

.unlock-reveal-slidein {
  animation: unlock-slide-in var(--motion-md) var(--ease-out) both;
}

/* ── Tutorial modal — bottom-sheet pattern (sprint 2) ────────────────────── */
/* Mirrors the .kyc-overlay / .rb-* pattern (Shipped DS v1.3 §3.3 + §6).    */

.tut-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.55);
  display: flex;
  align-items: flex-end;
  justify-content: center;
  z-index: 1000;
  animation: tut-fade-in var(--motion-fast) var(--ease-out);
}
.tut-overlay[hidden] { display: none; }

.tut-sheet {
  width: 100%;
  max-width: var(--app-max-width);
  background: var(--bg);
  border-top: 1px solid var(--pill-border);
  border-radius: var(--space-4) var(--space-4) 0 0;
  padding: var(--space-5) var(--space-5) var(--space-7);
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  animation: tut-slide-up var(--motion-md) var(--ease-out);
}

.tut-handle {
  width: var(--space-7);
  height: 4px;
  background: var(--border);
  border-radius: 2px;
  margin: 0 auto;
}

.tut-frame {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-5) 0;
  text-align: center;
  min-height: 140px;
}

.tut-frame-visual {
  font-size: 48px;
  line-height: 1;
  /* Each frame's emoji-only visual; sprint 3 can swap for SVG demos. */
}

.tut-caption {
  color: var(--cream);
  font-family: var(--font-ui);
  font-size: 16px;
  font-weight: 500;
  max-width: 30ch;
}

.tut-progress {
  display: flex;
  gap: var(--space-2);
  justify-content: center;
}
.tut-dot {
  width: var(--space-2);
  height: var(--space-2);
  border-radius: 50%;
  background: var(--border);
}
.tut-dot.is-active {
  background: var(--cyan);
}

.tut-cta {
  background: var(--cyan);
  color: var(--bg);
  border: none;
  border-radius: var(--space-3);
  padding: var(--space-3) var(--space-5);
  font-family: var(--font-ui);
  font-size: 16px;
  font-weight: 600;
  min-height: 48px;
  cursor: pointer;
}
.tut-cta:focus-visible {
  outline: 2px solid var(--cyan);
  outline-offset: 2px;
}

.tut-skip {
  background: transparent;
  color: var(--muted);
  border: none;
  font-family: var(--font-ui);
  font-size: 14px;
  padding: var(--space-2) var(--space-3);
  cursor: pointer;
  align-self: center;
}
.tut-skip:focus-visible {
  outline: 2px solid var(--cyan);
  outline-offset: 2px;
}

/* The replay "?" button — mirrors .ppc-info-btn (Shipped DS v1.3 §3.3). */
.unlock-replay-btn {
  width: 44px;
  height: 44px;
  min-width: 44px;
  border-radius: 50%;
  background: var(--pill-bg);
  border: 1px solid var(--pill-border);
  color: var(--cyan);
  font-family: var(--font-ui);
  font-size: 18px;
  font-weight: 600;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.unlock-replay-btn:focus-visible {
  outline: 2px solid var(--cyan);
  outline-offset: 2px;
}

@keyframes tut-fade-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}
@keyframes tut-slide-up {
  from { transform: translateY(100%); }
  to   { transform: translateY(0);    }
}

/* ── Mission tile (Sprint UNLK-S-2026-05-12 compact redesign) ─────────────
 * 3-column horizontal card: icon | body (title + progress) | reward chip.
 * Sits beneath the 28-day streak calendar on the Rewards screen. Half the
 * vertical footprint of the legacy stacked layout; the reward chip doubles
 * as the claim CTA (no full-width button competing with the calendar).
 *
 * States (set on .mission-tile):
 *   default       — chip is a quiet UC reward pill (aria-disabled)
 *   .is-claimable — chip morphs to cyan pulse; clickable
 *   .is-claimed   — whole tile dims to 60%, chip shows ✓
 *   .is-empty handled via [hidden] on .mt-row + .mt-empty toggle (no class)
 *   locked        — body.is-locked-mission hides the whole tile
 */

/* Card shell — matches the streak calendar's cyan-border treatment so the
   two cards read as siblings. Padding tighter than the legacy stack so the
   tile is ~100px tall instead of ~220px. */
.mission-tile {
  margin: 12px 16px 0;
  background: linear-gradient(135deg, rgba(0,229,255,0.04), var(--surface-2) 60%);
  border: 1px solid rgba(0, 229, 255, 0.24);
  border-radius: 14px;
  padding: 12px 14px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  font-family: var(--font-ui);
  transition: opacity 200ms ease-out;
}

/* Eyebrow row — "🎯 DAILY MISSION · Resets in 14h 32m". The reset
   countdown is a peer span so it can update independently every 30s. */
.mt-eyebrow {
  display: flex;
  align-items: baseline;
  gap: 4px;
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.6px;
  text-transform: uppercase;
  color: var(--muted);
  line-height: 1.2;
}
.mt-eyebrow-label { white-space: nowrap; }
.mt-eyebrow-sep   { opacity: 0.5; }
.mt-reset-cd {
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  font-weight: 600;
  text-transform: none;
  letter-spacing: 0.2px;
}

/* Vertical list of mission rows. Dividers are thin top borders on every
   row except the first, so the section reads as a single card with
   internal separators rather than N stacked cards. */
.mt-list {
  display: flex;
  flex-direction: column;
}

/* The 3-column row. flex-grow on the body lets the icon and chip stay
   intrinsic-width while the title + progress bar absorb remaining space. */
.mt-row {
  display: flex;
  align-items: center;
  gap: 12px;
  min-width: 0;
  padding: 10px 0;
  transition: opacity 200ms ease-out, background-color 160ms ease-out;
  cursor: default;
  /* Row-as-button focus ring lives on a pseudo-element so it doesn't
     fight the chip's own outline. */
  outline: none;
}
.mt-row + .mt-row {
  border-top: 1px solid rgba(255, 255, 255, 0.06);
}

/* Navigable rows (in-progress + has target screen) — pointer cursor, a
   subtle right-chevron after the chip, and a soft hover/focus highlight
   so the player can tell they're tappable. Claimable + claimed rows
   intentionally don't get this — claimable rows belong to the chip
   pulse, claimed rows are inert. Sprint UNLK-S-2026-05-12. */
.mt-row.is-navigable {
  cursor: pointer;
}
.mt-row.is-navigable:hover,
.mt-row.is-navigable:focus-visible {
  background: rgba(0, 229, 255, 0.04);
}
.mt-row.is-navigable:focus-visible {
  box-shadow: inset 0 0 0 2px rgba(0, 229, 255, 0.45);
  border-radius: 8px;
}
.mt-row.is-navigable::after {
  content: '›';
  color: var(--muted);
  font-size: 18px;
  line-height: 1;
  margin-left: 4px;
  margin-right: 2px;
  opacity: 0.55;
  transition: transform 160ms ease-out, opacity 160ms ease-out;
}
.mt-row.is-navigable:hover::after,
.mt-row.is-navigable:focus-visible::after {
  opacity: 1;
  transform: translateX(2px);
}

/* Mission category icon. 40x40 dark tile with a single emoji glyph. */
.mt-icon {
  flex: 0 0 40px;
  width: 40px;
  height: 40px;
  border-radius: 10px;
  background: rgba(255,255,255,0.05);
  border: 1px solid rgba(255,255,255,0.08);
  display: flex; align-items: center; justify-content: center;
  font-size: 20px;
  line-height: 1;
}

/* Body — title on line 1, progress strip on line 2. min-width:0 is the
   classic fix that allows the inner ellipsis / progress bar to shrink
   when the chip is wide. */
.mt-body {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.mt-title {
  color: var(--cream);
  font-size: 14px;
  font-weight: 600;
  line-height: 1.25;
  /* Ellipsis if the mission label is unexpectedly long (locale variant). */
  overflow: hidden;
  text-overflow: ellipsis;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}

/* Progress strip — bar + count side-by-side. */
.mt-progress {
  display: flex;
  align-items: center;
  gap: 8px;
}
.mt-progress-bar {
  flex: 1 1 auto;
  height: 5px;
  background: rgba(255,255,255,0.08);
  border-radius: 999px;
  overflow: hidden;
  min-width: 40px;
}
.mt-progress-fill {
  height: 100%;
  width: 0%;
  background: var(--cyan);
  transition: width 240ms var(--ease-out);
}
.mt-progress-count {
  flex: 0 0 auto;
  color: var(--muted);
  font-family: var(--font-mono);
  font-size: 11px;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* Reward chip. Three modes — quiet pill (default), pulsing cyan button
   (is-claimable), dimmed ✓ pill (is-claimed). One DOM node, three visuals. */
.mt-chip {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: baseline;
  gap: 3px;
  padding: 6px 10px;
  border-radius: 999px;
  border: 1px solid rgba(0, 229, 255, 0.30);
  background: rgba(0, 229, 255, 0.08);
  color: var(--cyan);
  font-family: var(--font-ui);
  font-size: 13px;
  font-weight: 700;
  line-height: 1.2;
  cursor: not-allowed;
  font-variant-numeric: tabular-nums;
}
.mt-chip-amount { letter-spacing: 0.2px; }
.mt-chip-unit   { font-size: 10px; font-weight: 600; opacity: 0.75; letter-spacing: 0.4px; }
.mt-chip:focus-visible {
  outline: 2px solid var(--cyan);
  outline-offset: 2px;
}
/* Chip is hidden while a mission is in-progress (2026-06-16) — the reward
   shows underneath and the whole row taps through to play. */
.mt-chip[hidden] { display: none !important; }

/* Reward line under the title (2026-06-16) — unified cyan/gold square glyphs,
   matching the Streak tab. Replaces the 🟦/🔑 emoji that used to sit in the
   chip. */
.mt-reward {
  display: flex;
  align-items: center;
  gap: 5px;
  flex-wrap: wrap;
  font-size: 11px;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}
.mt-reward:empty { display: none; }
.mt-reward-label {
  text-transform: uppercase;
  letter-spacing: 0.4px;
  font-size: 9px;
  font-weight: 700;
  opacity: 0.7;
}
.mt-g-dig, .mt-g-key {
  width: 9px; height: 9px; border-radius: 2px; display: inline-block; flex-shrink: 0;
  position: relative; top: 1px;
}
.mt-g-dig { background: var(--cyan); box-shadow: 0 0 5px rgba(0,229,255,0.6); }
.mt-g-key { background: var(--gold); box-shadow: 0 0 5px rgba(255,211,78,0.5); }

/* Claimable — row's chip turns solid cyan, gets a pulse, becomes clickable.
   Sprint UNLK-S-2026-05-12 — state moved from .mission-tile to .mt-row so
   each row in the multi-mission list paints independently. */
.mt-row.is-claimable .mt-chip {
  background: var(--success);
  color: var(--bg);
  border-color: var(--success);
  cursor: pointer;
  animation: mt-chip-pulse 1.6s ease-in-out infinite;
}
@keyframes mt-chip-pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(34,197,94,0.55); }
  50%      { box-shadow: 0 0 0 6px rgba(34,197,94,0);   }
}

/* Claimed — row dims, chip becomes a green-tick badge. */
.mt-row.is-claimed {
  opacity: 0.55;
}
.mt-row.is-claimed .mt-chip {
  background: transparent;
  border-color: var(--success);
  color: var(--success);
  animation: none;
  cursor: default;
}

/* Empty-state line (no eligible mission for this level). Lives inside
   the same card shell so the section never disappears entirely. */
.mt-empty {
  color: var(--muted);
  font-size: 12.5px;
  line-height: 1.45;
  padding: 4px 2px;
}

/* ── Reduced motion — REQUIRED for sprint 2 + 3 + 2026-05-12 acceptance ─── */
/* One block (single source of truth). Sprint UNLK-S-2026-05-12 retired the
   legacy .mission-claim-btn / .mission-progress-fill classes; the mt-*
   replacements are pinned below. */
@media (prefers-reduced-motion: reduce) {
  .unlock-reveal-slidein                  { animation: none; }
  .tut-overlay                            { animation: none; }
  .tut-sheet                              { animation: none; }
  .mt-row.is-claimable .mt-chip           { animation: none; box-shadow: 0 0 0 2px rgba(34,197,94,0.55); }
  .mt-progress-fill                       { transition: none; }
}
