/* ============================================================
   Nia's Puzzles — Base Stylesheet
   ============================================================ */

/* ------------------------------------------------------------
   Design Tokens (CSS Custom Properties)
   ------------------------------------------------------------ */
:root {
  /* Colors */
  --color-bg: #FAF7F0;       /* warm cream — easy on early-reader eyes */
  --color-text: #1A2438;     /* deep indigo — ~12:1 contrast on cream, WCAG AA */
  --color-nia-blue: #1F4FFF; /* cobalt blue — Nia's glasses accent */
  --color-accent: #4CCFE0;   /* cyan accent */

  /* Typography */
  --font-base-size: 1rem;    /* scales with root font size; .mode-big-text overrides */
  --font-family-base: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI',
    Roboto, Helvetica, Arial, sans-serif;
  --line-height-base: 1.5;

  /* Spacing scale (0.25rem steps) */
  --space-1: 0.25rem;  /*  4px */
  --space-2: 0.5rem;   /*  8px */
  --space-3: 0.75rem;  /* 12px */
  --space-4: 1rem;     /* 16px */
  --space-5: 1.5rem;   /* 24px */
  --space-6: 2rem;     /* 32px */
  --space-7: 3rem;     /* 48px */
  --space-8: 4rem;     /* 64px */
}

/* ------------------------------------------------------------
   Accessibility Mode Classes (applied to <html> by later phases)
   ------------------------------------------------------------ */

/* Quiet mode: reduce visual noise (future use) */
html.mode-quiet {
  --color-accent: #4CCFE0;
}

/* Big text mode: scale base font size up by 1.16× */
html.mode-big-text {
  --font-base-size: 1.16rem;
}

/* Reduced motion: eliminate all transitions */
html.mode-reduced-motion * {
  transition-duration: 0s !important;
  animation-duration: 0s !important;
  animation-iteration-count: 1 !important;
}

/* ------------------------------------------------------------
   Reset & Box Model
   ------------------------------------------------------------ */
*,
*::before,
*::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

/* ------------------------------------------------------------
   Base Typography
   ------------------------------------------------------------ */
html {
  font-size: var(--font-base-size);
  font-family: var(--font-family-base);
  line-height: var(--line-height-base);
  color: var(--color-text);
  background-color: var(--color-bg);
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

body {
  min-height: 100vh;
  min-height: 100dvh;
  background-color: var(--color-bg);
  color: var(--color-text);
  font-size: 1rem;
}

h1 {
  font-size: 2rem;
  line-height: 1.2;
  color: var(--color-nia-blue);
  margin-bottom: var(--space-4);
}

h2 {
  font-size: 1.5rem;
  line-height: 1.25;
  margin-bottom: var(--space-3);
}

h3 {
  font-size: 1.25rem;
  line-height: 1.3;
  margin-bottom: var(--space-2);
}

p {
  margin-bottom: var(--space-4);
}

/* ------------------------------------------------------------
   Layout
   ------------------------------------------------------------ */
header[role="banner"] {
  width: 100%;
  padding: var(--space-3) var(--space-4);
  background-color: var(--color-bg);
}

nav[aria-label="Main navigation"] {
  display: flex;
  align-items: center;
  gap: var(--space-3);
}

main {
  width: 100%;
  max-width: 40rem;
  margin: 0 auto;
  padding: var(--space-5) var(--space-4);
}

#app {
  width: 100%;
}

/* ------------------------------------------------------------
   Touch Target Baseline (WCAG 2.5.5 — ≥48×48 CSS px)
   ------------------------------------------------------------ */
button,
a,
[role="button"] {
  min-height: 48px;
  min-width: 48px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-2) var(--space-4);
  cursor: pointer;
  /* Ensure readable color on interactive elements */
  color: var(--color-text);
  text-decoration: none;
}

button {
  background-color: var(--color-nia-blue);
  color: #FFFFFF;
  border: none;
  border-radius: var(--space-2);
  font-size: 1rem;
  font-family: var(--font-family-base);
  transition-duration: 0.15s;
  transition-property: background-color, opacity;
}

button:focus-visible,
a:focus-visible {
  outline: 3px solid var(--color-nia-blue);
  outline-offset: 2px;
}

/* ------------------------------------------------------------
   Badge Color Tokens (Phase 2 — slot picker)
   Saturated, joyful tones on the warm cream background.
   Text is always --color-text (deep indigo) for contrast.
   ------------------------------------------------------------ */
:root {
  --color-badge-blue:   #1F4FFF; /* cobalt — matches Nia's brand blue */
  --color-badge-yellow: #F5B800; /* warm amber-yellow */
  --color-badge-green:  #1E9E4F; /* forest green */
  --color-badge-purple: #7B2FD6; /* vivid violet */

  /* Tints used as card backgrounds (light enough for dark text on top) */
  --color-badge-blue-tint:   #E8EEFF;
  --color-badge-yellow-tint: #FFF8DC;
  --color-badge-green-tint:  #E4F7ED;
  --color-badge-purple-tint: #F3EAFF;
}

/* ------------------------------------------------------------
   Slot Picker Screen
   ------------------------------------------------------------ */
.slot-picker {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-5);
  padding: var(--space-5) 0;
}

.slot-picker__title {
  color: var(--color-nia-blue);
  text-align: center;
  font-size: 2rem;
  margin-bottom: 0;
}

.slot-picker__subtitle {
  color: var(--color-text);
  text-align: center;
  font-size: 1.125rem;
  margin-bottom: 0;
  opacity: 0.75;
}

.slot-picker__grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--space-4);
  width: 100%;
  max-width: 28rem;
  padding: 0 var(--space-2);
  list-style: none;
}

/* ------------------------------------------------------------
   Slot Cards
   ------------------------------------------------------------ */
.slot-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2);
  position: relative;
}

.slot-card__btn {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  width: 100%;
  min-height: 120px;
  border-radius: var(--space-4);
  border: 3px solid transparent;
  padding: var(--space-4);
  cursor: pointer;
  font-size: 0.9375rem;
  font-weight: 600;
  font-family: var(--font-family-base);
  transition-property: transform, box-shadow, border-color;
  transition-duration: 0.15s;
  color: var(--color-text);
  background-color: var(--color-bg);
  position: relative;
}

