/* ============================================================================
   PRACTICE MODE (Phase 2)
   ----------------------------------------------------------------------------
   Spotlight overlay + instruction card. Practice runs on its OWN isolated
   local sandbox board (not the user's real team), so this file deliberately
   only styles the overlay chrome — no mock-board styles. The full traffic-light
   palette, scanner, team-bar, etc. come from their production CSS files because
   the live board (the sandbox) is what the user sees during practice.

   z-index: 9500 (above coach-marks at 9400, below system-critical dialogs).
   ============================================================================ */

.practice-spotlight-root {
  font-family: inherit;
}

.practice-spotlight-backdrop {
  /* Inline positioning set by JS; this rule provides paint-only defaults.
     NO backdrop blur: the steps ask the user to READ the board (which rows
     line up, where the readout lands), and a blur defeats that. The dim alone
     carries the "look here" framing. */
  background: rgba(15, 23, 42, 0.55);
}

body.dark-mode .practice-spotlight-backdrop {
  background: rgba(0, 0, 0, 0.65);
}

.practice-spotlight-ring {
  /* Soft teal halo around the target. Animates as the target moves. */
  border-radius: 12px;
  pointer-events: none;
}

/* ---------- Instruction Card ----------
   2026-10-08: the card IS the shared guide card (css/feature-tour.css
   .fr-guide-*), so the tour, tips and Show me how read as one feature. Only
   what is specific to a hands-on step lives here: the width, the line breaks
   in a step body, the feedback line and the gesture checklist. */
.practice-spotlight-card.fr-guide-card {
  width: 340px;
  max-width: calc(100vw - 32px);
  z-index: 1;
  pointer-events: auto;
  animation: practice-card-in 0.22s cubic-bezier(0.4, 0, 0.2, 1);
}

@keyframes practice-card-in {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* Step bodies carry real newlines (escapeHTML keeps them safe, so no <br>);
   pre-line renders them while still wrapping long lines. */
.practice-card-body {
  white-space: pre-line;
}
/* The text and the step's picture, as one block (and one scroll on phones). */
.practice-card-scroll { display: flex; flex-direction: column; gap: 12px; min-width: 0; }
/* More below (phones): the bottom edge fades until the end is reached. */
.practice-card-scroll.has-more {
  -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 36px), transparent);
  mask-image: linear-gradient(to bottom, #000 calc(100% - 36px), transparent);
}

/* ---------- Gesture checklist (2026-10-08) ----------
   A step with two gestures (move, then resize) ticks each one off as the
   learner does it, so they can see what is left rather than read a nudge. */
