/* „Užburtas miškas" — iPad-Safari-first. One stage, letterboxed, never scrolls.
   Everything inside #frame is laid out in 1600×1000 scene units; #frame is
   scaled to fit the viewport, so no CSS below needs media queries.

   The palette is a night one: the forest at dusk, lit by the moon and by small
   warm things (the hut's window, the lantern, fireflies, Giliukas's acorn cap).
   Paper and ink stay warm so every clue the child has to READ keeps the daylight
   contrast a beginner needs. */

@font-face {
  font-family: 'Andika';
  src: url('/fonts/Andika-Regular.ttf') format('truetype');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Andika';
  src: url('/fonts/Andika-Bold.ttf') format('truetype');
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

:root {
  --night: #101A22;
  --moon: #C8D8C0;
  --mist: #9FB8AC;
  --amber: #F5C86E;
  --paper: #F6EBD7;
  --paper-2: #E4D3B6;
  --ink: #3A2A1C;
  --bark: #4A3626;
  --bark-dark: #32241A;
  --moss: #7A8C5A;
  --cap: #C0503C;
  --font: 'Andika', 'Segoe UI', 'Helvetica Neue', Arial, sans-serif;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  width: 100%;
  height: 100%;
  overflow: hidden;
  position: fixed;
  overscroll-behavior: none;
  background: #0B1114;
  font-family: var(--font);
  -webkit-text-size-adjust: 100%;
  -webkit-tap-highlight-color: transparent;
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  user-select: none;
  touch-action: manipulation;
}

#app { width: 100%; height: 100%; }

/* The letterbox is darker than any scene, so the stage reads as a window cut
   into the night rather than as a picture pasted on a background. */
#stage {
  position: fixed;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background:
    radial-gradient(ellipse at 50% 45%, #16232B00 0%, #070C0F 100%),
    #0B1114;
}

#frame {
  position: relative;
  width: 1600px;
  height: 1000px;
  flex: 0 0 auto;
  transform-origin: 50% 50%;
  overflow: hidden;
  border-radius: 6px;
  box-shadow: 0 0 90px rgba(0, 0, 0, 0.8);
}

#scene {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
}

#ui {
  position: absolute;
  inset: 0;
  pointer-events: none;
  font-family: var(--font);
  color: var(--ink);
}

button {
  font-family: var(--font);
  -webkit-appearance: none;
  appearance: none;
  cursor: pointer;
  touch-action: manipulation;
}

/* ---------- hotspots ---------- */

.hs { cursor: pointer; }
.hitrect { fill: transparent; }

#scene.pulsing .hs { animation: hspulse 1.05s ease-in-out 2; }
@keyframes hspulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.6; }
}

.shaking {
  transform-box: fill-box;
  transform-origin: center;
  animation: shake 0.6s ease-in-out;
}
@keyframes shake {
  10%, 90% { transform: translateX(-7px); }
  30%, 70% { transform: translateX(9px); }
  50% { transform: translateX(-9px); }
}

/* A tap that arrived while a puzzle is still pausing after a wrong answer. The
   prop twitches just enough to say „I felt that", and nothing happens. This is
   the ONLY thing a lockout ever shows: no spinner, no counter, no scold. */
.nudging {
  transform-box: fill-box;
  transform-origin: center;
  animation: nudge 0.4s ease-in-out;
}
@keyframes nudge {
  25% { transform: translateX(-3px); }
  60% { transform: translateX(3px); }
  85% { transform: translateX(-1.5px); }
}

/* a mushroom already dropped in the pot, a herb already tipped into the teapot
   — a ghost, so the child can see how far down the plank or the recipe they are */
.used { opacity: 0.32; transition: opacity 0.35s ease; }
/* …and once the soup is poured the ghosts go entirely */
.consumed { display: none; }

/* delight-only idle reactions */
.twitch { transform-box: fill-box; transform-origin: 50% 100%; animation: twitch 1.4s ease-in-out; }
@keyframes twitch { 20% { transform: rotate(-2.5deg); } 45% { transform: rotate(2deg); } 70% { transform: rotate(-1deg); } }

.sway { transform-box: fill-box; transform-origin: 50% 0%; animation: sway 1.5s ease-in-out; }
@keyframes sway { 25% { transform: rotate(3deg); } 60% { transform: rotate(-2.4deg); } 85% { transform: rotate(1deg); } }