.slot-card__btn:active {
  transform: scale(0.96);
}

.slot-card__btn:focus-visible {
  outline: 3px solid var(--color-text);
  outline-offset: 3px;
}

/* Per-badge tint backgrounds */
.slot-card--blue   .slot-card__btn { background-color: var(--color-badge-blue-tint);   border-color: var(--color-badge-blue); }
.slot-card--yellow .slot-card__btn { background-color: var(--color-badge-yellow-tint); border-color: var(--color-badge-yellow); }
.slot-card--green  .slot-card__btn { background-color: var(--color-badge-green-tint);  border-color: var(--color-badge-green); }
.slot-card--purple .slot-card__btn { background-color: var(--color-badge-purple-tint); border-color: var(--color-badge-purple); }

/* Hover lift */
.slot-card__btn:hover {
  box-shadow: 0 4px 16px rgba(0,0,0,0.12);
  transform: translateY(-2px);
}

/* Existing slot: slightly deeper border */
.slot-card--exists .slot-card__btn {
  border-width: 4px;
}

.slot-card__icon {
  display: block;
  width: 2.5rem;
  height: 2.5rem;
}

.badge-icon {
  width: 100%;
  height: 100%;
  display: block;
}

/* Badge icon color matches the badge accent */
.slot-card--blue   .badge-icon { color: var(--color-badge-blue); }
.slot-card--yellow .badge-icon { color: var(--color-badge-yellow); }
.slot-card--green  .badge-icon { color: var(--color-badge-green); }
.slot-card--purple .badge-icon { color: var(--color-badge-purple); }

.slot-card__label {
  font-size: 0.875rem;
  font-weight: 700;
  text-align: center;
  line-height: 1.2;
  color: var(--color-text);
}

/* Checkmark badge on existing slots */
.slot-card__checkmark {
  position: absolute;
  top: var(--space-2);
  right: var(--space-2);
  width: 1.5rem;
  height: 1.5rem;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
}

