/* MoriPico — shared styling.
 *
 * SKELETON. This file carries the palette and the child-UX floor (tap target sizes, text
 * sizes, focus rings). It deliberately does NOT contain the design: the screens are
 * illustrated scenes, and painting them in CSS before the art exists would lock in the
 * wrong thing. See docs/VISUAL_REFERENCE.md.
 *
 * The tokens below are sampled from Episode 1, not invented.
 */

:root {
  /* Palette — see docs/VISUAL_REFERENCE.md */
  --canopy-green:   #2f5d3a;
  --moss-green:     #6f8f45;
  --leaf-light:     #a8c46a;
  --warm-gold:      #f0b755;
  --lantern-glow:   #ffd98a;
  --water-teal:     #4fd6d6;
  --water-deep:     #14707a;
  --pico-purple:    #a98bd6;
  --bloom-magenta:  #d96fa8;
  --wood-brown:     #6b4429;
  --wood-dark:      #3b2517;
  --cream:          #fff3dc;
  --night:          #17231f;

  /* The lighting is the signature of this world: warm points against cool shadow.
     A flat, evenly-lit UI will not read as MoriPico however correct the hues are. */
  --glow-warm: 0 0 32px rgba(255, 217, 138, 0.55);
  --glow-cool: 0 0 28px rgba(79, 214, 214, 0.45);

  /* Child-UX floor. These are minimums, not suggestions. */
  --tap-min: 64px;          /* nothing interactive smaller than this */
  --text-min: 1.25rem;      /* nothing readable smaller than this */
  --radius-soft: 24px;
}

* { box-sizing: border-box; }

html {
  height: 100%;
}

body {
  margin: 0;
  padding: 0;
  background: var(--night);
  color: var(--cream);
  font-family: system-ui, -apple-system, "Segoe UI", sans-serif;
  font-size: var(--text-min);

  /* The world should fill the screen — but "fill" must never mean "clip".
   *
   * `svh` is the SMALL viewport height: the height with the mobile browser's
   * toolbars SHOWN. Sizing to it guarantees nothing ever hides behind a toolbar
   * that slides back in. `100%` stays first as the fallback for older browsers.
   *
   * Deliberately NOT `100vh`: on iOS and Android `vh` resolves to the LARGE
   * viewport (toolbars hidden), so a "full height" screen sits partly underneath
   * the toolbar and its bottom edge is cut off.
   */
  min-height: 100%;
  min-height: 100svh;

  /* min-height, not height — and no `overflow: hidden` here.
   *
   * The previous global lock (`height: 100%; overflow: hidden`) clipped content
   * away with no way to reach it. Measured at 320x568 on /forest: "The Waterfall",
   * the only playable area, rendered at y=-6 and could not be tapped or scrolled to.
   * Overflow is now the page's normal business. A screen that genuinely must not
   * scroll opts in explicitly — see `.is-contained` below.
   */
  display: flex;
  flex-direction: column;
}

main#screen {
  position: relative;
  width: 100%;
  /* Fill the viewport, then keep growing if the content needs more room. */
  flex: 1 0 auto;
  display: flex;
  flex-direction: column;
}

/* --- Contained screens (opt-in) ------------------------------------------ */
/* A game must fit the viewport with no scrolling during play (brief section 14).
 * That is a promise an individual screen makes — never a global rule. The global
 * version is exactly what made the hub unreachable.
 *
 * `dvh` here rather than `svh`: a contained screen should track the visible area
 * as the toolbar slides, so it always fills precisely what the child can see. */
body.is-contained {
  height: 100vh;
  height: 100dvh;
  min-height: 0;
  overflow: hidden;
}

body.is-contained main#screen {
  flex: 1 1 auto;
  min-height: 0;
}

/* --- Interactive elements ------------------------------------------------ */
/* Big, obvious, and driven by tap. Nothing in this project may depend on :hover —
   the primary device is a tablet, where hover does not exist. */

button,
.big-button,
.hotspot {
  min-width: var(--tap-min);
  min-height: var(--tap-min);
  font-size: var(--text-min);
  font-family: inherit;
  cursor: pointer;
  border: none;
  border-radius: var(--radius-soft);
  touch-action: manipulation;          /* no 300ms delay, no double-tap zoom on controls */
}

/* Visible focus is an accessibility requirement, not decoration. */
:focus-visible {
  outline: 4px solid var(--lantern-glow);
  outline-offset: 3px;
}

.big-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 1rem 2.5rem;
  background: var(--warm-gold);
  color: var(--wood-dark);
  text-decoration: none;
  box-shadow: var(--glow-warm);
}

/* --- Sound controls ------------------------------------------------------ */
/* `fixed`, not `absolute`: now that a page is allowed to scroll, an absolutely
   positioned control would scroll off the top and become unreachable. Mute must
   always be one tap away. */

.sound-controls {
  position: fixed;
  top: max(1rem, env(safe-area-inset-top));
  right: max(1rem, env(safe-area-inset-right));
  z-index: 10;
  display: flex;
  gap: 0.75rem;
}

