/* shell/shell.css — shell chrome only. Skin palettes are scoped under
   [data-theme="<id>"] (never bare :root — README §6) so skins can't collide.
   Section/activity layout sizing comes from PA.layout() (the single config),
   never hardcoded here. */

/* Self-hosted Lexend (variable, weights 100–900) — offline-capable, no CDN. Without this the
   themes' "Lexend" fell through to "Comic Sans MS" on Apple devices. Two subsets cover English +
   the European-language accents (latin = U+0000–00FF incl. é/ñ/ü/ç; latin-ext for the rest). */
@font-face {
  font-family: 'Lexend'; font-style: normal; font-weight: 100 900; font-display: swap;
  src: url('fonts/lexend-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Lexend'; font-style: normal; font-weight: 100 900; font-display: swap;
  src: url('fonts/lexend-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

* { box-sizing: border-box; }
/* shared NON-color base tokens (skin-independent constants — safe in :root, README §6
   only forbids skin *palettes* here). */
:root { --ease-spring: cubic-bezier(.34, 1.56, .64, 1); }
/* shared Princess-Day SCENE palette — ONE source for the recurring royal-room colours, used in
   scene art via .pd-* classes (the hero's --pp-*/.pp-* pattern). Edit a token here, every scene
   updates; a skin could override these too. Per-room backgrounds stay each scene's own gradients. */
:root {
  --pd-gold: #ffd25a; --pd-gold-dk: #e0a51e; --pd-pink: #ff5d8f; --pd-pink-lt: #ff9ec4;
  --pd-wood: #caa46f; --pd-wood-dk: #a9764b; --pd-ink: #5e3c4e;
}
.pd-gold { fill: var(--pd-gold); } .pd-goldd { fill: var(--pd-gold-dk); }
.pd-pink { fill: var(--pd-pink); } .pd-pinkl { fill: var(--pd-pink-lt); }
.pd-wood { fill: var(--pd-wood); } .pd-woodd { fill: var(--pd-wood-dk); }
.pd-ink  { fill: var(--pd-ink); }
.pd-sgold { stroke: var(--pd-gold-dk); } .pd-sink { stroke: var(--pd-ink); } .pd-swood { stroke: var(--pd-wood-dk); }
/* shared wrong-answer shake (puzzles use .bad / .wrong { animation: shake … }) */
@keyframes shake { 0%,100% { transform: translateX(0); } 20%,60% { transform: translateX(-5px); } 40%,80% { transform: translateX(5px); } }
html, body { margin: 0; height: 100%; overflow: hidden; }
body {
  font: 16px/1.4 "Lexend", system-ui, -apple-system, sans-serif;
  background: var(--bg1, #fff0f7);
  color: var(--ink, #3a2f3d);
  -webkit-text-size-adjust: 100%;
  /* Little fingers must never highlight words/buttons — a stray selection can
     swallow a tap and make a control feel "dead." The -webkit- prefix +
     touch-callout (kills the long-press menu) are load-bearing on iOS/iPadOS. */
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
}

/* …but real text entry (grown-up magic-link email / code) must stay selectable. */
input, textarea {
  user-select: text;
  -webkit-user-select: text;
  -webkit-touch-callout: default;
}

/* ---- skin bridge ----
   The real palettes/textures live in themes/<id>.css (swapped into #pa-theme-css).
   Those files define each theme's tokens (--bg1/--bg2/--ink/--card/--pink/--gold/…) but
   not the shell's component vars, so we bridge them here, per active [data-theme]:
   - --accent  = the theme's primary accent (its --pink, except where a theme reads better
     on another token, e.g. twilight=gold, neobrutalism=purple).
   - --on-bg   = text that sits on the PAGE background (= --ink normally; twilight is a dark
     theme, so its page text is the theme's light --on-dark while cards keep dark --ink). */
:root                        { --accent: var(--pink, #ff6fae); --on-bg: var(--ink, #3a2f3d); }
[data-theme="twilight"]      { --accent: var(--gold, #ffd27a); --on-bg: var(--on-dark, #fdf4ff); }
[data-theme="neobrutalism"]  { --accent: var(--purple, #6637EE); }

/* ---- ambient skin decorations (the "floaty things"): a fixed layer BEHIND the section
   content; PA.decor.render() spawns per-skin petals/stars/fireflies/clouds (decor.js). ---- */
#pa-decor { position: fixed; inset: 0; overflow: hidden; pointer-events: none; z-index: 0; }
.pa-deco { position: absolute; will-change: transform, opacity; pointer-events: none; line-height: 1; }
.pa-petal   { top: -48px; animation: pa-fall linear infinite; }
.pa-cloud   { opacity: .9; animation: pa-drift linear infinite; }
.pa-star    { animation: pa-twinkle ease-in-out infinite; }
.pa-firefly { animation: pa-float ease-in-out infinite; filter: drop-shadow(0 0 4px #ffe27a); }
@keyframes pa-fall    { to { transform: translateY(115vh) rotate(380deg); } }
@keyframes pa-drift   { from { transform: translateX(-20vw); } to { transform: translateX(120vw); } }
@keyframes pa-twinkle { 0%,100% { opacity: .15; transform: scale(.7); } 50% { opacity: 1; transform: scale(1.2); } }
@keyframes pa-float   { 0%,100% { transform: translateY(0); } 50% { transform: translateY(-22px); } }
@media (prefers-reduced-motion: reduce) { .pa-deco { animation: none !important; } }

/* ---- persistent nav (slim dev bar; the kid UI replaces this in W3/UI) ---- */
#pa-nav {
  position: fixed; top: 0; left: 0; right: 0; height: 44px; z-index: 20;
  display: flex; gap: 6px; align-items: center; padding: 0 10px;
  background: color-mix(in srgb, var(--card) 86%, transparent);
  backdrop-filter: blur(8px); border-bottom: 1px solid rgba(0,0,0,.08);
}
#pa-nav button {
  font: inherit; font-size: 14px; padding: 6px 12px; border-radius: 999px;
  border: 1px solid transparent; background: transparent; color: var(--on-bg); cursor: pointer;
}
#pa-nav button.on { background: var(--accent); color: #fff; }
/* nothing in the nav shrinks or wraps: on a 390px phone, once the ⭐ / 💎 pills and the 💬 button are
   showing, flex squeezed "← Games" onto two lines (full-app QA 2026-10-16). Narrow phones get tighter spacing. */
#pa-nav > * { flex-shrink: 0; white-space: nowrap; }
/* every nav control gets a 44px-tall touch area (the pills themselves are 32–34px so the bar stays 44px):
   "← Games" is the most-tapped button in the app (QA 2026-10-16). Transparent, so nothing looks different. */
#pa-nav button, #pa-nav [role=button] { position: relative; }
#pa-nav button::after, #pa-nav [role=button]::after { content: ''; position: absolute; left: -2px; right: -2px; top: 50%; height: 44px; transform: translateY(-50%); }
@media (max-width: 420px) {
  #pa-nav { gap: 4px; padding: 0 6px; }
  #pa-nav button { padding: 6px 8px; }
  /* the pills carry inline margins/padding, hence !important */
  #pa-nav #pa-stars, #pa-nav #pa-gems { padding: 3px 7px !important; margin-left: 2px !important; gap: 3px !important; }
  #pa-nav #pa-stars { margin-left: auto !important; }
  /* with 3-digit stars and gems the bar was 394px wide — past the edge of a 390px phone. The 💎 pill opens the
     Dress-Up Studio too, so the 👗 shortcut steps aside while it shows. */
  #pa-nav:has(#pa-gems) button[data-go="closet"]:not(.on) { display: none; }   /* …except on the studio screen itself */
}
@media (max-width: 350px) {   /* 320px phones */
  #pa-nav button { padding: 6px 6px; font-size: 13px; }
  #pa-nav #pa-stars, #pa-nav #pa-gems { padding: 3px 5px !important; font-size: 13px; }
  #pa-nav [data-admin-comment] { width: 30px !important; height: 30px !important; margin-left: 2px !important; }
}

/* ---- the section mount fills the viewport below the nav (above the decor layer) ----
   #pa-section is the ONE full-width scroll container, so the scrollbar sits at the viewport
   edge — never mid-page. Section wraps (.cl-wrap / .setup-wrap / …) are centered with their own
   max-width, so if THEY scrolled, the bar would land at that inner edge; we neutralise their
   overflow here (higher specificity than their own class rule) and let #pa-section scroll. */
#pa-section { position: fixed; inset: 44px 0 0 0; overflow-y: auto; overflow-x: hidden; -webkit-overflow-scrolling: touch; z-index: 1; }
#pa-section > div { overflow-y: visible; }

/* ---- shared UI components (ONE definition; sections/overlays reuse these
   instead of each re-authoring buttons/inputs/cards in their own <style>) ---- */
.pa-btn {                                   /* outline pill button (sits on the page bg) */
  font: inherit; font-weight: 700; cursor: pointer;
  padding: 8px 18px; border-radius: 999px;
  border: 2px solid var(--accent); background: transparent; color: var(--on-bg);
}
.pa-btn--primary,                           /* filled accent button */
.pa-btn.is-on { background: var(--accent); border-color: var(--accent); color: #fff; }
.pa-btn:active { opacity: .85; }
.pa-btn--lg { font-size: clamp(16px, 4vw, 20px); padding: 12px 28px; }
.pa-btn--sm { font-weight: 600; font-size: 14px; padding: 6px 14px; }

.pa-input {                                 /* text input */
  width: 100%; box-sizing: border-box; font: inherit; font-size: 16px;
  padding: 8px 12px; border: 2px solid var(--accent); border-radius: 10px;
  background: transparent; color: var(--ink);
}

.pa-card {                                  /* tappable card */
  font: inherit; cursor: pointer; text-align: center; color: var(--ink);
  background: var(--card); border: 2px solid var(--accent); border-radius: 14px; padding: 16px 10px;
}
.pa-card:active { opacity: .85; }
.pa-card--cta {                             /* primary call-to-action card */
  background: var(--accent); color: #fff; border-color: var(--accent); font-weight: 700;
}

/* game-prompt display primitives (were re-authored inline in ~15 game files) */
/* colour inherits: the accent pink was 1.28:1 on the dark short-screen banner and ~2.6:1 on white (QA 2026-10-16) */
.pa-eq { font-size: clamp(32px, 9vw, 54px); font-weight: 900; color: inherit; letter-spacing: 2px; line-height: 1.1; }
.pa-col { display: flex; flex-direction: column; align-items: center; gap: 6px; }
.pa-row { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 6px; }
.pa-q { font-weight: 700; margin-top: 4px; }   /* the "What is …?" question line */

/* ---- full-bleed play area: practice games fill the whole section (no scene+hero stage).
   The scene+hero stage (.pa-stage, below) is reserved for STORY games. ---- */
.pa-play { position: absolute; inset: 0; overflow: hidden; }

/* ---- shared stage primitives (a section sizes regions via PA.layout) ---- */
.pa-stage { position: absolute; inset: 0; }
.pa-scene, .pa-game { position: absolute; overflow: hidden; }
/* The GAME is never clipped (the scene may crop; the game may not). A round taller than its panel —
   a phone in landscape, a long story line, two rows of big tiles — SCROLLS instead of slicing off its
   answers. Story QA 2026-10-14: in iPhone landscape every Fix the Silly beat hid its answer chips and
   letter bank below an overflow:hidden edge, with no way to reach them. */
.pa-game { overflow-x: hidden; overflow-y: auto; overscroll-behavior: contain; -webkit-overflow-scrolling: touch; }
/* The story's speech bubble lives INSIDE the scene region (narrative.js appends it to .pa-scene), so it
   can never sit on the game panel. On a phone in landscape the scene is a narrow strip beside the game;
   the bubble used to span the whole stage there and hide the question (and the stars to count, the
   swatch to match, the pattern to continue). Font scales with the SCENE width (--pa-scene-w, set by
   stage.js), which is the old 3.6vw everywhere the scene is full-width. */
.pa-bubble { position: absolute; left: 5%; right: 5%; top: 4%; margin: 0 auto; max-width: 680px;
  max-height: 92%; overflow-y: auto; box-sizing: border-box;
  background: rgba(255,255,255,.94); color: #27203a; border-radius: 16px; padding: 10px 16px;
  font-size: clamp(12px, calc(var(--pa-scene-w, 100vw) * .036), 22px); font-weight: 600; text-align: center;
  box-shadow: 0 6px 20px rgba(0,0,0,.18); z-index: 5; }
.pa-stage--side .pa-bubble { left: 4%; right: 4%; top: 3%; padding: 8px 10px; border-radius: 12px; }
/* In-scene puzzles (Princess Day's carousel, hopscotch, pancakes) draw their own prompt at ~20% down the
   room. On a short landscape screen the full-size bubble reached past that and hid it — on Hopscotch the
   hidden line was the word to rhyme with. Keep the bubble to one slim line at the very top there. */
@media (max-height: 500px) {
  .pa-stage--full .pa-bubble { top: 2%; padding: 4px 12px; font-size: 13px; line-height: 1.3; border-radius: 12px; max-width: 760px; max-height: 15%; }
}
.pa-scene svg, .pa-actor svg { display: block; width: 100%; height: 100%; }
/* The hero is scenery to the finger: taps pass through her to the puzzle. Her .pa-actor box sits at the
   scene's top-left (the pose wrapper inside is what moves), so without this it silently swallowed taps on
   whatever lay under that corner — Princess Day's carousel friends and hopscotch words could not be
   tapped on an iPhone held upright, so the day could not be finished (story QA 2026-10-14). */
.pa-actor { position: absolute; pointer-events: none; }
/* choreographed sets (story mode): an overlay layer for scene-coordinate actors
   (curtains/blanket/zzz/dim) + TWO nested hero wrappers — .pa-actor-pose carries the
   POSITION transform (translate/rotate/scale about the feet), .pa-actor-anim carries an
   idle ANIMATION (hop/bob/jump) so the two never fight over `transform`. The hero stays
   in her actor-safe band; only her pose changes in place. */
.pa-overlay { position: absolute; inset: 0; pointer-events: none; overflow: hidden; }
/* In-room puzzle stages (closet / breakfast / playground): the overlay IS the puzzle, so it draws in front
   of the hero — when a narrow screen brings her into view (stage.js keeps her in the crop) she stands
   behind the table, not over the plates. */
.pa-stage--full .pa-overlay { z-index: 2; }
.pa-front { position: absolute; inset: 0; pointer-events: none; overflow: hidden; }  /* over the hero */
.pa-actor-pose { position: absolute; inset: 0; transform-origin: 50% 100%; will-change: transform; }
.pa-actor-anim { position: absolute; inset: 0; transform-origin: 50% 100%; }
.pa-actor-pose svg { display: block; width: 100%; height: 100%; overflow: visible; }
.pa-anim-hop  { animation: paHop .9s cubic-bezier(.5,.05,.5,1) both; }
.pa-anim-bob  { animation: paBob .55s ease-in-out infinite; }
.pa-anim-jump { animation: paJump .8s cubic-bezier(.4,.05,.55,1) both; }
@keyframes paHop  { 0%{transform:translateY(0) rotate(0)} 45%{transform:translateY(-12%) rotate(-4deg)} 100%{transform:translateY(0) rotate(0)} }
@keyframes paBob  { 0%,100%{transform:translateY(0) rotate(1.4deg)} 50%{transform:translateY(-3%) rotate(-1.4deg)} }
@keyframes paJump { 0%{transform:translateY(0)} 38%{transform:translateY(-13%) rotate(3deg)} 70%{transform:translateY(0)} 84%{transform:translateY(-4%)} 100%{transform:translateY(0)} }
.pa-game { background: color-mix(in srgb, var(--card) 70%, transparent);
  border-radius: 18px; box-shadow: 0 8px 28px rgba(0,0,0,.14); }