.slot-card--blue   .slot-card__checkmark { background-color: var(--color-badge-blue);   color: #fff; }
.slot-card--yellow .slot-card__checkmark { background-color: var(--color-badge-yellow); color: #1A2438; }
.slot-card--green  .slot-card__checkmark { background-color: var(--color-badge-green);  color: #fff; }
.slot-card--purple .slot-card__checkmark { background-color: var(--color-badge-purple); color: #fff; }

.checkmark-icon {
  width: 1rem;
  height: 1rem;
  display: block;
}

/* Reset button — visually subdued via opacity, NOT via shrinking the hit area.
   WCAG 2.5.5 requires ≥48×48 CSS px touch targets. Opacity provides the
   "secondary action" feel without sacrificing accessibility. */
.slot-card__reset-btn {
  min-height: 48px;
  min-width: 64px;
  height: auto;
  padding: var(--space-2) var(--space-3);
  background-color: transparent;
  color: var(--color-text);
  border: 1.5px solid currentColor;
  border-radius: var(--space-2);
  font-size: 0.75rem;
  font-family: var(--font-family-base);
  cursor: pointer;
  opacity: 0.55;
  transition-property: opacity;
  transition-duration: 0.15s;
  /* override global button touch-target with inline flex */
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.slot-card__reset-btn:hover,
.slot-card__reset-btn:focus-visible {
  opacity: 1;
}

.slot-card__reset-btn:focus-visible {
  outline: 3px solid var(--color-nia-blue);
  outline-offset: 2px;
}

/* ------------------------------------------------------------
   "Choose a different journal" button (landing screen)
   ------------------------------------------------------------ */
.switch-journal-btn {
  margin-top: var(--space-5);
  background-color: transparent;
  color: var(--color-nia-blue);
  border: 2px solid var(--color-nia-blue);
  font-size: 1rem;
}

.switch-journal-btn:hover {
  background-color: #E8EEFF;
}

/* ------------------------------------------------------------
   Parent Challenge Modal
   ------------------------------------------------------------ */
.challenge-overlay {
  position: fixed;
  inset: 0;
  background: rgba(26, 36, 56, 0.55);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-4);
  z-index: 1000;
}

.challenge-card {
  background: var(--color-bg);
  border-radius: var(--space-4);
  padding: var(--space-6);
  max-width: 22rem;
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  box-shadow: 0 8px 32px rgba(0,0,0,0.18);
}

.challenge-intro {
  font-size: 0.9375rem;
  color: var(--color-text);
  opacity: 0.8;
  text-align: center;
  margin-bottom: 0;
  line-height: 1.5;
}

.challenge-question {
  font-size: 1.375rem;
  font-weight: 700;
  color: var(--color-text);
  text-align: center;
  margin-bottom: 0;
}

.challenge-options {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-3);
}

.challenge-btn {
  min-height: 56px;
  min-width: 56px;
  font-size: 1.25rem;
  font-weight: 700;
  background-color: var(--color-badge-blue-tint);
  color: var(--color-text);
  border: 2px solid var(--color-nia-blue);
  border-radius: var(--space-3);
  cursor: pointer;
  transition-property: background-color, transform;
  transition-duration: 0.1s;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-family-base);
}

.challenge-btn:hover {
  background-color: #D0DAFF;
  transform: scale(1.04);
}

.challenge-btn:focus-visible {
  outline: 3px solid var(--color-nia-blue);
  outline-offset: 2px;
}

.challenge-feedback {
  font-size: 0.9375rem;
  color: var(--color-text);
  text-align: center;
  min-height: 1.4em;
  margin-bottom: 0;
  opacity: 0.85;
}

.challenge-cancel-btn {
  background-color: transparent;
  color: var(--color-text);
  border: 1.5px solid currentColor;
  font-size: 0.9375rem;
  opacity: 0.6;
}

.challenge-cancel-btn:hover {
  opacity: 1;
}

/* ------------------------------------------------------------
   Quota-exceeded toast
   ------------------------------------------------------------ */
.quota-toast {
  position: fixed;
  bottom: var(--space-6);
  left: 50%;
  transform: translateX(-50%);
  background: var(--color-text);
  color: var(--color-bg);
  padding: var(--space-3) var(--space-5);
  border-radius: var(--space-3);
  font-size: 0.9375rem;
  max-width: 22rem;
  text-align: center;
  box-shadow: 0 4px 16px rgba(0,0,0,0.2);
  z-index: 1100;
  animation: toast-in 0.2s ease;
}

@keyframes toast-in {
  from { opacity: 0; transform: translateX(-50%) translateY(8px); }
  to   { opacity: 1; transform: translateX(-50%) translateY(0); }
}

html.mode-reduced-motion .quota-toast {
  animation: none;
}

/* ------------------------------------------------------------
   Visually-hidden utility (for live regions, off-screen h1s, etc.)
   ------------------------------------------------------------ */
.visually-hidden {
  position: absolute !important;
  width: 1px !important;
  height: 1px !important;
  padding: 0 !important;
  margin: -1px !important;
  overflow: hidden !important;
  clip: rect(0, 0, 0, 0) !important;
  white-space: nowrap !important;
  border: 0 !important;
}

/* ------------------------------------------------------------
   Bottom Nav (Phase 5)
   Visible on map / journal / level — hidden on picker / title.
   Touch targets ≥ 48×48.
   ------------------------------------------------------------ */
.bottom-nav {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  display: flex;
  justify-content: space-around;
  align-items: stretch;
  background: var(--color-bg);
  border-top: 2px solid rgba(31, 79, 255, 0.18);
  padding: var(--space-2) 0 calc(var(--space-2) + env(safe-area-inset-bottom, 0px));
  z-index: 900;
  gap: var(--space-1);
}

.bottom-nav__btn {
  flex: 1 1 0;
  min-height: 56px;
  min-width: 56px;
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  background: transparent;
  color: var(--color-text);
  border: none;
  border-radius: var(--space-2);
  font-size: 0.75rem;
  font-weight: 600;
  font-family: var(--font-family-base);
  cursor: pointer;
  padding: var(--space-1) var(--space-2);
}

.bottom-nav__btn.is-active {
  color: var(--color-nia-blue);
}

.bottom-nav__btn:focus-visible {
  outline: 3px solid var(--color-nia-blue);
  outline-offset: 2px;
}

.bottom-nav__icon {
  width: 24px;
  height: 24px;
  display: inline-flex;
}
.bottom-nav__icon svg {
  width: 100%;
  height: 100%;
}

.bottom-nav__label {
  font-size: 0.75rem;
  line-height: 1;
}

/* When bottom nav is visible, give main some breathing room so the last
   row of content isn't hidden behind it. */
body:has(.bottom-nav) main {
  padding-bottom: 88px;
}

/* ------------------------------------------------------------
   Full-screen coach-mark (modules/fullscreen.js) — one-time, dismissible,
   points at the Full screen nav button. Never traps.
   ------------------------------------------------------------ */
.fs-hint {
  position: fixed;
  transform: translateX(-50%);
  z-index: 60;
  max-width: min(20rem, calc(100vw - 2rem));
  background: var(--color-nia-blue, #1f4fff);
  color: #fff;
  border-radius: var(--space-2, 0.5rem);
  padding: var(--space-3, 0.75rem) var(--space-3, 0.75rem);
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.28);
  font-size: 0.95rem;
  line-height: 1.35;
  display: flex;
  flex-direction: column;
  gap: var(--space-2, 0.5rem);
  animation: fs-hint-in 0.28s ease-out both;
}
@keyframes fs-hint-in {
  from { opacity: 0; transform: translateX(-50%) translateY(8px); }
  to   { opacity: 1; transform: translateX(-50%) translateY(0); }
}
.mode-reduced-motion .fs-hint { animation: none; }
.fs-hint__text { display: block; }
.fs-hint__close {
  align-self: flex-end;
  min-height: 44px;
  min-width: 88px;
  padding: 0 var(--space-3, 0.75rem);
  background: #fff;
  color: var(--color-nia-blue, #1f4fff);
  border: none;
  border-radius: var(--space-1, 0.25rem);
  font-weight: 700;
  font-family: var(--font-family-base, inherit);
  font-size: 0.9rem;
  cursor: pointer;
}
.fs-hint__close:focus-visible {
  outline: 3px solid #fff;
  outline-offset: 2px;
}
/* downward arrow pointing at the button below */
.fs-hint__arrow {
  position: absolute;
  bottom: -8px;
  width: 0;
  height: 0;
  border-left: 9px solid transparent;
  border-right: 9px solid transparent;
  border-top: 9px solid var(--color-nia-blue, #1f4fff);
  transform: translateX(-50%);
}

/* ------------------------------------------------------------
   Intro Screen (Phase 5)
   ------------------------------------------------------------ */
/* Title screen breaks out of main's padding + header chrome so it can be
   edge-to-edge / immersive. The Phase 1 <header> is empty (a placeholder
   that was never populated — bottom nav lives at body level instead) so
   it gets hidden too. Uses :has() — modern Safari/Chrome only; on older
   browsers, the title screen still works, just with main's padding. */
body:has(.title-screen) header[role="banner"] { display: none; }
body:has(.title-screen) main {
  padding: 0;
  max-width: none;
}

/* Title / loading / tap-to-start screen.
   Flex column. Brand lockup (Mae + Nia's Puzzles + Nia stacked tight)
   sits in the upper-middle, button at the bottom. Sizing is width-based
   (not height-based) so the lockup stays a consistent visual scale
   when only the viewport height changes. */
.title-screen {
  position: relative;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: space-between;
  padding: calc(env(safe-area-inset-top, 0px) + var(--space-4)) var(--space-3)
          calc(env(safe-area-inset-bottom, 0px) + var(--space-4));
  cursor: pointer;
  overflow: hidden;
  gap: var(--space-3);
}

/* The brand lockup — Mae stamp + Nia's Puzzles wordmark + Nia character.
   Tight stack via negative margins so they read as ONE unit. */
.title-lockup {
  position: relative;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 100%;
  max-width: 30rem;
}

/* Dedicated title-screen backdrop — soft cobalt-to-dawn sky with
   sparkles and cloud forms. Designed to read at full opacity behind
   the wordmarks; no blur or heavy overlay needed. */
.title-bg {
  position: absolute;
  inset: 0;
  background-image: url('/assets/images/backgrounds/title-bg.webp');
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
  z-index: 0;
}

/* Very light wash to take 5–10% of the saturation off the backdrop so
   the wordmarks pop. Keep it subtle — the backdrop is the whole point. */
.title-bg-overlay {
  position: absolute;
  inset: 0;
  background:
    linear-gradient(180deg,
      rgba(250, 247, 240, 0.05) 0%,
      rgba(250, 247, 240, 0.15) 100%);
  z-index: 1;
}

/* Mae Adventures — small parent-brand stamp at the top of the lockup. */
.title-wordmark-parent {
  width: 60%;
  max-width: 16rem;
  height: auto;
  object-fit: contain;
  filter: drop-shadow(0 2px 6px rgba(31, 79, 255, 0.18));
}

/* Nia's Puzzles — directly under Mae Adventures, the visual hero. */
.title-wordmark-main {
  width: 100%;
  max-width: 22rem;
  height: auto;
  object-fit: contain;
  filter: drop-shadow(0 6px 18px rgba(31, 79, 255, 0.28));
  margin-top: -1rem;  /* tight under Mae */
}

/* (Older `.title-wordmark-parent` / `.title-wordmark-main` definitions
   were here — replaced by the hero composition above.) */
/* Nia character — tight under Nia's Puzzles wordmark, completing the
   lockup. Width-based sizing so she keeps her presence when only
   viewport HEIGHT shrinks (she's portrait 0.5 aspect, so she's tall
   for her width — cap conservatively so the lockup fits on phone). */
.title-nia-sprite {
  width: 32%;
  max-width: 9rem;
  height: auto;
  object-fit: contain;
  pointer-events: none;
  filter: drop-shadow(0 10px 22px rgba(0, 0, 0, 0.28));
  margin-top: -0.5rem;
}

/* First-launch welcome overlay (lives on the MAP screen now, fires once
   per slot). Nia's waving torso slides in from the left, holds while
   the welcome voice line plays, then slides off. */
.map-wave-overlay {
  position: fixed;
  left: 0;
  bottom: calc(env(safe-area-inset-bottom, 0px) + 4.5rem);
  width: min(60%, 18rem);
  height: auto;
  object-fit: contain;
  z-index: 1000;
  pointer-events: none;
  filter: drop-shadow(0 10px 24px rgba(0, 0, 0, 0.35));
  transform: translateX(-110%);
  transition: transform 0.5s cubic-bezier(0.2, 0.8, 0.2, 1);
}

.map-wave-overlay.is-in {
  transform: translateX(0);
}

.map-wave-overlay.is-out {
  transform: translateX(-110%);
  transition-duration: 0.5s;
  transition-timing-function: cubic-bezier(0.4, 0, 0.6, 1);
}

html.mode-reduced-motion .map-wave-overlay {
  transition: none;
}

/* Tap-to-start CTA — grid row 3, bottom-center. */
.title-start-btn {
  position: relative;
  z-index: 3;
  grid-row: 3;
  border: 0;
  background: var(--color-nia-blue);
  color: #ffffff;
  border-radius: 999px;
  padding: var(--space-3) var(--space-5);
  font-size: 1.25rem;
  font-weight: 700;
  min-height: 56px;
  min-width: 12rem;
  cursor: pointer;
  box-shadow: 0 4px 16px rgba(31, 79, 255, 0.32);
  animation: title-pulse 2s ease-in-out infinite;
}

.title-start-btn:focus-visible {
  outline: 3px solid var(--color-nia-blue);
  outline-offset: 4px;
}

.title-start-prompt {
  letter-spacing: 0.01em;
}

@keyframes title-pulse {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.04); }
}

/* Reduced-motion mode strips the pulse (the existing global rule sets
   animation-duration: 0s, but make the intent explicit here too). */
html.mode-reduced-motion .title-start-btn {
  animation: none;
}

/* ------------------------------------------------------------
   Title screen — responsive layouts (tablet, desktop, landscape)
   ------------------------------------------------------------ */

/* Tablet portrait (≥ 720px wide, portrait): scale lockup up. */
@media (min-width: 720px) and (orientation: portrait) {
  .title-lockup { max-width: 36rem; }
  .title-wordmark-parent { width: 50%; max-width: 22rem; }
  .title-wordmark-main { max-width: 28rem; }
  .title-nia-sprite { max-width: 14rem; }
  .title-start-btn { font-size: 1.4rem; min-height: 64px; min-width: 14rem; }
}

/* Landscape: switch to two-column so the lockup + button fit any height
   without scroll. Left column = brand lockup (Mae + Nia's Puzzles + Nia),
   right column = CTA. Children scale via dvh-based max-height so the
   relative proportions stay intact regardless of viewport height. */
@media (orientation: landscape) {
  .title-screen {
    flex-direction: row;
    justify-content: center;
    align-items: center;
    gap: var(--space-5);
    padding: var(--space-3);
  }
  .title-lockup {
    width: auto;
    max-width: 60%;
  }
  .title-wordmark-parent { width: auto; max-width: none; max-height: 18dvh; }
  .title-wordmark-main    { width: auto; max-width: none; max-height: 30dvh; }
  .title-nia-sprite       { width: auto; max-width: none; max-height: 46dvh; }
  .title-start-btn {
    flex: 0 0 auto;
    font-size: 1.4rem;
    min-height: 64px;
    min-width: 14rem;
  }
}

/* Wide desktop landscape (≥ 1280px): pump button bigger. */
@media (orientation: landscape) and (min-width: 1280px) {
  .title-start-btn { font-size: 1.5rem; min-height: 72px; min-width: 16rem; }
}

/* ------------------------------------------------------------
   Cutscene Screen (Phase 5 story intro)
   Full-bleed background, Nia in lower-left, dialog box across the
   bottom. Whole screen is a tap target — advances to next scene.
   ------------------------------------------------------------ */
body:has(.cutscene-screen) header[role="banner"] { display: none; }
body:has(.cutscene-screen) main {
  padding: 0;
  max-width: none;
}

.cutscene-screen {
  position: relative;
  min-height: 100dvh;
  width: 100%;
  display: block;
  overflow: hidden;
  cursor: pointer;
  background: #1a1a2e;  /* fallback while bg image loads */
}

.cutscene-bg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  user-select: none;
  -webkit-user-drag: none;
  z-index: 0;
}

.cutscene-bg-overlay {
  position: absolute;
  inset: 0;
  background: linear-gradient(
    to bottom,
    rgba(0, 0, 0, 0) 50%,
    rgba(31, 79, 255, 0.05) 65%,
    rgba(31, 79, 255, 0.6) 100%
  );
  z-index: 1;
  pointer-events: none;
}

/* Cutscene Nia talking — bigger close-up portrait, bottom-anchored just
   above the dialog box so her face is clearly visible (was buried at
   bottom: 0 / 95dvh, dialog covered her entire face). She sits to the
   left, with her bottom edge resting on the top of the dialog area. */
.cutscene-nia {
  position: absolute;
  /* Sit just above the dialog box (dialog is ~9rem tall + bottom inset). */
  bottom: calc(env(safe-area-inset-bottom, 0px) + 9rem);
  left: 2%;
  width: 60%;
  max-width: 18rem;
  max-height: 60dvh;
  z-index: 3;
  pointer-events: none;
  filter: drop-shadow(0 8px 18px rgba(0, 0, 0, 0.45));
  animation: cutscene-nia-pop 0.5s cubic-bezier(0.34, 1.56, 0.64, 1) both;
}

.cutscene-nia--open {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  opacity: 0;  /* mouth closed by default — open frame hidden */
}

/* Mouth animation only runs while Nia is actually speaking. The
   .is-talking class is added/removed by cutscene.js based on the
   <audio> element's playing/ended events. */
.cutscene-nia.is-talking .cutscene-nia--open {
  animation: cutscene-nia-talk 0.36s steps(1) infinite both;
}

@keyframes cutscene-nia-pop {
  0%   { transform: translateY(20px); opacity: 0; }
  100% { transform: translateY(0);    opacity: 1; }
}

/* Two-state mouth animation — opacity ping-pongs the open frame in/out
   over the closed frame so the mouth appears to open and close. */
@keyframes cutscene-nia-talk {
  0%, 49%   { opacity: 1; }   /* mouth open */
  50%, 100% { opacity: 0; }   /* mouth closed showing through */
}

html.mode-reduced-motion .cutscene-nia { animation: none; }
html.mode-reduced-motion .cutscene-nia.is-talking .cutscene-nia--open { animation: none; }

.cutscene-dialog {
  position: absolute;
  left: 50%;
  bottom: calc(env(safe-area-inset-bottom, 0px) + var(--space-4));
  transform: translateX(-50%);
  width: min(calc(100% - 2rem), 36rem);
  background: rgba(250, 247, 240, 0.96);
  border: 2px solid var(--color-nia-blue);
  border-radius: var(--space-4);
  padding: var(--space-4) var(--space-4) var(--space-3);
  z-index: 4;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.25);
  animation: cutscene-dialog-rise 0.4s ease-out both;
}