.shine { animation: shine 1.5s ease-in-out; }
@keyframes shine { 40% { filter: brightness(1.35); } }

.glow { animation: glow 4.2s ease-in-out; }
@keyframes glow { 10%, 90% { filter: brightness(1.25); } }

/* Giliukas idles: breathing always, mouth only while he speaks. The engine puts
   `.guide` on the group it mounts him into and `.talking` on it while a bubble
   of his is open, so the art module only has to name three parts. */
.guide .g-body { transform-box: fill-box; transform-origin: 50% 100%; animation: breathe 4.6s ease-in-out infinite; }
@keyframes breathe { 50% { transform: scaleY(1.025) scaleX(0.99); } }

.guide .g-eyes { transform-box: fill-box; transform-origin: 50% 50%; animation: blink 6.2s ease-in-out infinite; }
@keyframes blink { 0%, 95%, 100% { transform: scaleY(1); } 97.5% { transform: scaleY(0.08); } }

.guide.talking .g-mouth { transform-box: fill-box; transform-origin: 50% 50%; animation: talk 0.34s ease-in-out infinite; }
@keyframes talk { 50% { transform: scaleY(2.1) scaleX(0.85); } }

/* ---------- speech bubbles ---------- */

/* Explicit stacking, so DOM insertion order never decides who gets a tap:
   hud 5 < game layers 10 < tap catcher 50 < bubble 51 < sheets 60 < title 70. */
.tapcatch {
  position: absolute;
  inset: 0;
  z-index: 50;
  pointer-events: auto;
}

.bubble {
  position: absolute;
  left: 0;
  top: 0;
  z-index: 51;
  /* Narrow on purpose. A bubble anchored on Giliukas in his corner gets pushed
     back into the middle of the glade by its own width, and a wide one lands on
     whatever just opened. Short lines also suit a reader who is still sounding
     words out. */
  max-width: 640px;
  padding: 26px 36px;
  background: var(--paper);
  color: var(--ink);
  font-size: 38px;
  line-height: 1.34;
  border-radius: 30px;
  box-shadow: 0 14px 34px rgba(0, 0, 0, 0.55);
  pointer-events: none;
}
/* The resting state is VISIBLE and the entrance animates away from hidden, so
   a browser that suppresses animations (reduced motion) still shows the text. */
.bubble.in { animation: bubblein 0.22s ease-out; }
@keyframes bubblein { from { opacity: 0; transform: translateY(10px); } }

.bubble::after {
  content: '';
  position: absolute;
  left: var(--tail-x, 50%);
  margin-left: -18px;
  border: 18px solid transparent;
}
.bubble.tail-down::after { top: 100%; border-top-color: var(--paper); border-bottom: 0; }
.bubble.tail-up::after { bottom: 100%; border-bottom-color: var(--paper); border-top: 0; }

/* Giliukas — plain warm paper, the voice the child hears most. Spelled out
   rather than left to the base rule so the three styles read as three. */
.bubble-guide { background: var(--paper); }
.bubble-guide.tail-down::after { border-top-color: var(--paper); }
.bubble-guide.tail-up::after { border-bottom-color: var(--paper); }

/* the carved and the creature voices: the gate, the stone head, Gurgis, Ūkė,
   Miegapelė. Darker paper inside a bark border — heavier than Giliukas, so who
   is speaking is legible before a word of it is read. */
.bubble-stone {
  background: var(--paper-2);
  border: 5px solid var(--bark);
  color: #3B2A19;
  font-weight: 700;
}
.bubble-stone.tail-down::after { border-top-color: var(--paper-2); }
.bubble-stone.tail-up::after { border-bottom-color: var(--paper-2); }

/* the forest itself, narrating. Nobody's mouth moves and nothing is answered
   here, so the bubble steps back a little. */
.bubble-quiet {
  background: rgba(246, 235, 215, 0.92);
  font-style: italic;
}
.bubble-quiet.tail-down::after { border-top-color: rgba(246, 235, 215, 0.92); }
.bubble-quiet.tail-up::after { border-bottom-color: rgba(246, 235, 215, 0.92); }

/* ---------- paper overlays & panels ---------- */

