@font-face{font-family:Fredoka;font-style:normal;font-weight:400;font-display:swap;src:url('assets/fredoka-400.woff2') format('woff2')}
@font-face{font-family:Fredoka;font-style:normal;font-weight:600;font-display:swap;src:url('assets/fredoka-600.woff2') format('woff2')}

:root{
  --wood:#7a4a24;--wood-dark:#4d2c14;--cream:#f7e8c8;--paper:#fff6e2;--plum:#3b1f33;
  --amber:#ffc061;--amber-deep:#e8903a;--ink:#2a1622;--gold:#f2c141;--sage:#879a63;
  --radius:18px;--pad:clamp(6px,1.3vmin,14px);
  --safe-t:env(safe-area-inset-top,0px);--safe-r:env(safe-area-inset-right,0px);
  --safe-b:env(safe-area-inset-bottom,0px);--safe-l:env(safe-area-inset-left,0px);
}
*{box-sizing:border-box}
html,body{height:100%;margin:0}
body{
  font-family:Fredoka,system-ui,sans-serif;color:var(--cream);background:var(--plum);
  overflow:hidden;-webkit-text-size-adjust:100%;touch-action:manipulation;
}
button{font:inherit;color:inherit;border:0;background:none;cursor:pointer}
img{display:block;max-width:100%}
[hidden]{display:none!important}

.rune{position:fixed;left:calc(6px + var(--safe-l));bottom:calc(6px + var(--safe-b));width:42px;opacity:.85;pointer-events:none;z-index:80}
/* A dialog lives in the top layer, so its rune is pinned to the viewport corner
 * instead of scrolling inside the panel: the mark stays visible and clear of
 * the panel's own actions on every screen. */
dialog .rune{position:fixed;left:calc(6px + var(--safe-l));bottom:calc(6px + var(--safe-b));right:auto;top:auto;margin:0;width:38px;z-index:1}

/* -------------------------------------------------------------- opening */
/* A deliberate framed story illustration inside the Halloween veranda world:
 * the existing playfield background is the full-bleed surrounding world, and the
 * full story composition is shown ONCE inside a bounded wooden frame. Title sits
 * above, line + Play below, so nothing overlays the picture at any size. The art
 * aspect (1672x941 landscape / 941x1672 portrait) matches the 960x540 loop, so
 * the still and the video share the exact same rectangle with no seams and no
 * duplicated characters. */
#opening{
  position:fixed;inset:0;background:#3b1f33 center/cover no-repeat
    url('assets/bg-halloween-v4-landscape.webp');
  --story-ar:1.7768;--frame-matte:clamp(6px,1.2vmin,14px);
}
@media (orientation:portrait){
  #opening{background-image:url('assets/bg-halloween-v4-portrait.webp');--story-ar:0.5628}
}
.opening-stage{
  position:absolute;inset:0;z-index:1;
  display:grid;grid-template-rows:auto minmax(0,1fr) auto;
  gap:clamp(6px,1.4vh,14px);justify-items:center;align-items:center;
  padding:calc(var(--safe-t) + clamp(8px,1.6vh,16px)) calc(var(--safe-r) + clamp(10px,2vw,22px))
    calc(var(--safe-b) + clamp(8px,1.6vh,16px)) calc(var(--safe-l) + clamp(10px,2vw,22px));
}
.opening-frame{
  position:relative;align-self:center;justify-self:center;
  height:calc(100% - 2 * var(--frame-matte));min-height:0;
  max-width:calc(100% - 2 * var(--frame-matte));
  aspect-ratio:var(--story-ar);display:block;
}
/* The wooden ring is drawn OUTSIDE the picture rectangle, so it never squeezes
 * or crops the art and the inner rectangle keeps the exact story aspect. */