@keyframes cutscene-dialog-rise {
  0%   { transform: translate(-50%, 16px); opacity: 0; }
  100% { transform: translate(-50%, 0);    opacity: 1; }
}

html.mode-reduced-motion .cutscene-dialog { animation: none; }

.cutscene-dialog__text {
  margin: 0 0 var(--space-2);
  font-size: 1.1rem;
  line-height: 1.5;
  color: var(--color-text);
  font-weight: 600;
}

.cutscene-tap-hint {
  display: block;
  text-align: right;
  font-size: 0.9rem;
  color: var(--color-nia-blue);
  font-weight: 700;
  animation: cutscene-tap-pulse 1.6s ease-in-out infinite;
}

@keyframes cutscene-tap-pulse {
  0%, 100% { opacity: 0.55; }
  50%      { opacity: 1; }
}

html.mode-reduced-motion .cutscene-tap-hint { animation: none; opacity: 1; }

/* Landscape adjustments: smaller Nia, dialog wider/lower. */
@media (orientation: landscape) {
  .cutscene-nia { bottom: calc(env(safe-area-inset-bottom, 0px) + 8rem); width: 22%; max-width: 8rem; }
  .cutscene-dialog__text { font-size: 1rem; }
}

@media (min-width: 720px) {
  .cutscene-dialog__text { font-size: 1.25rem; }
  .cutscene-tap-hint { font-size: 1rem; }
}