.practice-card-checks {
  list-style: none;
  margin: 0;
  padding: 10px 12px;
  border-radius: 12px;
  background: var(--guide-soft, #f8fafc);
  display: flex;
  flex-direction: column;
  gap: 6px;
  font-size: 13px;
  font-weight: 600;
  color: var(--guide-ink-2, #475569);
}
.practice-card-checks li { display: flex; align-items: center; gap: 8px; }
.practice-card-checks li i { color: var(--slate-400, #94a3b8); width: 16px; text-align: center; }
.practice-card-checks li.is-done { color: var(--primary-700, #0f766e); }
.practice-card-checks li.is-done i { color: var(--primary-500, #14b8a6); }
body.dark-mode .practice-card-checks li.is-done { color: var(--primary-300, #5eead4); }

/* ---------- Feedback line ---------- */
.practice-card-feedback {
  font-size: 13px;
  font-weight: 600;
  line-height: 1.45;
  padding: 0;
  transition: all 0.2s ease;
}
.practice-card-feedback:empty { display: none; }
.practice-card-feedback.success,
.practice-card-feedback.error,
.practice-card-feedback.notice {
  padding: 9px 12px;
  border-radius: 12px;
}
.practice-card-feedback.success { color: var(--primary-700, #0f766e); background: var(--primary-50, #f0fdfa); }
.practice-card-feedback.error { color: var(--amber-700, #b45309); background: rgba(251, 191, 36, 0.14); }
/* Neutral notice — neither praise nor correction (2026-08-26): the two-stage
   Esc confirm is a statement of fact, not a mistake. */
.practice-card-feedback.notice { color: var(--slate-700, #334155); background: rgba(100, 116, 139, 0.12); }
body.dark-mode .practice-card-feedback.success { color: var(--primary-300, #5eead4); background: rgba(45, 212, 191, 0.12); }
body.dark-mode .practice-card-feedback.error { color: #fde68a; background: rgba(251, 191, 36, 0.16); }
body.dark-mode .practice-card-feedback.notice { color: var(--slate-300, #cbd5e1); background: rgba(148, 163, 184, 0.16); }

@media (max-width: 640px) {
  .practice-spotlight-card {
    width: calc(100vw - 24px);
    left: 12px !important;
  }
  /* JS can't beat a fixed-position pin here, so it instead stamps
     data-mobile-edge based on where the spotlight hole sits, and we pin the
     card to the edge AWAY from the target. (Stamped in positionCard().)

     Retuned 2026-07-31 (user: "the text would be better being at the top as the
     highlight highlights the lower and mid sections typically"). The card now
     defaults to the TOP and only drops to a bottom sheet when the hole sits
     entirely in the top ~30% band — because the steps mostly spotlight mid and
     lower board content, and because scrollTargetIntoClearZone() parks the
     target near the top of the screen on a narrow viewport. The unstamped
     fallback moved to `top` with it, so the first paint (before positionCard()
     runs) doesn't flash the sheet at the bottom and then jump up. */
  .practice-spotlight-card[data-mobile-edge="top"],
  .practice-spotlight-card:not([data-mobile-edge]) {
    top: 16px !important;
    bottom: auto;
  }
  .practice-spotlight-card[data-mobile-edge="bottom"] {
    bottom: 16px;
    top: auto !important;
  }

  /* 2026-08-08 — the sheet is pinned to an edge but had NO height limit, so a
     long step body simply grew across the highlight it was describing. On a
     727px-tall phone the first step rendered a 321px card at top:16px (ending
     at y=337) while its hole started at y=324: a 13px overlap, reported as
     "the highlight is under the text box".

     positionCard() cannot fix this — the !important pins above deliberately
     discard its computed top/left on mobile — so the ceiling has to live here,
     in the same rule that does the pinning. --practice-hole-edge is stamped by
     positionCard() with the px distance from the card's edge to the nearest
     edge of the hole; the fallback keeps the card inside a sane band if the
     variable is ever missing. Body scrolls inside the card rather than the card
     growing over the target. */
  .practice-spotlight-card {
    display: flex;
    flex-direction: column;
    max-height: var(--practice-hole-edge, 46vh);
  }
  /* 2026-10-08: the text and the step's annotated picture scroll together
     (.practice-card-scroll), so a picture can never push the buttons off a
     phone's card. The rules below moved here from .practice-card-body. */
  .practice-spotlight-card .practice-card-scroll {
    overflow-y: auto;
    /* THE BODY IS THE ONLY ELASTIC PART (2026-09-07, owner: "the text is even
       hidden or extremely vague"). The card's height is capped by
       --practice-hole-edge, and .practice-card-feedback appears MID-STEP (a
       validator hint like "Drag the scanner across the day") adding ~40px into
       that fixed budget. With every child free to shrink, the browser took it
       out of the body: the observed 2/7 card rendered its title, then the amber
       feedback line, and NO body copy at all. flex:1 1 auto + min-height make
       the body the one thing that gives, and a floor stops it collapsing —
       the header, feedback and buttons keep their natural size instead. */
    flex: 1 1 auto;
    min-height: 4.5em;
  }
  /* Never let the feedback line or the button row be the thing that shrinks. */
  .practice-spotlight-card .practice-card-feedback,
  .practice-spotlight-card .practice-card-title,
  .practice-spotlight-card .practice-card-step,
  .practice-spotlight-card .fr-guide-head,
  .practice-spotlight-card .fr-guide-progress,
  .practice-spotlight-card .practice-card-checks,
  .practice-spotlight-card .practice-card-footer {
    flex: 0 0 auto;
  }
  /* The guide card is roomier than the old practice card (2026-10-08), and the
     budget above is tight: on a 390x664 phone step 1 has ~247px above its ring.
     The 44px touch-floor X made the head a 44px row, so the minimum content
     outgrew the cap and the buttons spilled below the card. Pin the X in the
     corner (the head becomes one kicker line), tighten the gaps, and if the
     budget is still short, scroll the card rather than paint past its edge. */
  .practice-spotlight-card.fr-guide-card {
    gap: 8px;
    padding: 12px 16px 12px;
    overflow-y: auto;
  }
  .practice-spotlight-card .fr-guide-head { padding-right: 46px; min-height: 0; }
  .practice-spotlight-card .fr-guide-progress { margin-right: 46px; }
  .practice-spotlight-card .fr-guide-x { position: absolute; top: 6px; right: 6px; }
  .practice-spotlight-card .fr-guide-title { font-size: 16px; }
}

/* ---------- Body marker ----------
   Other code can opt out of itself during practice (e.g. sync listeners can
   skip demo rows, autosave can be deferred) by checking body.practice-mode-active
   or window.__practiceModeActive. */
body.practice-mode-active {
  /* No visual change — marker only. */
}

/* ---------- Board-swap veil (2026-08-26) ----------
   start() adds the body marker SYNCHRONOUSLY, then awaits
   applyPracticeSandboxBoard() — an async create + seed + setActiveBoard. For
   that whole gap the user's PREVIOUS board is still fully painted, so the
   timezone rows of whatever they were just looking at (typically the demo /
   sample board) sat on screen and then visibly swapped to the sandbox roster:
   the "clicking practice flashes the previous demo's timezones" report.

   Cover the board for exactly that gap. This is a plain opaque veil, not a
   spinner: the wait is short (two RAFs after the seed resolves) and a spinner
   for ~a frame reads as jank of its own. It is removed in the same RAF block
   that mounts the first spotlight, and on EVERY abort path, so it can never
   outlive the swap it hides.

   Painted above the board but BELOW the spotlight (z 9500) and the completion
   card, so the first step's ring is never veiled. */
.practice-board-veil {
  position: fixed;
  inset: 0;
  z-index: 9400;
  background: var(--bg-primary, #0f172a);
  pointer-events: all;
  opacity: 1;
}
/* Fade OUT only. Appearing instantly is correct (it must hide the old board on
   the very first frame); dissolving away lets the seeded board arrive gently. */
.practice-board-veil.is-clearing {
  opacity: 0;
  transition: opacity 0.22s ease;
}
@media (prefers-reduced-motion: reduce) {
  .practice-board-veil.is-clearing { transition: none; }
}

/* ============================================================================
   COMPLETION CARD
   ----------------------------------------------------------------------------
   Modal-light card shown when practice completes. Offers three next steps —
   "Create your own group" (the culmination, → Onboarding.startManual),
   "Back to my team" (clean return + sandbox teardown), and "Keep exploring the
   sandbox" (dismiss, stay on the sandbox board). No auto-dismiss: backdrop
   click / Esc / "Keep exploring" all leave the user on the sandbox.
   ============================================================================ */

.practice-completion-root {
  position: fixed;
  inset: 0;
  z-index: 9550;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  pointer-events: none;
  animation: practice-completion-in 0.32s cubic-bezier(0.4, 0, 0.2, 1);
}

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

.practice-completion-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(15, 23, 42, 0.5);
  pointer-events: auto;
}

/* The finish is the tour's finish card (2026-10-08); the guide card is
   position:fixed by default, so this one sits in the centred root instead. */
.practice-completion-card.fr-guide-card {
  position: relative;
  width: 100%;
  max-width: 420px;
  padding: 26px 26px 20px;
  pointer-events: auto;
  animation: practice-completion-card-in 0.4s cubic-bezier(0.4, 0, 0.2, 1);
}

@keyframes practice-completion-card-in {
  from { opacity: 0; transform: translateY(12px) scale(0.97); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}

.practice-completion-card .fr-guide-check {
  animation: practice-completion-pop 0.5s cubic-bezier(0.34, 1.56, 0.64, 1) 0.1s both;
}

@keyframes practice-completion-pop {
  from { opacity: 0; transform: scale(0.4); }
  to   { opacity: 1; transform: scale(1); }
}

@media (max-width: 640px) {
  .practice-completion-root { align-items: flex-end; padding: 10px; }
  .practice-completion-card.fr-guide-card { max-width: none; border-radius: 22px; }
}