.sheetwrap {
  position: absolute;
  inset: 0;
  z-index: 60;
  background: rgba(6, 12, 14, 0.7);
  pointer-events: auto;
  display: flex;
  align-items: center;
  justify-content: center;
}

.paper, .panel {
  position: relative;
  background: var(--paper);
  color: var(--ink);
  border-radius: 12px;
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.6);
}
.paper.in, .panel.in { animation: sheetin 0.2s ease-out; }
@keyframes sheetin { from { opacity: 0; transform: scale(0.96); } }

.paper {
  width: 900px;
  max-width: 90%;
  max-height: 88%;
  padding: 64px 74px 46px;
  overflow-y: auto;
  background-image: linear-gradient(rgba(140, 110, 70, 0.06) 1px, transparent 1px);
  background-size: 100% 56px;
}
.paper.wide { width: 1180px; }

.paper-close {
  position: absolute;
  top: 12px;
  right: 14px;
  width: 68px;
  height: 68px;
  border: none;
  border-radius: 50%;
  background: var(--bark);
  color: var(--paper);
  font-size: 34px;
  line-height: 1;
}
.paper-close:active { background: var(--bark-dark); }

.paper-body p { font-size: 35px; line-height: 1.45; margin: 0 0 24px; }
.paper-body h2 { font-size: 46px; margin: 0 0 30px; text-align: center; letter-spacing: 1px; }
.paper-body .riddle { font-weight: 700; font-size: 39px; line-height: 1.4; }
.paper-body .sign { text-align: right; font-style: italic; margin-bottom: 0; }
.paper-body ol.recipe { margin: 0; padding-left: 54px; }
.paper-body ol.recipe li { font-size: 36px; line-height: 1.4; margin-bottom: 22px; }

.panel {
  padding: 56px 64px 48px;
  text-align: center;
  max-width: 94%;
}
.panel-note { font-size: 32px; margin: 0 0 18px; }
.panel-task { font-size: 38px; font-weight: 700; line-height: 1.4; margin: 0 0 24px; }

.panel-body { display: block; }
.panel-actions { display: flex; align-items: center; justify-content: center; gap: 26px; }

/* „Raštelis" — small on purpose. It reopens the plank or the recipe mid-puzzle;
   it must be findable without competing with the panel's own big button. */
.notebtn {
  border: 3px solid var(--bark);
  border-radius: 16px;
  background: var(--paper-2);
  color: var(--ink);
  font-size: 30px;
  font-weight: 700;
  padding: 14px 28px;
}
.notebtn:active { background: var(--bark); color: var(--paper); }

/* A panel answered from something drawn BEHIND it sits low and dims lightly, so
   the clue stays readable over its top edge while the child works. */
.dialpanel-wrap {
  align-items: flex-end;
  padding-bottom: 26px;
  background: rgba(6, 12, 14, 0.45);
}
/* Sitting low is not enough on its own: at the default panel padding the top
   edge lands across whatever it is meant to leave visible. The room it gives
   back comes off the top, and the panel carries its own „note" button instead of
   a long reminder line. */
.dialpanel { padding: 34px 64px 24px; }
.dialpanel .panel-note { margin-bottom: 14px; }
.dialpanel .panel-actions { margin-top: 18px; }
.dialpanel .dial { gap: 6px; }
.dials { display: flex; gap: 16px; justify-content: center; }
.dial { display: flex; flex-direction: column; align-items: center; gap: 10px; }
.dial-letter {
  width: 108px;
  height: 112px;
  line-height: 112px;
  background: var(--paper-2);
  border-radius: 14px;
  font-size: 66px;
  font-weight: 700;
  color: var(--ink);
}
.dialbtn {
  width: 108px;
  height: 74px;
  border: none;
  border-radius: 14px;
  background: var(--bark);
  color: var(--paper);
  font-size: 36px;
  line-height: 1;
}
.dialbtn:active { background: var(--bark-dark); }

.bigbutton {
  border: none;
  border-radius: 22px;
  background: var(--cap);
  color: var(--paper);
  font-size: 46px;
  font-weight: 700;
  padding: 22px 60px;
  box-shadow: 0 8px 0 rgba(0, 0, 0, 0.28);
}
.bigbutton:active { transform: translateY(4px); box-shadow: 0 4px 0 rgba(0, 0, 0, 0.28); }
.bigbutton.ghost { background: var(--moss); }