/* ------------------------------------------------------------
   Map Screen (Phase 5)
   ------------------------------------------------------------ */
.map-screen {
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.map-canvas {
  position: relative;
  aspect-ratio: 1024 / 1536;
  /* Pick the smaller of: 100% available, 32rem, or derived-from-height.
     This keeps the portrait aspect intact across all viewports. */
  width: min(100%, 32rem, calc((100dvh - 7rem) * 1024 / 1536));
  overflow: hidden;
  border-radius: var(--space-4);
  background: var(--color-badge-green-tint);
}

/* Tablet+ portrait: bigger map cap so it doesn't feel like a phone view. */
@media (min-width: 720px) and (orientation: portrait) {
  .map-canvas {
    width: min(100%, 40rem, calc((100dvh - 7rem) * 1024 / 1536));
  }
}

.map-bg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  user-select: none;
  -webkit-user-drag: none;
}

.map-nodes {
  position: absolute;
  inset: 0;
  pointer-events: none; /* let clicks pass through except on nodes */
}

.map-node {
  position: absolute;
  pointer-events: auto;
  width: 56px;
  height: 56px;
  min-width: 48px;
  min-height: 48px;
  border-radius: 50%;
  border: 3px solid #FFFFFF;
  background: var(--color-nia-blue);
  color: #FFFFFF;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 1.125rem;
  font-weight: 800;
  font-family: var(--font-family-base);
  cursor: pointer;
  transform: translate(-50%, -50%);
  padding: 0;
  box-shadow: 0 2px 8px rgba(0,0,0,0.35);
  transition-property: transform, box-shadow;
  transition-duration: 0.15s;
}