.opening-frame::before{
  content:'';position:absolute;inset:calc(-1 * var(--frame-matte));z-index:0;
  border-radius:clamp(14px,2.2vmin,26px);
  background:linear-gradient(#a8622c,#7a4a24);
  box-shadow:inset 0 2px 0 #ffffff2e,inset 0 -3px 0 #3a2210aa,0 16px 34px #1c0e1acc;
}
.opening-frame picture{position:relative;z-index:1;display:block;width:100%;height:100%;
  border-radius:clamp(9px,1.6vmin,16px);overflow:hidden;background:#2a1622}
.opening-frame img{display:block;width:100%;height:100%;object-fit:contain;object-position:center}
/* The opening loop fades in over the EXACT same rectangle as the still. It is
 * decoration for the landscape opening only; portrait and reduced motion keep
 * the still. */
.opening-frame .story-video{
  position:absolute;inset:0;z-index:2;width:100%;height:100%;object-fit:contain;object-position:center;
  background:transparent;opacity:0;transition:opacity .35s ease;pointer-events:none;
  border-radius:clamp(9px,1.6vmin,16px);
}
#opening.is-video .story-video{opacity:1}
@media (orientation:portrait){#opening.is-video .story-video{opacity:0}}
@media (prefers-reduced-motion: reduce){#opening .story-video{display:none}}
.opening-copy{
  width:min(94vw,760px);text-align:center;pointer-events:none;z-index:5;
}
.opening-copy h1{
  display:inline-block;margin:0;padding:10px 24px 13px;border:3px solid #d6ad65;
  border-radius:30px 24px 32px 25px;background:linear-gradient(145deg,#fffbedf5,#f8dfa8f5);
  color:#654023;font-size:clamp(1.35rem,3.4vw,2.5rem);line-height:1.1;font-weight:600;
  box-shadow:0 4px 0 #75502740,0 8px 22px #5b3a1f26;text-wrap:balance;
}
.opening-line{
  margin:10px auto 0;padding:6px 16px 8px;border-radius:999px;width:max-content;max-width:92vw;
  background:#2a1622b8;color:#ffe9bd;font-size:clamp(.85rem,2.2vw,1.15rem);
  text-shadow:0 2px 4px #2a162299;
}
.opening-bottom{
  display:flex;flex-direction:column;align-items:center;gap:clamp(6px,1.4vh,14px);
  width:min(92vw,520px);z-index:5;
}
#play{position:relative;width:clamp(104px,17vw,164px);aspect-ratio:1}
#play img{width:100%;height:100%;object-fit:contain;filter:drop-shadow(0 8px 14px #2a1622cc)}
.play-label{
  position:absolute;left:50%;bottom:2%;transform:translateX(-50%);
  padding:2px 14px 4px;border-radius:999px;background:#fff8e6e6;color:#654023;
  font-size:clamp(.85rem,2vw,1.1rem);font-weight:600;pointer-events:none;
}
#play:focus-visible{outline:4px solid #fff8e6;outline-offset:6px;border-radius:50%}
/* Short landscape phones (844x390, 1024x600): keep the framed story large by
 * trimming the title pill and the Play button instead of overlaying the art. */
@media (orientation:landscape) and (max-height:560px){
  .opening-copy h1{padding:6px 18px 8px;font-size:clamp(1.05rem,2.6vw,1.6rem)}
  .opening-line{margin-top:4px;padding:4px 12px 6px;font-size:clamp(.72rem,1.8vw,.95rem)}
  #play{width:clamp(82px,11vw,116px)}
}

/* ------------------------------------------------------------- playfield */
#playfield{
  position:fixed;inset:0;display:grid;
  grid-template-columns:auto minmax(0,1fr) auto;
  grid-template-rows:auto minmax(0,1fr) auto;
  gap:var(--pad);
  padding:calc(var(--pad) + var(--safe-t)) calc(var(--pad) + var(--safe-r)) calc(var(--pad) + var(--safe-b)) calc(var(--pad) + var(--safe-l));
  background:#3b1f33;
}
#bgWrap{position:absolute;inset:0;z-index:0}
#bgWrap img{width:100%;height:100%;object-fit:cover}
/* A friendly corner web, mirrored to the roomy bottom-right of the scene. It is
 * pure decoration: it never receives a pointer event, never moves and is hidden
 * from assistive tech. It sits under the puzzle, controls, tray and Ori so it
 * cannot cover any of them; short or portrait screens drop it entirely where the
 * background already keeps its own webs. */
.scene-web{
  position:absolute;right:0;bottom:0;width:clamp(96px,11vw,176px);height:auto;
  transform:scale(-1,-1);pointer-events:none;user-select:none;z-index:1;opacity:.92;
  filter:drop-shadow(0 6px 14px #10202f66);display:none;
}
@media (orientation:landscape) and (min-height:540px){.scene-web{display:block}}

/* Five wooden controls, always one unbroken row: Pause, Sound, Restart, Home, ? */
#controls{grid-area:1/1/2/2;justify-self:start;align-self:start;z-index:4;display:flex;gap:8px}
#controls button{flex:0 0 56px;width:56px;height:56px;min-width:56px;border-radius:50%;filter:drop-shadow(0 3px 2px #46301e66)}
#controls button img{width:100%;height:100%;object-fit:contain;pointer-events:none}
#controls button:active{transform:translateY(2px) scale(.96)}
#controls button:focus-visible,.wood:focus-visible,#check:focus-visible,#choices button:focus-visible,#guide:focus-visible,.slot:focus-visible,.panel-title:focus-visible{outline:3px solid #fff8e6;outline-offset:2px}

#hud{grid-area:1/2/2/4;justify-self:end;align-self:start;z-index:4;display:flex;align-items:center;justify-content:flex-end;flex-wrap:wrap;gap:6px 12px;min-width:0;max-width:calc(100vw - 2*var(--pad) - 320px)}
#levelName{margin:0;padding:6px 14px;border-radius:999px;background:#2a1622a6;font-size:clamp(.9rem,2.3vw,1.25rem);font-weight:600;white-space:nowrap;text-shadow:0 2px 6px #2a162288}
#pips{display:flex;align-items:center;justify-content:flex-end;flex-wrap:wrap;gap:4px 8px;max-width:100%;padding:6px;border-radius:14px;background:#3b1f33cc}
#pips ol{display:flex;gap:4px;margin:0;padding:0;list-style:none}
#pips li{position:relative;flex:0 0 auto;display:grid;place-items:center}
#pips li img{width:100%;height:100%;object-fit:contain;pointer-events:none}
#stagePips li{width:30px;height:30px}
#stagePips li[data-stage='todo'] img{filter:grayscale(.5) brightness(.85);opacity:.85}
#stagePips li[data-stage='now'] img{filter:drop-shadow(0 0 2px #fff8e6) drop-shadow(0 0 8px var(--amber))}
#stagePips li[data-stage='now']::after{content:'';position:absolute;inset:-3px;border:2px solid #fff8e6;border-radius:50%}
#stagePips li[data-stage='done'] img{filter:saturate(1.15)}
#stagePips li[data-stage='done']::after{content:'\2713';position:absolute;right:-3px;bottom:-4px;font-size:14px;font-weight:600;line-height:1;color:#9ce89a;text-shadow:0 1px 2px #2a1622}
#roundPips li{width:36px;height:36px}
#roundPips li[data-star='on'] img{filter:drop-shadow(0 0 5px var(--gold))}

/* ----------------------------------------------------------------- board */
#board{grid-area:2/1/3/4;display:flex;align-items:center;justify-content:center;gap:clamp(8px,1.6vw,22px);min-height:0;z-index:2}
.panel{
  position:relative;flex:1 1 0;max-width:min(46vw,620px);height:100%;max-height:100%;
  display:flex;flex-direction:column;min-width:0;min-height:0;
  /* The board's own alpha rounds the outer corners; let it show instead of
   * clipping the carved frame with a second, rounder radius. */
  border-radius:26px;overflow:visible;isolation:isolate;
}
/* Both boards are the same carved frame: the generated 1024px board is drawn
 * with a nine-slice border-image so its sculpted corners and silver webs keep
 * their true proportions instead of being stretched with the panel. The frame
 * width is the same value as the border, so the carved edge owns the outer
 * ~14-28px and the calm ivory linen fills the middle for the props. */
.panel{
  --frame:clamp(14px,2.4vmin,28px);
  padding:calc(var(--frame) + clamp(2px,.6vw,8px));
  background:#f0e7d5; /* quiet cream linen if the board art cannot load */
  box-shadow:0 14px 30px #1c0e1acc;
}
.panel::before{
  content:'';position:absolute;inset:0;pointer-events:none;z-index:-1;
  border:var(--frame) solid transparent;
  border-image-source:url('assets/board-halloween-v4.webp');
  border-image-slice:180 fill;border-image-width:var(--frame);border-image-repeat:round;
}
/* The carving has to read as richly sculpted on the roomy tablet, laptop and
 * portrait-tablet sizes, stay modest in short landscape windows and shrink on
 * the smallest phones so the tiny board keeps its play area. */
@media (min-width:800px) and (min-height:700px){
  .panel{--frame:39px;padding:calc(var(--frame) + clamp(4px,.8vw,10px))}
}
@media (max-width:480px){
  .panel{--frame:12px;padding:calc(var(--frame) + 2px)}
}
#picturePanel,#tablePanel{background:#f0e7d5}
#picturePanel .slots,#tablePanel .slots{background:transparent;border-radius:12px;box-shadow:none}
#tablePanel .slots{position:relative}
.panel-title{
  margin:0 0 clamp(4px,0.8vw,10px);padding:4px 10px 6px;border-radius:12px;align-self:flex-start;
  background:#2a1622a6;color:#ffe9bd;font-size:clamp(.72rem,1.6vw,1rem);font-weight:600;letter-spacing:.01em;
}
.slots{position:relative;flex:1 1 auto;min-height:0}
.slot-layer{position:absolute;inset:0}
.slot{
  position:absolute;left:0;top:0;transform:translate(-50%,-50%);
  width:var(--slot-px,40%);height:var(--slot-px,40%);display:grid;place-items:center;
  /* Bounded tracks: an auto track would grow to the bitmap's intrinsic size and
   * let a tall prop spill past its own slot. 1fr pins the track to the slot. */
  grid-template-columns:minmax(0,1fr);grid-template-rows:minmax(0,1fr);
}
.prop{width:100%;height:100%;min-width:0;min-height:0;max-width:100%;max-height:100%;
  object-fit:contain;pointer-events:none;
  filter:drop-shadow(0 7px 8px #2a162255);transform:rotate(var(--rot,0deg)) scale(var(--sc,1));transition:transform .18s ease-out,filter .18s ease-out}
.slot.filled{z-index:1}
/* The neutral empty spot: a soft cushion ring, never a silhouette of the answer.
 * On the light linen the dashed ring needs a darker, warmer ink to read. */
.slot.empty{
  border-radius:24px;background:radial-gradient(circle at 50% 45%,#0000001c,#00000000 70%);
  box-shadow:inset 0 0 14px #3a2a1022,0 0 0 1px #6b4f3326;
}
.empty-ring{
  width:74%;height:74%;border-radius:50%;border:4px dashed #6f4e2c;
  animation:spotPulse 2.6s ease-in-out infinite;
}
.slot.empty,.slot.filled{touch-action:none}
/* Honest media failure: the picture could not load, so the object keeps its
 * exact name instead of being replaced by a different prop. */
.prop-missing{
  width:auto;max-width:96%;padding:6px 10px;border-radius:12px;text-align:center;
  background:#fff6e2e8;color:#654023;font-size:clamp(.62rem,1.4vw,.86rem);font-weight:600;
  box-shadow:inset 0 0 0 3px #b8792f88;pointer-events:none;
}
.prop-fallback{opacity:.9}
#mediaNote{
  position:absolute;left:50%;top:calc(var(--safe-t) + 6px);transform:translateX(-50%);z-index:6;
  margin:0;padding:6px 14px;border-radius:999px;background:#2a1622dd;color:#ffe9bd;
  font-size:clamp(.7rem,1.8vw,.9rem);max-width:92vw;text-align:center;
}
.slot.over .empty-ring{border-color:#a56b13;background:#e7b0554d}
.slot.filled.over{filter:brightness(1.08)}
@keyframes spotPulse{50%{transform:scale(1.05);opacity:.75}}
#picturePanel .slot .prop{transform:none}

.prop.is-extra{animation:extraNudge .9s ease-out 2;filter:drop-shadow(0 0 12px var(--amber))}
@keyframes extraNudge{
  0%,100%{transform:translate(0,0) rotate(var(--rot,0deg)) scale(var(--sc,1))}
  30%{transform:translate(-7%,-3%) rotate(calc(var(--rot,0deg) - 5deg)) scale(var(--sc,1))}
  70%{transform:translate(7%,-1%) rotate(calc(var(--rot,0deg) + 5deg)) scale(var(--sc,1))}}
.prop.is-twin{filter:drop-shadow(0 0 0 #fff) drop-shadow(0 0 12px var(--amber)) brightness(1.08)}
.prop.is-hint{animation:hintGlow 1.9s ease-in-out infinite;filter:drop-shadow(0 0 14px var(--gold)) brightness(1.06)}
@keyframes hintGlow{50%{filter:drop-shadow(0 0 22px var(--gold)) brightness(1.16)}}
.prop.is-correct{animation:correctPop .9s cubic-bezier(.2,1.3,.4,1);filter:drop-shadow(0 0 16px var(--gold)) brightness(1.12)}
@keyframes correctPop{0%{transform:rotate(var(--rot,0deg)) scale(var(--sc,1))}
45%{transform:rotate(var(--rot,0deg)) scale(calc(var(--sc,1) * 1.18))}
100%{transform:rotate(var(--rot,0deg)) scale(var(--sc,1))}}
.slot.returning .prop{animation:returnTray .6s ease-in forwards}
@keyframes returnTray{to{opacity:0;transform:rotate(var(--rot,0deg)) scale(calc(var(--sc,1) * .6)) translateY(24%)}}

/* The hint itself is shown on the picture (a soft gold pulse on the prop that
 * has no twin on the table); this node only announces it to screen readers. */
#hint{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;
  clip-path:inset(50%);white-space:nowrap;border:0}

/* ------------------------------------------------------------------ tray */
#tray{
  grid-area:3/2/4/4;justify-self:center;align-self:end;z-index:3;
  display:flex;align-items:center;justify-content:center;gap:clamp(8px,1.4vw,18px);
  max-width:100%;padding:10px 14px;border-radius:24px;background:#2a1622a6;box-shadow:0 10px 24px #1c0e1acc;
}
#choices{display:flex;gap:clamp(8px,1.4vw,14px);margin:0;padding:0;list-style:none;min-width:0}
#choices button{
  width:clamp(72px,9vw,104px);height:clamp(72px,9vw,104px);min-width:72px;min-height:72px;
  padding:6px;border-radius:18px;background:#f7e8c814;box-shadow:inset 0 0 0 3px #b8792f88;
  display:grid;place-items:center;touch-action:none;
  /* Same bounded-track rule as the slots, so a tall bitmap always fits the
   * wooden tray button instead of pushing the button's content outside it. */
  grid-template-columns:minmax(0,1fr);grid-template-rows:minmax(0,1fr);overflow:hidden;
}
#choices img{width:100%;height:100%;min-width:0;min-height:0;max-width:100%;max-height:100%;
  object-fit:contain;pointer-events:none;filter:drop-shadow(0 5px 6px #2a162255)}
#choices button[aria-pressed='true']{background:#ffc06133;box-shadow:inset 0 0 0 3px var(--amber),0 0 18px #ffc06199}
#choices button:disabled{opacity:.6}
#check{width:clamp(72px,8vw,86px);height:clamp(72px,8vw,86px);min-width:72px;border-radius:50%;filter:drop-shadow(0 4px 6px #2a162299)}
#check img{width:100%;height:100%;max-width:100%;max-height:100%;object-fit:contain}
#check:disabled{opacity:.78}
#check.demo-ok{filter:drop-shadow(0 0 14px #8fe08a) drop-shadow(0 4px 6px #2a162299)}
#check.armed{animation:okReady 2s ease-in-out infinite}
@keyframes okReady{50%{filter:drop-shadow(0 0 14px var(--gold)) drop-shadow(0 4px 6px #2a162299)}}

/* ---------------------------------------------------------------- guide */
#guide{
  grid-area:3/1/4/2;justify-self:start;align-self:end;z-index:4;
  display:flex;align-items:center;gap:10px;max-width:min(38vw,340px);text-align:left;
  /* The rune owns the bottom-left corner in every state; keep the guide clear
   * of it instead of letting the two draw over each other. */
  padding-left:calc(50px + var(--safe-l));
}
/* The avatar slot is ready for the Kling toss clip later; until then it holds
 * the static Ori picture. It carries no card and no chroma fill of its own. */
#guideAvatar{position:relative;flex:0 0 auto;display:inline-flex;line-height:0}
#guideAvatar img{display:block;width:clamp(110px,11vw,150px);height:auto;
  filter:drop-shadow(0 6px 10px #2a1622cc);transition:opacity .12s linear}
/* The Kling toss clip sits exactly on the still, in the same 400x450 box, with
 * no card and no chroma fill: alpha is native, otherwise the poster stays. */
#guideVideo{position:absolute;inset:0;width:100%;height:100%;object-fit:contain;pointer-events:none;
  background:transparent;opacity:0;transition:opacity .12s linear}
#guideAvatar.is-playing img{opacity:0}
#guideAvatar.is-playing #guideVideo{opacity:1}
/* Only the spoken line wears the paper bubble - never the avatar slot. */
#guideText{position:relative;display:block;background:var(--paper);color:var(--ink);border-radius:22px 30px 30px 24px;padding:10px 16px 10px 14px;
  font-size:clamp(.76rem,1.6vw,1rem);line-height:1.3;box-shadow:0 8px 18px #1c0e1a99}
/* Organic contour: a soft rounded tongue grows out of the bubble's right side
 * toward Ori and overlaps it half-hidden, so the two silhouettes merge into one
 * continuous shape instead of a sharp triangle stuck on top. */
#guideText::after{
  content:'';position:absolute;right:-9px;top:50%;width:28px;height:28px;margin-top:-14px;z-index:-1;
  background:var(--paper);
  border-radius:64% 100% 100% 60% / 52% 100% 100% 48%;
  transform:rotate(9deg);
}
#guide:active #guideAvatar img{transform:scale(.96)}

/* -------------------------------------------------------------- dialogs */
/* The whole popup family belongs to the adventure: each dialog is a deliberate
 * carved board-halloween-v4 frame with a quiet ivory linen centre and real
 * bitmap action icons, never a flat app rectangle recoloured beige. */
dialog{
  --frame:clamp(12px,2.2vmin,26px);
  border:var(--frame) solid transparent;
  border-image-source:url('assets/board-halloween-v4.webp');
  border-image-slice:180 fill;border-image-width:var(--frame);border-image-repeat:round;
  border-radius:26px;padding:clamp(12px,2vmin,20px);
  max-width:min(94vw,660px);max-height:min(90vh,calc(100dvh - 150px));
  overflow:auto;color:var(--ink);background:#f0e7d5;
  box-shadow:0 18px 40px #1c0e1acc;font-size:clamp(.86rem,1.7vw,1rem);
}
dialog::backdrop{background:#2a1622cc}
dialog h2{margin:0;font-size:clamp(1.25rem,3.4vw,1.75rem);color:var(--wood-dark);text-shadow:0 1px 0 #fff8e6cc}
dialog p{margin:8px 0;line-height:1.4}
.dialog-head{display:flex;flex-direction:column;align-items:center;gap:2px;margin-bottom:6px;text-align:center}
.dialog-host{width:clamp(90px,15vh,140px);height:auto;object-fit:contain;filter:drop-shadow(0 8px 14px #2a1622aa)}
.dialog-line{margin:0;color:var(--wood-dark);font-weight:600}
.menu-label{margin:10px 0 6px;font-weight:600;color:var(--wood-dark);text-align:center}
/* A compact horizontal path of real level-pumpkin tokens with clear 1-5 badges. */
.level-menu{display:flex;flex-wrap:nowrap;gap:clamp(6px,1.4vw,12px);align-items:center;justify-content:center;padding:4px 2px;overflow-x:auto}
.level-token{position:relative;flex:0 0 auto;width:clamp(48px,7.4vh,62px);height:clamp(48px,7.4vh,62px);padding:4px;border-radius:16px;
  background:#7a4a241c;box-shadow:inset 0 0 0 2px #b8792f66;cursor:pointer}
.level-token img{display:block;width:100%;height:100%;object-fit:contain;pointer-events:none;filter:drop-shadow(0 3px 4px #2a162255)}
.level-badge{position:absolute;right:2px;bottom:2px;min-width:18px;height:18px;padding:0 4px;border-radius:9px;
  background:#fff6e2f2;color:#654023;font-size:.72rem;font-weight:600;line-height:18px;text-align:center;box-shadow:0 1px 0 #4d2c14}
.level-token.is-current{box-shadow:inset 0 0 0 3px var(--amber),0 0 14px #ffc06199}
.level-token.is-done::before{content:'\2713';position:absolute;left:2px;top:1px;font-size:.9rem;font-weight:600;color:#3f7a3a;text-shadow:0 1px 0 #fff8e6}
.level-token:disabled{filter:grayscale(.65) brightness(.92);opacity:.58;cursor:default}
.level-token:focus-visible{outline:3px solid #4d2c14;outline-offset:2px;box-shadow:0 0 0 6px #ffc06188}
.dialog-actions{display:flex;flex-wrap:wrap;gap:10px;margin-top:14px;align-items:center;justify-content:center}
/* Help must always offer a visible way back to the table: the close button
 * sits at the top of the dialog, reachable without scrolling on a short phone. */
#dlg-help .dialog-actions{margin:0 0 12px;justify-content:flex-start}
.wood{display:inline-flex;align-items:center;gap:8px;min-height:56px;padding:6px 18px 6px 10px;border-radius:16px;
  background:linear-gradient(#a8622c,#7a4a24);color:#fff6e2;font-weight:600;
  box-shadow:inset 0 2px 0 #ffffff33,0 3px 0 #4d2c14}
.wood img{width:34px;height:34px;object-fit:contain;pointer-events:none;filter:drop-shadow(0 3px 4px #2a1622aa)}
/* The dominant Continue action reads bigger than the secondary Replay/Home. */
.wood.primary{min-height:64px;padding:6px 22px 6px 12px;font-size:1.1rem;
  background:linear-gradient(#c47a34,#8a5220);
  box-shadow:inset 0 2px 0 #ffffff40,0 4px 0 #4d2c14,0 0 18px #ffc06159}
.wood.primary img{width:48px;height:48px}
.wood:active{transform:translateY(2px)}
/* Short landscape phones (844x390): a compact two-column Pause that shows the
 * whole Continue action AND all five level tokens without any scrolling, with
 * Ori beside the content and smaller heading/copy. */
@media (orientation:landscape) and (max-height:560px){
  #dlg-pause[open]{
    display:grid;grid-template-columns:auto minmax(0,1fr);
    grid-template-areas:"head label" "head tokens" "head actions";
    align-items:center;align-content:center;justify-items:start;
    column-gap:clamp(10px,2vw,20px);row-gap:6px;
    width:min(96vw,900px);max-height:calc(100dvh - 120px);
    padding:clamp(8px,1.6vmin,14px);
  }
  #dlg-pause .dialog-head{grid-area:head;flex-direction:row;align-items:center;gap:10px;margin:0;text-align:left}
  #dlg-pause .dialog-host{width:clamp(90px,26vh,124px)}
  #dlg-pause h2{font-size:clamp(1.05rem,3.4vh,1.4rem)}
  #dlg-pause .dialog-line{font-size:.84rem}
  #dlg-pause .menu-label{grid-area:label;margin:0;text-align:left;font-size:.82rem}
  #dlg-pause .level-menu{grid-area:tokens;justify-content:flex-start;padding:0}
  #dlg-pause .level-token{width:clamp(48px,13vh,58px);height:clamp(48px,13vh,58px)}
  #dlg-pause .dialog-actions{grid-area:actions;margin-top:0;justify-content:flex-start;gap:8px}
  #dlg-pause .wood{min-height:52px;padding:4px 14px 4px 8px}
  #dlg-pause .wood img{width:30px;height:30px}
  #dlg-pause .wood.primary{min-height:56px;padding:4px 16px 4px 8px;font-size:1rem}
  #dlg-pause .wood.primary img{width:38px;height:38px}
}
#helpSteps{margin:0;padding:0;list-style:none;display:flex;gap:14px;flex-wrap:wrap}
#helpSteps li{display:flex;align-items:center;gap:8px;min-width:170px;max-width:100%}
/* One logically complete miniature: the reference holds the exact dragged prop,
 * the drag step then sends that same prop INTO the empty spot, so the motion
 * matches the real round without more than three props overload. Miniatures are
 * large enough for a child to read and shrink only on the smallest phone. */
.step-art{width:auto;min-width:88px;max-width:190px;min-height:64px;flex:0 0 auto;display:flex;align-items:center;justify-content:center;gap:5px;padding:6px 10px;border-radius:12px;background:transparent;box-shadow:inset 0 0 0 2px #b8792f40}
.step-art img{width:42px;height:42px;object-fit:contain}
.step-picture img{width:38px;height:38px}
.step-arrow{color:var(--wood);font-size:1.9rem;font-weight:600;line-height:1}
.step-hole{width:38px;height:38px;flex:0 0 auto;border-radius:50%;border:3px dashed #b8792f}
.step-ok img{width:54px;height:54px}
.narration{display:flex;gap:10px;margin:14px 0 6px;flex-wrap:wrap;justify-content:center}
#helpText{font-size:.92rem;background:transparent;padding:8px 2px;color:#4a3320}
/* The reward dialog keeps its primary action initially visible: the canonical
 * high-five flexes to the remaining height (shrinking on short screens) while
 * the action row stays on screen; no page scroll, secondary prose may scroll. */
/* Scoped to [open] so the UA dialog:not([open]){display:none} still hides it;
 * overflow stays the base dialog's auto so secondary prose/controls can scroll. */
#dlg-reward[open]{display:flex;flex-direction:column;gap:6px}
#dlg-reward p{margin:0}
#dlg-reward .dialog-actions{margin-top:6px;flex:0 0 auto}
#rewardArt{flex:1 1 auto;min-height:44px;max-height:32vh;width:100%;object-fit:contain;border-radius:16px;
  background:transparent;filter:drop-shadow(0 8px 16px #2a162255)}
/* The finale is the strongest reward: a larger canonical high-five and title. */
#dlg-reward.is-finale #rewardArt{max-height:52vh}
#dlg-reward.is-finale #rewardTitle{font-size:clamp(1.5rem,4vw,2.2rem);color:#8a5220}

/* ------------------------------------------------------------ fx layer */
#fx-layer{position:fixed;inset:0;pointer-events:none;z-index:60;overflow:hidden}
.spark{position:absolute;width:12px;height:12px;border-radius:50%;
  background:radial-gradient(circle,#fff6d8,var(--gold) 60%,#f2c14100 72%);
  animation:sparkFly .72s ease-out forwards}
@keyframes sparkFly{from{opacity:0;transform:translate(0,0) scale(.5)}
  25%{opacity:1}
  to{opacity:0;transform:translate(var(--dx),var(--dy)) scale(1.15)}}

#hand{position:fixed;width:66px;pointer-events:none;transform-origin:70% 70%;filter:drop-shadow(0 4px 6px #2a1622aa);transition:left .35s ease,top .35s ease,transform .35s ease;z-index:130}
#game[data-state='paused'] #hand,#game[data-state='help'] #hand{display:none!important}
/* Pause and Help freeze every board animation in place - the prop pop/nudge,
 * the hint glow, the neutral ring, the ready OK and the success sparks - so no
 * motion keeps running behind the modal. Reduced motion and the authored
 * timings are untouched; only the play state changes. */
#game[data-state='paused'] .slot .prop,#game[data-state='paused'] .empty-ring,
#game[data-state='paused'] #check.armed,#game[data-state='paused'] #check.demo-ok,
#game[data-state='paused'] .spark,#game[data-state='paused'] #hand,
#game[data-state='help'] .slot .prop,#game[data-state='help'] .empty-ring,
#game[data-state='help'] #check.armed,#game[data-state='help'] #check.demo-ok,
#game[data-state='help'] .spark,#game[data-state='help'] #hand{animation-play-state:paused!important}

/* ----------------------------------------------------------- portrait */
@media (orientation:portrait){
  #playfield{grid-template-columns:minmax(0,1fr);grid-template-rows:auto auto minmax(0,1fr) auto auto;padding-top:calc(var(--pad) + var(--safe-t))}
  #controls{grid-area:1/1/2/2;justify-self:start}
  #hud{grid-area:2/1/3/2;justify-self:end;max-width:100%}
  #levelName{font-size:clamp(.8rem,3.2vw,1rem);white-space:normal;text-align:right}
  #stagePips li{width:26px;height:26px}
  #roundPips li{width:32px;height:32px}
  #board{grid-area:3/1/4/2;flex-direction:column;gap:8px}
  .panel{max-width:100%;width:100%;flex:1 1 0}
  .panel-title{font-size:clamp(.68rem,3vw,.9rem)}
  #guide{grid-area:4/1/5/2;justify-self:center;max-width:min(92vw,420px);padding-left:0}
  #guideText{font-size:clamp(.74rem,3.1vw,.95rem);padding:8px 12px}
  #guideAvatar img{width:clamp(82px,32vw,128px)}
  #tray{grid-area:5/1/6/2;padding:8px 10px 8px calc(46px + var(--safe-l))}
  #choices button{min-width:0;width:clamp(64px,20vw,92px);height:clamp(64px,20vw,92px)}
  #check{width:clamp(64px,17vw,80px);height:clamp(64px,17vw,80px);min-width:64px}
  #hint{top:calc(var(--safe-t) + 13%)}
}
@media (orientation:portrait) and (max-height:700px){
  .panel-title{padding:2px 8px 4px}
  #choices button{width:clamp(58px,16vw,78px);height:clamp(58px,16vw,78px)}
  #guideText{font-size:.72rem}
}
/* Short landscape windows (1024x600, 844x390, 1280x700) keep the tray compact. */
@media (orientation:landscape) and (max-height:640px){
  #controls button{flex-basis:56px;width:56px;height:56px}
  #roundPips li{width:32px;height:32px}
  #stagePips li{width:26px;height:26px}
  #choices button{width:clamp(64px,8vw,84px);height:clamp(64px,8vw,84px);min-width:64px;min-height:64px}
  #check{width:64px;height:64px;min-width:64px}
  #guide{max-width:min(34vw,300px)}
  #guideAvatar img{width:clamp(76px,9vw,104px)}
}
@media (max-width:480px){
  #rewardArt{max-height:150px}
  #rewardActions{display:grid;grid-template-columns:1fr 1fr;gap:8px}
  #rewardActions .wood{min-height:56px;padding:0 10px;font-size:.86rem;line-height:1.15}
}
@media (prefers-reduced-motion:reduce){
  *{animation-duration:.001ms!important;animation-iteration-count:1!important;transition-duration:.001ms!important}
  .empty-ring{animation:none}
  #guideVideo{display:none}
}