.sound-btn {
  width: var(--tap-min);
  height: var(--tap-min);
  background: rgba(0, 0, 0, 0.35);
  color: var(--cream);
  border-radius: 50%;
}

.sound-btn.is-off { opacity: 0.45; }

/* --- Back to the world --------------------------------------------------- */
/* Every screen a child can enter needs a way out, so this lives here rather than in one
   screen's stylesheet. It was in games.css, which the story screen does not load — the
   link rendered as bare 27px-tall text across the full width, under the tap floor.
   Positions against `main#screen`, which is `position: relative`. */
.back-to-forest {
  position: absolute;
  left: max(1rem, env(safe-area-inset-left));
  bottom: max(1rem, env(safe-area-inset-bottom));
  z-index: 10;
  display: inline-flex;
  align-items: center;
  min-height: var(--tap-min);
  padding: 0 1.5rem;
  border-radius: var(--radius-soft);
  background: rgba(0, 0, 0, 0.35);
  color: var(--cream);
  text-decoration: none;
}


/* --- Accessibility utility ----------------------------------------------- */
/* Present for screen readers and search engines, absent for the eye. Used where the
   artwork already carries the words — the Home title is painted into the picture, so
   rendering it a second time would clutter the scene and break "very little text". */

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* One screen's scene lives in its own file — forest.css for the hub, games.css for a
   game. main.css loads on every screen, so nothing screen-specific belongs in it.
   (home.css went with the title screen it styled; see app.py's `home` docstring.) */

/* --- Turn your phone ------------------------------------------------------
 * Shown only on an upright phone. See the comment on the markup in templates/_base.html
 * for why this is CSS-only and why the escape hatch exists.
 *
 * Hidden by default and switched ON by the media query, never the other way round: if a
 * browser cannot parse the query, the child gets the world (letterboxed but working)
 * rather than a full-screen overlay with no way past it.
 *
 * The query is deliberately three conditions:
 *   orientation: portrait   the actual problem
 *   max-width: 559.98px     the layout breakpoint used everywhere else, so a tablet held
 *                           upright — which is fine, and is the brief's priority device —
 *                           is never gated
 *   pointer: coarse         a narrow desktop window is not a phone and cannot be turned
 */

.rotate-gate { display: none; }

/* Off-screen but still focusable, so the escape hatch is reachable by keyboard and by a
 * screen reader. `display: none` would remove it from the tab order entirely. */
.rotate-gate-escape {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  opacity: 0;
  pointer-events: none;
}

@media (orientation: portrait) and (max-width: 559.98px) and (pointer: coarse) {
  .rotate-gate {
    display: grid;
    place-items: center;
    position: fixed;
    inset: 0;
    /* Above the sound controls and the light toggle, which are fixed at z-index 10. */
    z-index: 100;
    padding: 1.5rem;
    background: radial-gradient(circle at 50% 38%, #1d3327 0%, var(--night) 70%);
  }

  /* The whole card is the escape hatch — a child taps the picture, not a small target. */
  .rotate-gate-card {
    display: grid;
    place-items: center;
    gap: 0.75rem;
    padding: 1.5rem;
    cursor: pointer;
    text-align: center;
    color: var(--lantern-glow);
    -webkit-tap-highlight-color: transparent;
  }

  /* He leans the way the phone turns, a beat ahead of it, so the two read as one idea. */
  .rotate-gate-pico {
    width: min(42vw, 190px);
    /* His real proportions — static/images/characters/pico.webp is 461x542. */
    height: auto;
    filter: drop-shadow(0 10px 20px rgba(0, 0, 0, 0.5));
    animation: pico-lean 3.4s ease-in-out infinite;
  }

  @keyframes pico-lean {
    0%, 14%   { transform: rotate(0deg); }
    40%, 70%  { transform: rotate(-11deg); }
    100%      { transform: rotate(0deg); }
  }

  .rotate-gate-icon {
    width: min(38vw, 170px);
    height: auto;
    filter: drop-shadow(0 0 26px rgba(255, 200, 110, 0.4));
  }

  /* Only the phone turns; the arrow beside it stays put and reads as the instruction. */
  .rotate-gate-phone {
    transform-box: fill-box;
    transform-origin: center;
    animation: turn-phone 3.4s ease-in-out infinite;
  }

  .rotate-gate-words {
    font-family: Baskerville, "Palatino Linotype", "Book Antiqua", Palatino,
                 Georgia, "Times New Roman", serif;
    font-size: 1.5rem;
    letter-spacing: 0.06em;
    text-shadow: 0 2px 6px rgba(0, 0, 0, 0.8);
  }

  /* Tapped through: the world is upright and letterboxed, which is worse but never
     broken. It stays dismissed while the page lives; turning the phone hides the gate
     anyway, because the media query stops matching. */
  .rotate-gate-escape:checked ~ .rotate-gate { display: none; }

  /* A pause at each end, so it reads as "turn it" rather than a spinning object. */
  @keyframes turn-phone {
    0%, 20%   { transform: rotate(0deg); }
    45%, 75%  { transform: rotate(-90deg); }
    100%      { transform: rotate(0deg); }
  }
}

/* Respect the child's (or parent's) motion preference. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
}