.map-node:focus-visible {
  outline: 3px solid #FFFFFF;
  outline-offset: 2px;
  box-shadow: 0 0 0 6px var(--color-nia-blue);
}

.map-node--unlocked:hover {
  transform: translate(-50%, -50%) scale(1.08);
}

.map-node--locked {
  background: #5A6478;
  opacity: 0.75;
  cursor: pointer; /* tappable to show 'Coming soon' */
}

.map-node__num {
  position: relative;
  z-index: 1;
}

.map-node__lock {
  position: absolute;
  width: 22px;
  height: 22px;
  bottom: -4px;
  right: -4px;
  background: var(--color-bg);
  color: var(--color-text);
  border-radius: 50%;
  padding: 2px;
}

.map-tooltip {
  position: fixed;
  background: var(--color-text);
  color: var(--color-bg);
  padding: var(--space-2) var(--space-3);
  border-radius: var(--space-2);
  font-size: 0.875rem;
  font-weight: 600;
  pointer-events: none;
  z-index: 1000;
  box-shadow: 0 4px 12px rgba(0,0,0,0.25);
  animation: tooltip-in 0.15s ease;
}

@keyframes tooltip-in {
  from { opacity: 0; transform: translate(-50%, -90%); }
  to   { opacity: 1; transform: translate(-50%, -100%); }
}

html.mode-reduced-motion .map-tooltip {
  animation: none;
}

/* ------------------------------------------------------------
   Journal Screen (Phase 5)
   ------------------------------------------------------------ */
.journal-screen {
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-4);
}

.journal-title {
  text-align: center;
  margin-bottom: 0;
}

.journal-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-6) var(--space-4);
  text-align: center;
}

.journal-empty__portrait {
  width: 120px;
  height: 120px;
  border-radius: 50%;
  object-fit: cover;
  background: var(--color-badge-blue-tint);
}

.journal-empty__text {
  font-size: 1.125rem;
  color: var(--color-text);
  max-width: 22rem;
  margin-bottom: 0;
}

.journal-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(96px, 1fr));
  gap: var(--space-3);
  width: 100%;
  max-width: 32rem;
  list-style: none;
  padding: 0;
}

.journal-cell {
  background: var(--color-badge-blue-tint);
  border: 2px solid var(--color-nia-blue);
  border-radius: var(--space-3);
  aspect-ratio: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 700;
  color: var(--color-text);
  padding: var(--space-2);
  text-align: center;
}

.journal-cell__label {
  font-size: 0.9375rem;
}

/* ------------------------------------------------------------
   Level Stub Screen (Phase 5; Phase 6 replaces level 1)
   ------------------------------------------------------------ */
.level-screen {
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-4);
  text-align: center;
  padding: var(--space-5) 0;
}

.level-title {
  margin-bottom: 0;
}

.level-stub {
  font-size: 1.125rem;
  opacity: 0.8;
  margin-bottom: 0;
}

.level-back-btn {
  margin-top: var(--space-4);
  background-color: transparent;
  color: var(--color-nia-blue);
  border: 2px solid var(--color-nia-blue);
  font-size: 1rem;
}

.level-back-btn:hover {
  background-color: var(--color-badge-blue-tint);
}

/* ------------------------------------------------------------
   Level 1 — Wake the Wordlings (Phase 6)
   ------------------------------------------------------------ */
.l1-screen {
  width: 100%;
  max-width: 28rem;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-4);
  padding: var(--space-3) var(--space-3) var(--space-4);
}

.l1-header {
  width: 100%;
  text-align: center;
}

.l1-title {
  font-size: 1.5rem;
  margin-bottom: var(--space-1);
}

.l1-progress {
  font-size: 0.9375rem;
  color: var(--color-text);
  opacity: 0.7;
  margin-bottom: 0;
}

.l1-content {
  width: 100%;
}

.l1-puzzle {
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-3);
}

/* Wordling figure — 2-frame sleep/wake cross-fade by opacity */
.l1-wordling {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2);
  margin: 0;
}

.l1-wordling__frames {
  position: relative;
  width: 160px;
  height: 160px;
  border-radius: 50%;
  background: var(--color-badge-green-tint);
  overflow: hidden;
  box-shadow: 0 4px 14px rgba(31, 79, 255, 0.18);
}

.l1-wordling__sleep,
.l1-wordling__wake {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  transition: opacity 0.5s ease;
}

.l1-puzzle[data-state="sleeping"] .l1-wordling__sleep { opacity: 1; }
.l1-puzzle[data-state="sleeping"] .l1-wordling__wake  { opacity: 0; }

.l1-puzzle[data-state="waking"]   .l1-wordling__sleep { opacity: 0; }
.l1-puzzle[data-state="waking"]   .l1-wordling__wake  { opacity: 1; }

.l1-puzzle[data-state="awake"]    .l1-wordling__sleep { opacity: 0; }
.l1-puzzle[data-state="awake"]    .l1-wordling__wake  { opacity: 1; }

/* In reduced-motion mode, the frame transition is instant (the global
   .mode-reduced-motion rule already zeroes transition-duration; this is
   a belt-and-braces). */
html.mode-reduced-motion .l1-wordling__sleep,
html.mode-reduced-motion .l1-wordling__wake {
  transition: none !important;
}