/* ---------- HUD ---------- */

.hud {
  position: absolute;
  z-index: 5;
  left: 28px;
  top: 22px;
  display: flex;
  align-items: center;
  gap: 24px;
  pointer-events: none;
  padding: 10px 20px 10px 14px;
  border-radius: 20px;
  background: rgba(8, 16, 20, 0.42);
}
.hud[hidden] { display: none; }
/* steps aside while anyone is speaking — see Engine.say() */
.hud { transition: opacity 0.18s ease; }
.hud.dimmed { opacity: 0; }

/* The four moon-stone recesses. An empty one is a socket cut in rock; a filled
   one holds a pale stone lit from inside, and the mark carved on it is a RUNE —
   never a letter. The whole point of the chain is that the gate's word is read
   off its slab, and a legible letter in the corner of the screen would hand it
   over for free. */
.hud-stones { display: flex; gap: 10px; }
.hud-stone svg { width: 62px; height: 62px; display: block; }
.hud-stone .s-socket { fill: rgba(4, 10, 12, 0.55); stroke: rgba(200, 216, 192, 0.3); stroke-width: 2; }
.hud-stone .s-stone { fill: rgba(200, 216, 192, 0.07); stroke: none; }
.hud-stone .s-rune { stroke: rgba(200, 216, 192, 0.22); }
.hud-stone.lit .s-socket { fill: #1A2A2C; stroke: rgba(220, 235, 215, 0.55); }
.hud-stone.lit .s-stone {
  fill: #DCEBD7;
  filter: drop-shadow(0 0 5px rgba(220, 235, 215, 0.85));
}
.hud-stone.lit .s-rune { stroke: #4C6058; }

/* the mushrooms already in Gurgis's pot — the colour is the whole point, so the
   cap takes its fill straight from the game */
.hud-shrooms { display: flex; gap: 8px; }
.hud-shroom svg { width: 40px; height: 40px; display: block; }
.hud-shroom .m-stem { fill: var(--paper-2); }
.hud-shroom .m-cap { stroke: rgba(8, 16, 20, 0.35); stroke-width: 1.5; }

.hud-items { display: flex; gap: 12px; }
.hud-item svg { width: 54px; height: 54px; display: block; }

/* the herbalist's glass jar, empty and then with a firefly in it */
.hud-jar .j-cork { fill: var(--bark); }
.hud-jar .j-glass { fill: rgba(200, 216, 192, 0.16); stroke: rgba(220, 235, 215, 0.6); stroke-width: 2; }
.hud-jar.glow .j-glass { fill: rgba(245, 200, 110, 0.16); stroke: var(--amber); }
.hud-jar .j-fly { fill: #FFF0BE; }
.hud-jar.glow { filter: drop-shadow(0 0 6px rgba(245, 200, 110, 0.7)); }

/* what else is in the child's hands, on the way to the owl */
.hud-snail .n-foot { fill: rgba(200, 216, 192, 0.5); }
.hud-snail .n-shell { fill: #B9793F; stroke: rgba(8, 16, 20, 0.3); stroke-width: 1.5; }
.hud-snail .n-spiral { stroke: #F0DFC0; }
.hud-snail .n-horn { stroke: rgba(200, 216, 192, 0.5); }
.hud-snail .n-eye { fill: #F0DFC0; }
.hud-acorn .a-nut { fill: #C79A5E; }
.hud-acorn .a-cap { fill: var(--cap); }
.hud-acorn .a-stem { stroke: var(--bark); }

/* ---------- prizes ---------- */
/* A collected thing is shown in the MIDDLE of the stage before it is filed in
   the corner — see Engine.prize(). The layer never takes taps: the game holds
   the forest still for the length of the ceremony, and the ceremony is short. */

.prizelayer { position: absolute; inset: 0; z-index: 62; pointer-events: none; }
.prize-scrim { position: absolute; inset: 0; background: rgba(4, 9, 12, 0.5); }

.prize-flyer { position: absolute; will-change: transform; }
.prize-art { position: absolute; inset: 0; }
/* the clone is a HUD slot, and its icon is sized for the corner */
.prize-art > div { width: 100%; height: 100%; }
.prize-art > div > svg { width: 100%; height: 100%; display: block; }

/* moonlight, the light the whole game is lit by */
.prize-glow {
  position: absolute;
  inset: -38%;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(214, 231, 208, 0.5) 0%, rgba(214, 231, 208, 0) 64%);
}
/* Motes, not stars — fireflies scattering off the thing. */
.prize-mote {
  position: absolute;
  left: 50%;
  top: 50%;
  border-radius: 50%;
  background: #FFF0BE;
  box-shadow: 0 0 14px rgba(245, 200, 110, 0.9);
}

/* The slot a prize is flying into stays empty until it lands, then takes it
   with a pop — the corner is where the thing ends up, not where it appears. */
.hud .awaiting { opacity: 0; }
.hud .landed { animation: prizeland 0.44s ease-out; }
@keyframes prizeland {
  0% { transform: scale(1.6); }
  55% { transform: scale(0.88); }
  100% { transform: scale(1); }
}

/* ---------- title & ending ---------- */

.gamelayer { position: absolute; inset: 0; z-index: 10; pointer-events: none; }
.gamelayer > * { pointer-events: auto; }

.titlescreen {
  position: absolute;
  inset: 0;
  z-index: 70;
  pointer-events: auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 24px;
  background: rgba(9, 20, 24, 0.82);
}
.title-h1 {
  margin: 0;
  font-size: 124px;
  font-weight: 700;
  color: var(--amber);
  text-shadow: 0 8px 26px rgba(0, 0, 0, 0.7);
  text-align: center;
}
.title-sub { margin: 0 0 26px; font-size: 46px; color: var(--moon); text-align: center; }
.title-buttons { display: flex; gap: 36px; }

.endingui {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-end;
  gap: 34px;
  padding-bottom: 64px;
}
/* The closing line lands on the busiest part of the picture beyond the gate —
   the path, the grass, the cottage windows — and dark brown on that is not a
   readable pair. It carries its own light instead: a moonlight halo that hugs
   the letters, so the line is legible over every colour under it while the
   picture stays whole. A scrim panel would read as a caption bar and wipe out
   the art it sits on. */
.ending-quiet {
  margin: 0;
  font-size: 44px;
  color: var(--ink);
  text-align: center;
  text-shadow:
    0 0 10px rgba(220, 235, 215, 0.98),
    0 0 20px rgba(220, 235, 215, 0.95),
    0 0 34px rgba(220, 235, 215, 0.82),
    0 0 54px rgba(220, 235, 215, 0.58);
}

/* ---------- P5 — the gate's four stone wheels ---------- */

/* Centred, unlike a panel with a clue behind it: nothing under this one is a
   hint, so there is nothing to keep visible. The wheels are cut stone rather
   than paper, so the lock reads as the thing set into the gate and not as
   another sheet to read.
   `.doorpanel` is kept as an alias of the same look — the two escape games
   share a lock shape, and a scene that names either class gets it. */
.gatepanel, .doorpanel { padding: 40px 64px 30px; }
/* The padding is what keeps the title clear of the ✕: the panel is sized by its
   widest child, so the title carries its own gutter on BOTH sides — the corner
   button gets its room and the line stays centred over the wheels. */
.gatepanel .panel-note, .doorpanel .panel-note {
  font-size: 34px;
  font-weight: 700;
  margin: 0 auto 22px;
  padding: 0 64px;
}
.gatepanel .dials, .doorpanel .dials { gap: 20px; }
.gatepanel .panel-actions, .doorpanel .panel-actions { margin-top: 24px; }
.gatepanel .dial-letter, .doorpanel .dial-letter {
  background: #B9C7BC;
  border: 4px solid #6C7C6E;
  line-height: 104px; /* the 112px box minus its own border */
  color: #22301F;
}

/* the moonlight that floods out of the ring when the gate opens */
.lightburst::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 4;
  pointer-events: none;
  opacity: 0;
  background: radial-gradient(circle at 50% 42%, rgba(228, 244, 226, 0.95), rgba(228, 244, 226, 0) 62%);
  animation: burst 1.4s ease-out;
}
@keyframes burst { 0% { opacity: 0; } 25% { opacity: 1; } 100% { opacity: 0; } }

@media (prefers-reduced-motion: reduce) {
  * { animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; }
}