/* Small bounce on waking — disabled in reduced-motion */
.l1-puzzle[data-state="waking"] .l1-wordling__frames,
.l1-puzzle[data-state="awake"]  .l1-wordling__frames {
  animation: l1-wake-bounce 0.55s cubic-bezier(0.34, 1.56, 0.64, 1);
}
html.mode-reduced-motion .l1-wordling__frames {
  animation: none !important;
}
@keyframes l1-wake-bounce {
  0%   { transform: scale(0.92); }
  60%  { transform: scale(1.06); }
  100% { transform: scale(1); }
}

.l1-wordling__caption {
  font-size: 0.9375rem;
  color: var(--color-text);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  text-align: center;
}

.l1-wordling__name { font-weight: 700; }
.l1-wordling__state { font-size: 0.8125rem; opacity: 0.65; }

/* Legacy class kept for any future reuse — current puzzle DOM uses
   .l1-instruction (see below) which carries both the Wordling name and the
   phoneme chip. Removing this rule would break nothing in the current
   shipped DOM, but we keep it for forward compatibility. */
.l1-prompt {
  font-size: 1.125rem;
  color: var(--color-text);
  text-align: center;
  margin: 0;
  padding: 0 var(--space-2);
}

/* Per-puzzle instruction header — the visual answer to "what is this kid
   supposed to do?". Big, simple sentence + a colored phoneme chip so the
   target sound is unmistakable. */
.l1-instruction {
  width: 100%;
  text-align: center;
  /* Allow the chip + text to wrap naturally on narrow viewports; protect
     against overflow in big-text mode (1.16× root). */
  min-width: 0;
  overflow-wrap: anywhere;
  padding: 0 var(--space-2);
}
.l1-instruction__title {
  font-size: 1.25rem;
  font-weight: 800;
  color: var(--color-text);
  margin: 0 0 var(--space-1);
  line-height: 1.25;
}
.l1-instruction__name {
  color: var(--color-nia-blue);
}
.l1-instruction__sub {
  font-size: 1rem;
  color: var(--color-text);
  margin: 0;
  line-height: 1.4;
}
.l1-phoneme-chip {
  display: inline-block;
  background: var(--color-badge-yellow-tint);
  color: var(--color-text);
  border: 2px solid var(--color-badge-yellow);
  border-radius: 999px;
  padding: 2px var(--space-2);
  font-weight: 800;
  font-size: 1.0625rem;
  line-height: 1.1;
  /* Avoid the chip's middle border ever splitting across a wrap point. */
  white-space: nowrap;
  margin: 0 2px;
}

/* Tap-and-hold hint — persistent, understated caption under the option grid.
   Mutes the color slightly so it reads as a tip, not a competing instruction. */
.l1-hint {
  width: 100%;
  text-align: center;
  font-size: 0.9375rem;
  color: var(--color-text);
  opacity: 0.7;
  margin: 0;
  padding: 0 var(--space-2);
  min-width: 0;
  overflow-wrap: anywhere;
}
.l1-hint__icon {
  margin-right: 4px;
}

/* Wake announcement — toast-style banner that appears when a Wordling wakes.
   aria-live="polite" on the element makes SRs announce it; the visible
   styling gives sighted players the same sound→friend connection. */
.l1-wake-announce {
  width: 100%;
  text-align: center;
  font-size: 1.125rem;
  font-weight: 700;
  color: var(--color-badge-green);
  background: var(--color-badge-green-tint);
  border: 2px solid var(--color-badge-green);
  border-radius: var(--space-3);
  padding: var(--space-2) var(--space-3);
  margin: 0;
  min-width: 0;
  overflow-wrap: anywhere;
  animation: l1-wake-announce-pop 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.l1-wake-announce[hidden] { display: none; }
html.mode-reduced-motion .l1-wake-announce { animation: none !important; }
@keyframes l1-wake-announce-pop {
  0%   { transform: scale(0.85); opacity: 0; }
  100% { transform: scale(1);    opacity: 1; }
}

/* First-time tutorial overlay — focus-trapped dialog. Single big "Got it!"
   button (≥48×48). Reduced-motion mode skips the fade. */
.l1-tutorial-host {
  /* The host element is always in the DOM; the backdrop is conditionally
     rendered inside it. We don't need to position the host itself. */
}
.l1-tutorial-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(26, 36, 56, 0.55);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-4);
  z-index: 100;
  animation: l1-tutorial-fade-in 0.18s ease-out;
}
html.mode-reduced-motion .l1-tutorial-backdrop { animation: none !important; }
@keyframes l1-tutorial-fade-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}
.l1-tutorial {
  width: 100%;
  max-width: 22rem;
  background: var(--color-bg);
  color: var(--color-text);
  border: 3px solid var(--color-nia-blue);
  border-radius: var(--space-4);
  padding: var(--space-4);
  box-shadow: 0 12px 32px rgba(31, 79, 255, 0.25);
  /* Same defensive overflow handling as the puzzle area. */
  min-width: 0;
  overflow-wrap: anywhere;
}
.l1-tutorial__title {
  font-size: 1.375rem;
  color: var(--color-nia-blue);
  margin: 0 0 var(--space-3);
  text-align: center;
}
.l1-tutorial__list {
  list-style: none;
  padding: 0;
  margin: 0 0 var(--space-4);
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  font-size: 1rem;
  line-height: 1.4;
}
.l1-tutorial__list li {
  padding-left: var(--space-2);
}
.l1-tutorial__btn {
  display: block;
  width: 100%;
  min-height: 56px; /* well above the 48×48 touch-target floor */
  background: var(--color-nia-blue);
  color: #fff;
  border: none;
  border-radius: 999px;
  padding: var(--space-3) var(--space-5);
  font-size: 1.125rem;
  font-weight: 800;
  font-family: var(--font-family-base);
  cursor: pointer;
}
.l1-tutorial__btn:focus-visible {
  outline: 3px solid var(--color-text);
  outline-offset: 3px;
}
.l1-tutorial__btn:active {
  transform: scale(0.98);
}
html.mode-reduced-motion .l1-tutorial__btn:active {
  transform: none;
}

/* Option grid — 2x2 on phone, 4x1 in landscape. Each card ≥ 48×48. */
.l1-options {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--space-3);
  width: 100%;
  list-style: none;
  padding: 0;
}

.l1-option-row {
  position: relative;
  display: block;
  /* Allow grid track to shrink below row min-content so long words don't
     blow out the viewport (especially in big-text mode at 1.16× root). */
  min-width: 0;
}

/* Paired Answer + Listen buttons inside one visual card. */
.l1-option-pair {
  width: 100%;
  display: flex;
  flex-direction: row;
  align-items: stretch;
  border: 2.5px solid var(--color-nia-blue);
  border-radius: var(--space-3);
  background: var(--color-badge-blue-tint);
  overflow: hidden;
  /* Allow children to shrink below their min-content so long words
     don't blow out the viewport (especially in big-text mode). */
  min-width: 0;
}

.l1-option {
  flex: 1 1 auto;
  min-height: 72px;
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: flex-start;
  padding: var(--space-3) var(--space-4);
  background: transparent;
  color: var(--color-text);
  border: none;
  border-radius: 0;
  font-size: 1.25rem;
  font-weight: 700;
  font-family: var(--font-family-base);
  cursor: pointer;
  transition: transform 0.1s ease, background-color 0.1s ease;
  user-select: none;
  -webkit-user-select: none;
  /* Same: prevent min-content from forcing horizontal overflow. */
  min-width: 0;
  /* Defensive fallback if any future option string is unusually long. */
  overflow-wrap: anywhere;
}

.l1-option:hover {
  background: #D0DAFF;
}
.l1-option:active {
  transform: scale(0.97);
}
.l1-option:focus-visible {
  outline: 3px solid var(--color-text);
  outline-offset: -3px;
}
.l1-option[disabled] {
  opacity: 0.55;
  cursor: default;
}

/* Dedicated Listen button — visible speaker affordance on the right
   side of each option card. Plays the word without committing. */
.l1-option-listen {
  flex: 0 0 auto;
  min-width: 56px;
  min-height: 72px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  border-left: 2px solid var(--color-nia-blue);
  background: rgba(31, 79, 255, 0.12);
  color: var(--color-nia-blue);
  font-size: 1.5rem;
  cursor: pointer;
  padding: 0 var(--space-3);
  font-family: inherit;
  transition: transform 0.1s ease, background-color 0.1s ease;
  user-select: none;
  -webkit-user-select: none;
}
.l1-option-listen:hover {
  background: rgba(31, 79, 255, 0.22);
}
.l1-option-listen:active {
  transform: scale(0.95);
}
.l1-option-listen:focus-visible {
  outline: 3px solid var(--color-text);
  outline-offset: -3px;
}
.l1-option-listen[disabled] {
  opacity: 0.55;
  cursor: default;
}

.l1-scanner-host {
  width: 100%;
  display: flex;
  justify-content: center;
}
.l1-scanner-host[hidden] {
  display: none;
}
.l1-scanner-btn {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  background: var(--color-badge-yellow-tint);
  color: var(--color-text);
  border: 2px solid var(--color-badge-yellow);
  border-radius: 999px;
  padding: var(--space-3) var(--space-4);
  font-size: 1rem;
  font-weight: 700;
  min-height: 48px;
  cursor: pointer;
  font-family: var(--font-family-base);
}
.l1-scanner-btn:hover { background: #FBE69B; }
.l1-scanner-btn:focus-visible { outline: 3px solid var(--color-text); outline-offset: 2px; }
.l1-scanner-btn__icon { font-size: 1.25rem; }

.l1-feedback {
  width: 100%;
  text-align: center;
  font-size: 1rem;
  color: var(--color-text);
  min-height: 1.4em;
  margin: 0;
  opacity: 0.9;
}

/* Completion screen */
.l1-complete {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-4);
  text-align: center;
  padding: var(--space-3);
}
.l1-complete__title {
  font-size: 1.375rem;
  color: var(--color-nia-blue);
  margin: 0;
}
.l1-complete__grid {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: var(--space-2);
  width: 100%;
  list-style: none;
  padding: 0;
}
@media (max-width: 360px) {
  .l1-complete__grid { grid-template-columns: repeat(3, 1fr); }
}
.l1-complete__cell {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  font-size: 0.6875rem;
  font-weight: 700;
  color: var(--color-text);
  /* Same min-width:0 protection as .l1-option for big-text safety. */
  min-width: 0;
  overflow-wrap: anywhere;
}
.l1-complete__cell img {
  width: 100%;
  aspect-ratio: 1;
  object-fit: contain;
  background: var(--color-badge-green-tint);
  border-radius: 50%;
  padding: 4px;
}
.l1-complete__btn {
  background: var(--color-nia-blue);
  color: #fff;
  border: none;
  border-radius: 999px;
  padding: var(--space-3) var(--space-5);
  font-size: 1.125rem;
  font-weight: 700;
  min-height: 56px;
}

/* Map node completion check */
.map-node--complete {
  background: var(--color-badge-green);
  border-color: #FFFFFF;
}
.map-node__check {
  position: absolute;
  top: -6px;
  right: -6px;
  background: #FFFFFF;
  color: var(--color-badge-green);
  border-radius: 50%;
  width: 22px;
  height: 22px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-size: 0.875rem;
  font-weight: 800;
  border: 2px solid var(--color-badge-green);
  z-index: 2;
}

/* Journal cell with image */
.journal-cell {
  flex-direction: column;
  gap: var(--space-1);
}
.journal-cell__img {
  width: 64px;
  height: 64px;
  object-fit: contain;
  background: var(--color-badge-green-tint);
  border-radius: 50%;
  padding: 4px;
}

/* Landscape: lay options out as 4-up so all 4 are visible without scroll. */
@media (orientation: landscape) and (min-height: 360px) {
  .l1-options { grid-template-columns: repeat(2, 1fr); }
}

/* Tablet portrait+: a bit more breathing room */
@media (min-width: 720px) {
  .l1-screen { max-width: 32rem; }
  .l1-wordling__frames { width: 200px; height: 200px; }
}
