/* Royal Jelly Jam — Play mode chrome.
   Everything here is dormant until <body> gets the `play-mode` class. */

/* ============================================================
   TOPBAR PLATE COLORS — tweak everything from here by hand.
   ============================================================ */
:root {
  /* main plate gradient (top → bottom) */
  --pt-plate-top:        #305ab4;
  --pt-plate-bottom:     #234892;
  /* socket wells gradient (the dark inset holes) */
  --pt-sock-top:         #2c2360;
  --pt-sock-bottom:      #473c8a;
  /* ----- LEVEL hexagon (the badge under the level number) ----- */
  --pt-lvl-face-top:     #4a3f96;                 /* fill behind the number (top) */
  --pt-lvl-face-bottom:  #4a3f96;                 /* fill behind the number (bottom) */
  --pt-lvl-ring-top:     #2c2360;                 /* dark ring around the face (top) */
  --pt-lvl-ring-bottom:  #2c2360;                 /* dark ring around the face (bottom) */
  --pt-lvl-border:       #0e214e;                 /* outer outline of the hexagon */
  --pt-lvl-rim: #6758c7;  /* light inner rim on the face */
  /* plate rim / bevel gradient (top → mid → bottom) */
  --pt-rim-top:          #2e6ad1;
  --pt-rim-mid:          #2a62c4;
  --pt-rim-bottom:       #122a63;
  /* outlines */
  --pt-frame-edge:       #182869;                 /* thin outer edge of the plate */
  --pt-socket-stroke:    #0e214e;                 /* dark outline of sockets + hexagon */
  --pt-socket-highlight: rgba(255,255,255,0.13);  /* inner light rim of sockets */

  /* exit (✕) button */
  --pt-exit-top:         #ff5a5a;
  --pt-exit-bottom:      #ec1c2e;
  --pt-exit-shadow:      #b31221;
  /* replay (⟳) button */
  --pt-replay-top:       #4fd0ff;
  --pt-replay-bottom:    #2aa6e8;
  --pt-replay-shadow:    #1d7bb0;
  --pt-icon:             #fff;                     /* button glyph color */

  /* timer pill (normal) */
  --pt-timer-top:        #ffe07a;
  --pt-timer-bottom:     #f3ae2b;
  --pt-timer-shadow:     #c8860f;
  --pt-timer-cap:        #8a5a00;                  /* "TIME" caption */
  --pt-timer-val:        #5a3b00;                  /* timer digits */
  /* timer pill (low-time warning) */
  --pt-timer-warn-top:    #ff8a7a;
  --pt-timer-warn-bottom: #ef4f4f;
  --pt-timer-warn-shadow: #b32d2d;

  /* LEVEL label */
  --pt-lvl-cap:          #cdbfff;
  --pt-lvl-num:          #fff;
  /* LEFT (remaining moves) label */
  --pt-moves-cap:        #b9aef0;
  --pt-moves-num:        #fff;
}

/* wire the SVG gradient stops + outlines to the vars above */
#ptPlate stop:nth-child(1) { stop-color: var(--pt-plate-top); }
#ptPlate stop:nth-child(2) { stop-color: var(--pt-plate-bottom); }
#ptSock  stop:nth-child(1) { stop-color: var(--pt-sock-top); }
#ptSock  stop:nth-child(2) { stop-color: var(--pt-sock-bottom); }
#ptFace    stop:nth-child(1) { stop-color: var(--pt-lvl-face-top); }
#ptFace    stop:nth-child(2) { stop-color: var(--pt-lvl-face-bottom); }
#ptHexRing stop:nth-child(1) { stop-color: var(--pt-lvl-ring-top); }
#ptHexRing stop:nth-child(2) { stop-color: var(--pt-lvl-ring-bottom); }
#ptRim   stop:nth-child(1) { stop-color: var(--pt-rim-top); }
#ptRim   stop:nth-child(2) { stop-color: var(--pt-rim-mid); }
#ptRim   stop:nth-child(3) { stop-color: var(--pt-rim-bottom); }
.pt-frame-edge { stroke: var(--pt-frame-edge); }
.pt-socket     { stroke: var(--pt-socket-stroke); }
.pt-socket-hi  { stroke: var(--pt-socket-highlight); }
.pt-hex-ring   { stroke: var(--pt-lvl-border); }
.pt-hex-rim    { stroke: var(--pt-lvl-rim); }

/* ---- "Play" entry button (lives in the debug topbar) ---- */
.play-enter-btn {
  background: linear-gradient(180deg, #2fdd6d, #12aa4c);
  color: #06210f;
  border: none;
  border-radius: 10px;
  padding: 6px 16px;
  font-size: 14px;
  font-weight: 700;
  cursor: pointer;
  box-shadow: 0 3px 0 #0b7d35;
}
.play-enter-btn:active { transform: translateY(2px); box-shadow: 0 1px 0 #0b7d35; }

/* ---- play chrome is hidden in debug mode ---- */
.play-top, .play-bottom { display: none; }

/* ---- debug progress panel (hidden in play mode) ---- */
.play-admin {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 14px;
  margin: 2px auto 6px;
  padding: 8px 14px;
  background: var(--board-bg);
  border: 1px solid var(--cell-border);
  border-radius: 12px;
  color: #d7ddef;
  font-size: 13px;
}
body.play-mode .play-admin { display: none !important; }
.pa-title { font-weight: 700; color: #9aa3bf; }
.pa-field { display: inline-flex; align-items: center; gap: 6px; }
.pa-num {
  width: 56px;
  background: var(--cell-bg);
  color: #f0f2f8;
  border: 1px solid var(--cell-border);
  border-radius: 7px;
  padding: 4px 6px;
  font-size: 13px;
}
.pa-num-wide { width: 72px; }
.pa-boosters { display: inline-flex; gap: 8px; }
.pa-bstr { display: inline-flex; align-items: center; gap: 4px; }
.pa-bstr-ico { font-size: 16px; }
.pa-bstr .pa-num { width: 46px; }
.pa-btn {
  background: #3a4566;
  color: #eef1f8;
  border: none;
  border-radius: 8px;
  padding: 6px 12px;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
}
.pa-btn:hover { background: #46527a; }
.pa-reset { background: #7a2f2f; }
.pa-reset:hover { background: #983a3a; }

/* ---- when in play mode, suppress debug chrome ---- */
body.play-mode .controls,
body.play-mode .topbar h1,
body.play-mode .booster-bar,
body.play-mode .hint { display: none !important; }

body.play-mode .topbar {
  justify-content: center;
  padding: 0;
  min-height: 0;
}

/* Lock the play screen to the viewport. Without a DEFINITE app height the flex
   column is content-sized, so a tall board stretches it past the screen — the
   booster bar gets pushed below the fold and a page scrollbar appears. Pinning
   the app to 100% (and clipping body) bounds the flex stage so its
   min-height:0/overflow:hidden actually take effect and fitBoard() shrinks the
   board into whatever vertical space the HUD and booster bar leave. */
body.play-mode { overflow: hidden; }

/* ====================================================================
   Play-mode backdrop — vector/Disney castle hall.
   Visible from the pre-match window onward. `cover` + centred position
   keeps the symmetrical composition framed in BOTH portrait and
   landscape (the moon/door/carpet axis stays centred; only the flanking
   knights crop). Swap the url to backgrounds/castle_hall_a.webp for the
   brighter variant. The dark gradient on top keeps UI/text readable.
   ==================================================================== */
body.play-mode {
  background-image:
    linear-gradient(rgba(10, 14, 26, 0.34), rgba(10, 14, 26, 0.52)),
    url("backgrounds/castle_hall_b.webp");
  background-size: cover;
  background-position: center center;
  background-repeat: no-repeat;
  background-attachment: fixed;
}
body.play-mode .app {
  height: 100%;
  min-height: 0;
}

/* ====================================================================
   Top HUD bar — unified SVG frame with carved sockets
   Layout: [LEVEL hex] .. [TIME] .. [LEFT] .. [✕][replay]
   The frame (plate + sockets) is one SVG; values & buttons overlay it.
   ==================================================================== */
body.play-mode .play-top {
  display: block;
  position: relative;
  width: 100%;
  max-width: 520px;
  margin: 6px auto 10px;
  padding: 0;
}
.pt-frame { display: block; width: 100%; height: auto; filter: drop-shadow(0 6px 5px rgba(0, 0, 0, 0.224)); }
.pt-frame-m { display: none; }   /* зеркальная правая грань гекса — только landscape */

/* overlays sit on top of the frame, centred on their socket */
.pt-ov { position: absolute; top: 50%; transform: translate(-50%, -50%); }

/* level (in the hexagon) */
.pt-lvl { left: 11.48%; display: flex; flex-direction: column; align-items: center; justify-content: center; line-height: 1; pointer-events: none; }
.pt-lvl-cap { font-size: 10px; font-weight: 800; letter-spacing: 1px; color: var(--pt-lvl-cap); margin-bottom: 3px; text-shadow: 0 1px 1px rgba(0,0,0,0.5); }
.pt-lvl-num { font-size: 28px; font-weight: 900; color: var(--pt-lvl-num); text-shadow: 0 2px 0 rgba(0,0,0,0.5); transition: opacity .35s ease; }

/* ====================================================================
   КК (Королевский Кондитер) в гексе топбара — MGM-выглядывание + заставка.
   Геометрия гекса ИДЕНТИЧНА level-complete топбару (socket-контур
   x 5.77..106.23, y 10.6..121.4), viewBox тут -6 -4 540 140 → пересчёт
   только контейнеров под ширину 540. Техника: MGM_PEEK_TECHNIQUE.md.
   ==================================================================== */

/* --- Заставка: тьма внутри гекса + белые чёрточки летят вверх --------- */
/* Контейнер = bbox грани гекса (SVG x12.7..99.3 y18.31..113.69), клип по
   шестиугольнику грани. */
/* Всегда отрисован (display:block), но прозрачен в покое — чтобы opacity-
   переходы фона реально анимировались (из display:none плавного fade не
   выходит). Клип по шестиугольнику грани, поверх сиреневой грани рамки. */
.pt-hexfx { position: absolute; left: 3.463%; top: 15.936%; width: 16.037%; height: 68.129%;
  overflow: hidden; pointer-events: none; z-index: 2;
  clip-path: polygon(50% 0%,100% 28.63%,100% 71.37%,50% 100%,0% 71.37%,0% 28.63%); }
/* Чёрный слой: fade-in (сиреневый→чёрный) на входе, fade-out (чёрный→сиреневый)
   когда появляется КК. В покое и под КК прозрачен → видна сиреневая грань. */
.pt-hexfx-dark { position: absolute; inset: 0; opacity: 0; transition: opacity .55s ease;
  background: radial-gradient(circle at 50% 45%, #0b0b16 0%, #030308 82%); }
.pt-hexfx-streaks { position: absolute; inset: 0; opacity: 0; transition: opacity .35s ease; }
.pt-streak { position: absolute; top: 0; width: 2px; height: 22%;
  border-radius: 2px; background: linear-gradient(to top, rgba(255,255,255,0) 0%,
    rgba(255,255,255,0.95) 55%, rgba(255,255,255,0) 100%);
  transform: translateY(130%) scaleY(1); will-change: transform, opacity; }
@keyframes ptStreakUp {
  0%   { transform: translateY(150%) scaleY(0.7); opacity: 0; }
  12%  { opacity: 1; }
  70%  { opacity: 1; }
  100% { transform: translateY(-260%) scaleY(3.4); opacity: 0; }
}
/* armed = фаза затемнения: чёрный проявляется, чёрточки бегут. КК ещё нет. */
.play-top.pt-kk-armed .pt-hexfx-dark { opacity: 1; }
.play-top.pt-kk-armed .pt-hexfx-streaks { opacity: 1; }
.play-top.pt-kk-armed .pt-streak { animation: ptStreakUp var(--dur,0.5s) cubic-bezier(.55,0,.9,.35) var(--delay,0s) infinite; }
/* on = КК появляется: чёрный гаснет обратно в сиреневый (правила opacity:1
   для dark тут НЕТ → transition ведёт к 0), чёрточки гаснут. */

/* --- MGM: видео-персонаж поверх рамки -------------------------------- */
/* Контейнер = bbox гнезда, вытянутый вверх (SVG x5.76..114, y-6..122). */
.pt-kk { position: absolute; left: 2.178%; top: -1.429%; width: 20.044%; height: 91.429%;
  display: none; pointer-events: none; z-index: 3;
  clip-path: polygon(0% 0%,100% 0%,100% 51.56%,92.82% 51.56%,92.82% 74.84%,88.67% 80.94%,
                     50.57% 99.53%,42.25% 99.53%,4.16% 80.94%,0% 74.84%); }
.pt-kk-vid { position: absolute; left: -6.95%; top: 1.41%; width: 116.42%; height: auto;
  display: none; transform-origin: 50% 100%; }  /* origin снизу: scale в «нырке» dismiss() = отступ назад */
.pt-kk-vid.on { display: block; }
.pt-kk-rim { position: absolute; left: 0; top: 0; width: 100%; height: auto;
  display: none; pointer-events: none; z-index: 4; }
.play-top.pt-kk-on .pt-kk,
.play-top.pt-kk-on .pt-kk-rim { display: block; }
/* «Level N» гаснет уже во время затемнения (заставки), а не только с видео. */
.play-top.pt-kk-armed .pt-lvl,
.play-top.pt-kk-on    .pt-lvl { opacity: 0; }
@media (prefers-reduced-motion: reduce) {
  .play-top.pt-kk-armed .pt-streak { animation-duration: .9s; }
}

/* control buttons (✕ / replay) */
.pt-btn { width: 35px; height: 32px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: none; border-radius: 12px; font-size: 17px; color: #fff; cursor: pointer; padding: 0; line-height: 1; transition: filter .1s; transform: translate(-50%, calc(-50% - 2px)); }
.pt-exit { left: 78.96%; background: linear-gradient(180deg, var(--pt-exit-top), var(--pt-exit-bottom)); box-shadow: 0 4px 0 var(--pt-exit-shadow), inset 0 2px 0 rgba(255,255,255,0.35); }
.pt-replay { left: 92.04%; background: linear-gradient(180deg, var(--pt-replay-top), var(--pt-replay-bottom)); box-shadow: 0 4px 0 var(--pt-replay-shadow), inset 0 2px 0 rgba(255,255,255,0.4); }
.pt-exit:hover, .pt-replay:hover { filter: brightness(1.06); }
.pt-exit:active { transform: translate(-50%, calc(-50% + 1px)); box-shadow: 0 1px 0 var(--pt-exit-shadow), inset 0 2px 0 rgba(255,255,255,0.35); }
.pt-replay:active { transform: translate(-50%, calc(-50% + 1px)); box-shadow: 0 1px 0 var(--pt-replay-shadow), inset 0 2px 0 rgba(255,255,255,0.4); }
.pt-ic { width: 20px; height: 20px; fill: none; stroke: var(--pt-icon); stroke-width: 2.6; stroke-linecap: round; stroke-linejoin: round; }

/* countdown timer pill (gold, raised, fits its socket) */
.pt-timer { left: 36.34%; width: 116px; height: 32px; box-sizing: border-box; display: flex; flex-direction: column; align-items: center; justify-content: center; line-height: 1; border-radius: 14px; border: none; background: linear-gradient(180deg, var(--pt-timer-top), var(--pt-timer-bottom)); box-shadow: 0 4px 0 var(--pt-timer-shadow), inset 0 2px 0 rgba(255,255,255,0.6); transform: translate(-50%, calc(-50% - 2px)); }
.pt-timer-cap { font-size: 9px; font-weight: 800; letter-spacing: 1px; color: var(--pt-timer-cap); margin-bottom: 2px; transform: translateY(2px); }
.pt-timer-val { font-size: 19px; font-weight: 900; color: var(--pt-timer-val); font-variant-numeric: tabular-nums; text-shadow: 0 1px 0 rgba(255,255,255,0.4); }
/* low-time warning: red + heartbeat pulse */
.pt-timer.pt-timer-warn { background: linear-gradient(180deg, var(--pt-timer-warn-top), var(--pt-timer-warn-bottom)); box-shadow: 0 4px 0 var(--pt-timer-warn-shadow), inset 0 2px 0 rgba(255,255,255,0.4); animation: ptPulse 0.6s ease-in-out infinite; }
.pt-timer.pt-timer-warn .pt-timer-val { color: #fff; text-shadow: 0 1px 2px rgba(0,0,0,0.3); }
.pt-timer.pt-timer-warn .pt-timer-cap { color: rgba(255,255,255,0.85); }
@keyframes ptPulse {
  0%, 100% { transform: translate(-50%, calc(-50% - 2px)) scale(1); }
  50%      { transform: translate(-50%, calc(-50% - 2px)) scale(1.06); }
}

/* remaining figures counter */
.pt-moves { left: 61.26%; display: flex; flex-direction: column; align-items: center; line-height: 1; pointer-events: none; transform: translate(-50%, calc(-50% + 1px)); }
.pt-moves-cap { font-size: 9px; font-weight: 800; letter-spacing: 1px; color: var(--pt-moves-cap); margin-bottom: 2px; }
.pt-moves-num { font-size: 22px; font-weight: 900; color: var(--pt-moves-num); text-shadow: 0 1px 1px rgba(0,0,0,0.55); }

/* ---- bottom booster bar ---- */
body.play-mode .play-bottom {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 22px;
  margin: 18px 0 22px;
  min-height: 72px;
}

/* Round, chunky 3D booster button. No text — icon image lives inside. */
.play-booster {
  position: relative;
  width: 68px;
  height: 68px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  border-radius: 50%;
  cursor: pointer;
  user-select: none;
  background:
    radial-gradient(circle at 50% 32%, #6c8bf0 0%, #3f5ec4 55%, #2b3f93 100%);
  box-shadow:
    0 7px 0 #1d2c6b,                        /* solid 3D base */
    0 10px 14px rgba(0,0,0,0.45),           /* ambient drop */
    inset 0 4px 5px rgba(255,255,255,0.55), /* top gloss */
    inset 0 -6px 9px rgba(0,0,0,0.40);      /* bottom inner shade */
  transition: transform .08s ease, box-shadow .12s ease;
}
.play-booster:active {
  transform: translateY(5px);
  box-shadow:
    0 2px 0 #1d2c6b,
    0 4px 7px rgba(0,0,0,0.4),
    inset 0 4px 5px rgba(255,255,255,0.5),
    inset 0 -5px 8px rgba(0,0,0,0.4);
}
.play-booster.armed {
  background:
    radial-gradient(circle at 50% 32%, #ffe07a 0%, #f5b820 55%, #d18f10 100%);
  box-shadow:
    0 7px 0 #9c6a08,
    0 0 18px rgba(241,196,15,0.7),
    inset 0 4px 5px rgba(255,255,255,0.65),
    inset 0 -6px 9px rgba(0,0,0,0.35);
}
/* Icon image (generated separately, dropped in as <img>) */
.play-booster-ico {
  width: 38px;
  height: 38px;
  object-fit: contain;
  pointer-events: none;
  filter: drop-shadow(0 1px 1px rgba(0,0,0,0.45));
}
.play-booster-count {
  position: absolute;
  top: -6px; right: -6px;
  min-width: 20px; height: 20px;
  padding: 0 5px;
  border-radius: 10px;
  background: #ec1c2e;
  color: #fff;
  font-size: 12px; font-weight: 700;
  display: flex; align-items: center; justify-content: center;
}

/* ---- play overlays ---- */
.play-overlay {
  position: fixed;
  inset: 0;
  background: rgba(8, 12, 22, 0.78);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 200;
  backdrop-filter: blur(2px);
}
.play-overlay.hidden { display: none; }
/* Pre-match window: soften the flat scrim to a centred vignette so the
   castle backdrop reads around the card (the card itself is opaque, so
   text stays readable). Only #playStart is lightened; the fail/shop
   overlays keep their own solid gradient backgrounds. */
#playStart.play-overlay {
  background: radial-gradient(ellipse at 50% 48%,
    rgba(8, 12, 22, 0.30) 0%,
    rgba(8, 12, 22, 0.52) 60%,
    rgba(8, 12, 22, 0.70) 100%);
  /* no backdrop blur here — it softened the castle behind the card */
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}
/* Light zoom-in for the pre-match window. Re-triggered each time the window
   opens by toggling .pm-anim-in on #playStart (see play.js). */
/* --pm-scale (по умолчанию 1) вкомпонован в keyframes: в мобильном landscape
   плашка (SVG 392×552 выше вьюпорта) ужимается этим же множителем — анимация
   не перебивает статический scale, оба ведут в одно состояние. */
@keyframes pm-zoom-in {
  from { opacity: 0; transform: scale(calc(var(--pm-scale, 1) * .88)); }
  to   { opacity: 1; transform: scale(var(--pm-scale, 1)); }
}
#playStart.pm-anim-in .pm-wrap {
  animation: pm-zoom-in .26s cubic-bezier(.22,.68,.36,1) both;
  will-change: transform, opacity;
}
/* ====================================================================
   Level launch sequence (added on loadCurrentLevel):
   1. top bar drops in from above
   2. board zooms in with a light overshoot, puffs of steam fly off it
   3. bottom bar rises in (at the same time as the board)
   All eased and short. Classes are added/removed by play.js.
   ==================================================================== */
@keyframes lvl-top-in {
  from { opacity: 0; transform: translateY(-150%); }
  to   { opacity: 1; transform: translateY(0); }
}
@keyframes lvl-bottom-in {
  from { opacity: 0; transform: translateY(140%); }
  to   { opacity: 1; transform: translateY(0); }
}
/* Multiply the launch scale by --view-scale so big boards that fitBoard()
   shrinks don't snap to full size during the animation. */
@keyframes lvl-board-in {
  0%   { opacity: 0; transform: scale(calc(var(--view-scale, 1) * .78)); }
  60%  { opacity: 1; }
  80%  { transform: scale(calc(var(--view-scale, 1) * 1.04)); }
  100% { opacity: 1; transform: scale(calc(var(--view-scale, 1) * 1)); }
}
body.play-mode .play-top.lvl-launch-top {
  animation: lvl-top-in .42s cubic-bezier(.22,.9,.32,1) both;
  will-change: transform, opacity;
}
body.play-mode .play-bottom.lvl-launch-bottom {
  animation: lvl-bottom-in .42s cubic-bezier(.22,.9,.32,1) .18s both;
  will-change: transform, opacity;
}
.board-frame.lvl-launch-board {
  animation: lvl-board-in .5s cubic-bezier(.34,1.32,.5,1) .18s both;
  transform-origin: 50% 50%;
  will-change: transform, opacity;
}

/* Reverse of the launch: on win the board zooms out + fades away (light
   easing). Holds the end state so it stays hidden until the next level. */
@keyframes lvl-board-out {
  0%   { opacity: 1; transform: scale(calc(var(--view-scale, 1) * 1)); }
  100% { opacity: 0; transform: scale(calc(var(--view-scale, 1) * .8)); }
}
.board-frame.lvl-launch-board-out {
  animation: lvl-board-out .38s cubic-bezier(.4,0,.5,1) both;
  transform-origin: 50% 50%;
  will-change: transform, opacity;
}

/* On a time-out the gameplay chrome slides off the field (top up, bottom down)
   before the fail window comes up — mirrors the board zoom-out. */
@keyframes lvl-top-out    { from { opacity:1; transform:translateY(0); }    to { opacity:0; transform:translateY(-150%); } }
@keyframes lvl-bottom-out { from { opacity:1; transform:translateY(0); }    to { opacity:0; transform:translateY(150%); } }
body.play-mode .play-top.lvl-exit-top {
  animation: lvl-top-out .34s cubic-bezier(.4,0,.6,1) both; will-change: transform, opacity;
}
body.play-mode .play-bottom.lvl-exit-bottom {
  animation: lvl-bottom-out .34s cubic-bezier(.4,0,.6,1) both; will-change: transform, opacity;
}

/* Steam puffs that fly off the board as it lands. Each puff is positioned
   inline by play.js; it scales up, drifts out, and fades fast. */
.lvl-puff {
  position: absolute;
  width: 46px;
  height: 46px;
  border-radius: 50%;
  pointer-events: none;
  background: radial-gradient(circle at 50% 45%,
              rgba(255,255,255,0.95) 0%,
              rgba(235,242,255,0.65) 45%,
              rgba(220,230,250,0) 72%);
  filter: blur(1px);
  opacity: 0;
  transform: translate(-50%, -50%) scale(.3);
  animation: lvl-puff-pop var(--puff-dur, .62s) ease-out var(--puff-delay, 0s) forwards;
  will-change: transform, opacity;
}
@keyframes lvl-puff-pop {
  0%   { opacity: 0;   transform: translate(-50%, -50%) scale(.3); }
  22%  { opacity: .9; }
  100% { opacity: 0;
         transform: translate(calc(-50% + var(--puff-dx, 0px)),
                               calc(-50% + var(--puff-dy, 0px))) scale(var(--puff-scale, 1.8)); }
}

/* Win confetti: small coloured pieces that burst from the board centre,
   arc up-and-out, then rain down and fade. Rendered in a body-level fixed
   layer so they outlive the board's zoom-out. Position/colour are set inline
   by play.js (spawnConfetti); the trajectory is driven here. */
.lvl-confetti-layer {
  position: fixed;
  inset: 0;
  pointer-events: none;
  overflow: hidden;
  z-index: 340;   /* above the post-match overlay (z 200) AND the keyhole
                     shutter (z 320): confetti keeps raining over the closing
                     keyhole instead of getting cut off by it */
}
.lvl-confetti {
  position: absolute;
  pointer-events: none;
  border-radius: 1px;
  opacity: 0;
  transform: translate(-50%, -50%) rotate(0deg);
  /* linear timing: the smooth parabola lives in the keyframe values themselves,
     so there's no velocity snap at the peak. */
  animation: lvl-confetti-fall var(--cf-dur, 1.4s) linear
             var(--cf-delay, 0s) forwards;
  will-change: transform, opacity;
}
/* Vertical path blends the up-peak (--cf-rise, negative) and the final drop
   (--cf-fall, positive) along a gravity-like parabola; horizontal drifts out
   with mild air-resistance ease. The slope changes gradually through the peak,
   so the rise->fall handover reads as a smooth arc. */
@keyframes lvl-confetti-fall {
  0%   { opacity: 1;
         transform: translate(-50%, -50%) rotate(0deg); }
  18%  { transform: translate(calc(-50% + var(--cf-dx, 0px) * 0.40),
                               calc(-50% + var(--cf-rise, -60px) * 0.85))
                    rotate(calc(var(--cf-spin, 360deg) * 0.18)); }
  34%  { transform: translate(calc(-50% + var(--cf-dx, 0px) * 0.62),
                               calc(-50% + var(--cf-rise, -60px)))
                    rotate(calc(var(--cf-spin, 360deg) * 0.34)); }
  50%  { transform: translate(calc(-50% + var(--cf-dx, 0px) * 0.78),
                               calc(-50% + var(--cf-rise, -60px) * 0.55
                                         + var(--cf-fall, 300px) * 0.12))
                    rotate(calc(var(--cf-spin, 360deg) * 0.5)); }
  72%  { transform: translate(calc(-50% + var(--cf-dx, 0px) * 0.92),
                               calc(-50% + var(--cf-fall, 300px) * 0.5))
                    rotate(calc(var(--cf-spin, 360deg) * 0.74)); }
  88%  { opacity: 1; }
  100% { opacity: 0;
         transform: translate(calc(-50% + var(--cf-dx, 0px)),
                               calc(-50% + var(--cf-fall, 300px)))
                    rotate(var(--cf-spin, 360deg)); }
}

/* ====================================================================
   Tutorial levels (first CFG.TUTORIAL_LEVELS): the top HUD is stripped
   away entirely — no timer, level number or "left" counter. Winning one
   scrolls straight into the next level (see .tut-slide-ghost below).
   ==================================================================== */
body.play-mode.pm-tutorial .play-top { display: none !important; }

/* Horizontal level-to-level pan. The outgoing board is a static clone
   (.tut-slide-ghost) pinned over the stage; the incoming board is the real
   #boardFrame. The stage is the positioning context and clips both as they
   pass its edges. */
.stage.tut-sliding { position: relative; }
.stage.tut-sliding .board { pointer-events: none; }   /* no input mid-pan */
.tut-slide-ghost {
  position: absolute;
  margin: 0;
  pointer-events: none;
  z-index: 6;
  will-change: translate;
}

/* Keep the board hidden behind the pre-match window — the level renders only
   after Play is pressed. */
body.play-mode.pm-prematch .stage { visibility: hidden; }
/* The in-game HUD (top + bottom chrome) belongs to a running level, not the
   pre-match window. */
body.play-mode.pm-prematch .play-top,
body.play-mode.pm-prematch .play-bottom { display: none !important; }

.play-card {
  background: linear-gradient(180deg, #313c58, #283150);
  padding: 28px 34px 30px;
  border-radius: 20px;
  text-align: center;
  min-width: 280px;
  box-shadow: 0 24px 70px rgba(0,0,0,0.55);
  border: 1px solid rgba(255,255,255,0.06);
}
.play-card h2 { margin: 0 0 6px; color: #f4f6fc; font-size: 22px; }
.play-card-sub { margin: 0 0 16px; color: #9aa3bf; font-size: 13px; }
.play-card-win h2 { color: #5ee08a; }
.play-card-lose h2 { color: #ff7a6b; }

.play-reward {
  font-size: 30px;
  font-weight: 800;
  color: #f1c40f;
  margin: 6px 0 20px;
}

/* buttons */
.play-btn {
  display: block;
  width: 100%;
  margin: 8px 0 0;
  background: linear-gradient(180deg, #2fdd6d, #12aa4c);
  color: #06210f;
  border: none;
  border-radius: 12px;
  padding: 12px 20px;
  font-size: 16px;
  font-weight: 700;
  cursor: pointer;
  box-shadow: 0 3px 0 #0b7d35;
}
.play-btn:active { transform: translateY(2px); box-shadow: 0 1px 0 #0b7d35; }
.play-btn-cost { font-size: 13px; opacity: 0.8; font-weight: 600; }
.play-btn-secondary {
  background: linear-gradient(180deg, #ffce33, #f5a208);
  color: #2a1700;
  box-shadow: 0 3px 0 #b47008;
}
.play-btn-ghost {
  background: transparent;
  color: #aeb6d2;
  box-shadow: none;
  font-weight: 600;
  font-size: 14px;
}
.play-btn-ghost:active { transform: none; }
.play-btn.disabled, .play-btn:disabled {
  filter: grayscale(0.7) brightness(0.7);
  cursor: not-allowed;
  box-shadow: none;
}

/* pre-level booster chooser */
.ps-boosters {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  justify-content: center;
  margin: 0 0 18px;
  min-height: 40px;
}
.ps-empty { color: #8a93b0; font-size: 13px; padding: 8px; }
.ps-chip {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  background: var(--cell-bg);
  color: #eef1f8;
  border: 2px solid transparent;
  border-radius: 14px;
  padding: 8px 14px;
  cursor: pointer;
  transition: border-color .15s, background .15s;
}
.ps-chip.selected {
  border-color: #2fdd6d;
  background: #2e4a3c;
}
.ps-chip-ico { font-size: 24px; line-height: 1; }
.ps-chip-label { font-size: 11px; color: #c4cbe2; }
.ps-chip-count { font-size: 11px; color: #8a93b0; }

.ps-nolives {
  color: #ff8e80;
  font-size: 15px;
  font-weight: 600;
  line-height: 1.6;
  padding: 8px 0;
}
.ps-nolives.hidden { display: none; }

/* ============================================================
   PRE-MATCH WINDOW (new design) — scoped under #playStart
   ============================================================ */
#playStart{
  --cap:#cdbfff;
  --play-top:#2fdd6d; --play-bottom:#12aa4c; --play-shadow:#0b7d35;
  --play-text-shadow:#0f552d;
}
#playStart .pm-wrap{position:relative;width:100%;max-width:392px;}

#playStart .pm-head-hex{position:absolute;display:block;left:-6%;top:8.33%;transform:translateY(-50%);
             width:53%;height:auto;z-index:4;
             filter:drop-shadow(0 6px 7px rgba(0,0,0,0.5));pointer-events:none;}
#playStart .pm-head-hex-outline{position:absolute;display:block;left:-6%;top:8.33%;transform:translateY(-50%);
             width:53%;height:auto;z-index:-1;pointer-events:none;}
#playStart .pm-head-lvl{position:absolute;left:20.5%;top:8.33%;transform:translate(-50%,-50%);
             display:flex;flex-direction:column;align-items:center;line-height:1;
             z-index:5;pointer-events:none;}
#playStart .pm-head-cap{font-size:12px;font-weight:800;letter-spacing:1.5px;color:var(--cap);
             margin-bottom:3px;text-shadow:0 1px 1px rgba(0,0,0,.5);}
#playStart .pm-head-num{font-size:68px;font-weight:900;color:#efffc9;
             -webkit-text-stroke:2.6px #14245e;paint-order:stroke;
             filter:drop-shadow(0 0.07em 0 rgba(0,0,0,.5));}
#playStart .pm-head-title{position:absolute;left:68%;top:8.33%;transform:translate(-50%,-50%);
               font-size:30px;font-weight:900;letter-spacing:.5px;
               -webkit-text-stroke:2px #14245e;paint-order:stroke;
               filter:drop-shadow(0 0.07em 0 rgba(0,0,0,.45));pointer-events:none;z-index:5;}
#playStart .pm-head-title.normal,#playStart .pm-head-title.hard,#playStart .pm-head-title.veryhard{color:#efffc9;}

#playStart .pm-close{position:absolute;z-index:6;top:1%;right:1.9%;
          width:40px;height:40px;border:none;border-radius:50%;cursor:pointer;padding:0;
          display:flex;align-items:center;justify-content:center;
          background:linear-gradient(180deg,#ff5a5a,#ec1c2e);
          box-shadow:0 4px 0 #b31221,0 0 0 1.5px #0f214e,0 4px 0 1.5px #0f214e,inset 0 2px 0 rgba(255,255,255,.35);
          transition:transform .08s,box-shadow .12s;}
#playStart .pm-close:active{transform:translateY(3px);
          box-shadow:0 1px 0 #b31221,0 0 0 1.5px #0f214e,0 1px 0 1.5px #0f214e,inset 0 2px 0 rgba(255,255,255,.3);}
#playStart .pm-close svg{width:17px;height:17px;filter:drop-shadow(0 2px 0 rgba(150,30,45,.55));}

#playStart .pm-box{position:relative;width:100%;filter:drop-shadow(0 14px 22px rgba(0,0,0,0.5));}
#playStart .pm-box svg.pm-plate{display:block;width:100%;height:auto;}
#playStart .pm-ov{position:absolute;}

#playStart .pm-frame{left:7.1%;right:7.1%;top:15.22%;height:60.87%;padding:14px;box-sizing:border-box;}
#playStart .pm-subframe{width:100%;height:100%;box-sizing:border-box;
             background:#f9efc9;border-radius:20px;border:2px solid #e4cf91;
             padding:20px 8px;display:flex;flex-direction:column;
             align-items:center;justify-content:center;gap:12px;
             box-shadow:inset 0 2px 4px rgba(255,255,255,.7),
                        inset 0 -3px 7px rgba(159,130,60,.35),
                        0 2px 0 rgba(0,0,0,.25);}
#playStart .pm-goal{display:flex;flex-direction:column;align-items:center;gap:12px;line-height:1;}
#playStart .pm-goal-cap{font-size:13px;font-weight:800;letter-spacing:2px;color:var(--cap);
             text-shadow:0 1px 1px rgba(0,0,0,.5);}
#playStart .pm-subframe .pm-goal-cap{color:#9c7a26;text-shadow:0 1px 0 rgba(255,255,255,.5);}
#playStart .pm-subframe .pm-goal-num{color:#fff;
             -webkit-text-stroke:2px #785f28;paint-order:stroke;
             filter:drop-shadow(0 0.07em 0 #785f28);}
#playStart .pm-goal-row{display:flex;align-items:center;gap:14px;}
#playStart .pm-goal-num{font-size:36px;font-weight:900;color:#fff;position:relative;top:-3px;}

#playStart .gp-block{width:54px;height:54px;border-radius:16px;position:relative;color:var(--c);flex:0 0 auto;}
#playStart .pm-goal-ico{width:54px;height:54px;object-fit:contain;flex:0 0 auto;pointer-events:none;
             /* cream outline + soft shadow. НЕ url(#goalOutline): Safari рисует
                reference-фильтры на HTML-элементах серой плитой вместо тени.
                Тот же приём, что у иконок бустеров: 4 жёстких drop-shadow =
                обводка, потом мягкая тень (см. style.css, booster outline). */
             filter:drop-shadow(1px 0 0 #f2f9e2) drop-shadow(-1px 0 0 #f2f9e2)
                    drop-shadow(0 1px 0 #f2f9e2) drop-shadow(0 -1px 0 #f2f9e2)
                    drop-shadow(0 3px 3px rgba(0,0,0,.35));}
#playStart .gp-inner{position:absolute;inset:0;border-radius:inherit;overflow:hidden;
          background:var(--c);border:1px solid rgba(255,255,255,0.28);
          --wall:rgba(0,0,0,0.497);
          --wall:color-mix(in srgb, var(--c) 90%, #0a0c12);
          box-shadow:
            0 0 0 2px #f2f9e2,
            inset 0 2px 6px rgb(255,255,255),
            inset 0 -10px 10px rgba(255,255,255,0.3),
            inset 0 -32px 8px -16px var(--wall),
            inset 14px 0 30px -1px var(--wall),
            inset -14px 0 8px -10px var(--wall),
            inset 0 10px 38px -2px var(--wall),
            0 1px 1px -1px var(--c),
            0 8px 18px rgba(0,0,0,0.19);}
#playStart .gp-inner::before{content:'';position:absolute;inset:0;border-radius:inherit;pointer-events:none;
          background:linear-gradient(to bottom, rgba(255,255,255,0.28) 0%, rgba(255,255,255,0.07) 42%, rgba(255,255,255,0) 68%);}
#playStart .gp-inner::after{content:'';position:absolute;inset:0;border-radius:inherit;pointer-events:none;
          background:
            radial-gradient(circle at 82% 82%, rgba(255,255,255,0.30) 2%, rgba(255,255,255,0) 3%),
            radial-gradient(circle at 31% 27%, rgba(255,255,255,0.22) 0%, rgba(255,255,255,0) 6%),
            radial-gradient(circle at 71% 15%, rgba(255,255,255,0.40) 0%, rgba(255,255,255,0) 2%),
            radial-gradient(circle at 56% 38%, rgba(222,236,255,0.35) 0%, rgba(255,255,255,0) 3%),
            radial-gradient(140% 22% at 50% 6%, rgba(255,255,255,0.35) 0%, rgba(255,255,255,0) 30%);}

#playStart .pm-bsec{display:flex;flex-direction:column;align-items:center;gap:12px;}
#playStart .pm-sel-label{font-size:15px;font-weight:800;letter-spacing:.5px;color:#9c7a26;
              text-shadow:0 1px 0 rgba(255,255,255,.5);}
#playStart .pm-subframe2{background:#ebe0b6;border:2px solid #d9c98f;border-radius:16px;
              padding:18px 40px;
              box-shadow:0 0 0 2px #f2f9e2,inset 0 2px 4px rgba(150,120,50,.3),0 1px 0 rgba(255,255,255,.5);}
#playStart .pm-boosters{display:flex;justify-content:center;gap:8px;}
#playStart .pm-bstr-slot{position:relative;width:64px;height:68.2px;
              display:flex;align-items:center;justify-content:center;}
#playStart .pm-slot-svg{position:absolute;inset:0;width:100%;height:100%;
             filter:drop-shadow(0 1px 0 rgba(255,255,255,.5));}
#playStart .slot-floor{fill:url(#sqFloor);}
#playStart .slot-rim{fill:none;stroke:rgba(120,95,40,.5);stroke-width:1.5;}
#playStart .slot-outer{fill:none;stroke:#f2f9e2;stroke-width:1.5;}
#playStart .pm-bstr{position:relative;width:58px;height:60.2px;background:none;border:none;padding:0;
         display:flex;align-items:center;justify-content:center;cursor:pointer;user-select:none;
         transform:translateX(-0.25px);transition:transform .08s ease;}
#playStart .pm-bstr:active{transform:translate(-0.25px,3px);}
#playStart .pm-bstr.locked{cursor:default;}
#playStart .pm-bstr.locked:active{transform:translateX(-0.25px);}
#playStart .pm-bstr-svg{position:absolute;inset:0;width:100%;height:100%;}
#playStart .pm-bstr .sq-face{fill:url(#sqBlue);}
#playStart .pm-bstr.selected .sq-face{fill:url(#sqGreen);}
#playStart .pm-bstr .sq-base{fill:#1d3f8e;}
#playStart .pm-bstr.selected .sq-base{fill:#0b7d35;}
#playStart .pm-bstr-ico{position:relative;z-index:2;width:60%;height:60%;object-fit:contain;
             filter:drop-shadow(0 1px 1px rgba(0,0,0,.4));pointer-events:none;}
#playStart .pm-bstr-badge{position:absolute;z-index:3;top:0;right:2px;min-width:24px;height:24px;padding:0 6px;
         border-radius:12px;background:#ec1c2e;color:#fff;font-size:13px;font-weight:800;
         display:flex;align-items:center;justify-content:center;
         box-shadow:0 2px 0 rgba(0,0,0,.3);pointer-events:none;}
#playStart .pm-bstr.selected .pm-bstr-badge{background:#0f7a3f;font-size:15px;}
#playStart .pm-bstr-lockbig{position:relative;z-index:2;width:54%;height:54%;pointer-events:none;
         filter:drop-shadow(0 2px 1px rgba(0,0,0,.3));}

#playStart .pm-play{left:11.22%;right:11.22%;top:80.62%;height:12.32%;border:none;border-radius:18px;cursor:pointer;
         display:flex;align-items:center;justify-content:center;gap:14px;
         background:linear-gradient(180deg,var(--play-top),var(--play-bottom));
         color:#efffc9;font-size:44px;font-weight:900;letter-spacing:2px;line-height:1;
         -webkit-text-stroke:2px var(--play-text-shadow);paint-order:stroke;
         box-shadow:0 6px 0 var(--play-shadow),0 0 0 1.5px #0f214e,0 6px 0 1.5px #0f214e,inset 0 3px 0 rgba(255,255,255,.45);
         transition:transform .08s,box-shadow .12s;}
#playStart .pm-play:active{transform:translateY(4px);box-shadow:0 2px 0 var(--play-shadow),0 0 0 1.5px #0f214e,0 2px 0 1.5px #0f214e,inset 0 3px 0 rgba(255,255,255,.4);}
#playStart .pm-play-label{display:inline-flex;align-items:center;gap:14px;
               filter:drop-shadow(0 0.07em 0 var(--play-text-shadow));}
#playStart .pm-play svg{width:38px;height:38px;}

#playStart .pm-nolives{left:11.22%;right:11.22%;top:80.62%;height:12.32%;
         display:flex;align-items:center;justify-content:center;text-align:center;
         color:#ff8e80;font-size:15px;font-weight:700;line-height:1.3;}
#playStart .pm-play.hidden,#playStart .pm-nolives.hidden{display:none;}

/* ====================================================================
   Fail / Continue window (#playFail) — reuses the prematch plate, no
   hexagon. Title = fail reason; the frame holds an hourglass + time
   bonus on a short cream card with the message below on the dark socket;
   the bottom button continues the same board for coins.
   ==================================================================== */
#playFail{
  --play-top:#2fdd6d; --play-bottom:#12aa4c; --play-shadow:#0b7d35;
  --play-text-shadow:#0f552d;
}
/* solid backdrop (like prematch/postmatch) so the emptied field is fully hidden */
#playFail.play-overlay{background:linear-gradient(180deg,#2c2658,#1d1840);
  backdrop-filter:none;-webkit-backdrop-filter:none;}
/* the window zooms in just like the pre-match window */
#playFail.pm-anim-in .pm-wrap{animation:pm-zoom-in .26s cubic-bezier(.22,.68,.36,1) both;
  will-change:transform,opacity;}
/* z-index:5 — плашка (крестик z6) всегда ВЫШЕ мета-топбара (z4): бар не накрывает ✕ → нет софтлока */
#playFail .pm-wrap{position:relative;width:100%;max-width:392px;z-index:5;}
#playFail .pm-box{position:relative;width:100%;filter:drop-shadow(0 14px 22px rgba(0,0,0,0.5));}
#playFail .pm-box svg.pm-plate{display:block;width:100%;height:auto;}
#playFail .pm-ov{position:absolute;}

/* fail reason title, centred where the hexagon/difficulty used to sit */
#playFail .pm-head-title{position:absolute;left:50%;top:8.33%;transform:translate(-50%,-50%);
         font-size:32px;font-weight:900;letter-spacing:.5px;white-space:nowrap;z-index:5;pointer-events:none;
         -webkit-text-stroke:2px #14245e;paint-order:stroke;
         filter:drop-shadow(0 0.07em 0 rgba(0,0,0,.45));}
#playFail .pm-head-title.fail{color:#ffe2c4;}

#playFail .pm-close{position:absolute;z-index:6;top:1%;right:1.9%;
         width:40px;height:40px;border:none;border-radius:50%;cursor:pointer;padding:0;
         display:flex;align-items:center;justify-content:center;
         background:linear-gradient(180deg,#ff5a5a,#ec1c2e);
         box-shadow:0 4px 0 #b31221,0 0 0 1.5px #0f214e,0 4px 0 1.5px #0f214e,inset 0 2px 0 rgba(255,255,255,.35);
         transition:transform .08s,box-shadow .12s;}
#playFail .pm-close:active{transform:translateY(3px);
         box-shadow:0 1px 0 #b31221,0 0 0 1.5px #0f214e,0 1px 0 1.5px #0f214e,inset 0 2px 0 rgba(255,255,255,.3);}
#playFail .pm-close svg{width:17px;height:17px;filter:drop-shadow(0 2px 0 rgba(150,30,45,.55));}

/* big frame (dark socket): a short cream card on top, message below on dark */
#playFail .pm-frame--fail{left:7.1%;right:7.1%;top:15.22%;height:60.87%;padding:22px;box-sizing:border-box;
         display:flex;flex-direction:column;align-items:center;justify-content:flex-start;gap:0;}
#playFail .fc-card{box-sizing:border-box;width:100%;background:#f9efc9;border-radius:20px;border:2px solid #e4cf91;
         padding:16px 20px 20px;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:4px;
         box-shadow:inset 0 2px 4px rgba(255,255,255,.7),inset 0 -3px 7px rgba(159,130,60,.35),0 2px 0 rgba(0,0,0,.25);}
#playFail .fc-hero{display:flex;flex-direction:column;align-items:center;gap:6px;line-height:1;}
#playFail .fc-watch{width:118px;height:118px;object-fit:contain;filter:drop-shadow(0 6px 8px rgba(0,0,0,.28));}
#playFail .fc-plus{font-family:inherit;font-variant-numeric:lining-nums tabular-nums;
         font-size:62px;font-weight:900;color:#ffd24a;
         -webkit-text-stroke:3px #7a4d10;paint-order:stroke;filter:drop-shadow(0 0.05em 0 #7a4d10);}
#playFail .fc-plus small{font-size:24px;font-weight:800;letter-spacing:1px;}
#playFail .fc-msg{flex:1;display:flex;align-items:center;justify-content:center;
         max-width:260px;margin:0;text-align:center;font-size:17px;font-weight:800;line-height:1.35;
         color:#ffe2c4;-webkit-text-stroke:1px #14245e;paint-order:stroke;filter:drop-shadow(0 0.06em 0 rgba(0,0,0,.45));}

/* continue button: label on top, coin price below (stacked) */
#playFail .pm-play--fail{left:11.22%;right:11.22%;top:80.62%;height:12.32%;border:none;border-radius:18px;cursor:pointer;
         display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;
         background:linear-gradient(180deg,var(--play-top),var(--play-bottom));color:#efffc9;line-height:1;
         box-shadow:0 6px 0 var(--play-shadow),0 0 0 1.5px #0f214e,0 6px 0 1.5px #0f214e,inset 0 3px 0 rgba(255,255,255,.45);
         transition:transform .08s,box-shadow .12s;}
#playFail .pm-play--fail:active{transform:translateY(4px);box-shadow:0 2px 0 var(--play-shadow),0 0 0 1.5px #0f214e,0 2px 0 1.5px #0f214e,inset 0 3px 0 rgba(255,255,255,.4);}
#playFail .pm-play-label{display:inline-flex;align-items:center;white-space:nowrap;
         font-size:26px;font-weight:900;letter-spacing:1px;
         -webkit-text-stroke:1.5px var(--play-text-shadow);paint-order:stroke;
         filter:drop-shadow(0 0.06em 0 var(--play-text-shadow));}
#playFail .fc-price{display:inline-flex;align-items:center;gap:6px;
         font-family:inherit;font-variant-numeric:lining-nums tabular-nums;font-size:19px;font-weight:900;color:#efffc9;
         -webkit-text-stroke:0.9px var(--play-text-shadow);paint-order:stroke;filter:drop-shadow(0 0.06em 0 var(--play-text-shadow));}
#playFail .fc-price svg{width:20px;height:20px;-webkit-text-stroke:0;filter:drop-shadow(0 1px 1px rgba(0,0,0,.35));}
/* not enough coins → button reads as disabled */
#playFail .pm-play--fail.disabled{filter:grayscale(.65) brightness(.92);cursor:default;
         box-shadow:0 6px 0 #5a6470,0 0 0 1.5px #0f214e,0 6px 0 1.5px #0f214e,inset 0 3px 0 rgba(255,255,255,.25);}
#playFail .pm-play--fail.disabled:active{transform:none;}

/* ===== Interlevel (meta) top bar — lives + coins ===== */
/* meta top bar — fixed at the top of the fail window; slides down on open */
#playFail .meta-top{position:fixed;top:16px;left:50%;transform:translate(-50%,-160%);
  width:100%;max-width:480px;padding:0 16px;box-sizing:border-box;z-index:4;
  pointer-events:none;}
#playFail.pm-anim-in .meta-top{animation:mt-drop .42s cubic-bezier(.22,.9,.32,1) .04s both;}
@keyframes mt-drop{from{transform:translate(-50%,-160%);}to{transform:translate(-50%,0);}}
#playFail .mt-wrap{position:relative;width:100%;}
#playFail .mt-frame{display:block;width:100%;height:auto;filter:drop-shadow(0 6px 5px rgba(0,0,0,0.5));}
#playFail .mt-ov{position:absolute;transform:translate(-50%,-50%);top:50%;pointer-events:none;}
#playFail .mt-avatar{left:12.60%;width:11.3%;height:auto;}
#playFail .mt-lives-num{left:31.3%;font-size:17px;font-weight:900;color:#fff;
  -webkit-text-stroke:0.7px #8f2438;text-shadow:0 1px 1px rgba(0,0,0,0.55);
  transform:translate(-50%,calc(-50% - 1.5px));font-variant-numeric:tabular-nums;}
#playFail .mt-slot-val{font-size:16px;font-weight:400;font-variant-numeric:tabular-nums;
  letter-spacing:.4px;white-space:nowrap;text-shadow:0 1px 1px rgba(0,0,0,0.55);}
#playFail .mt-lives-win{left:44.11%;color:#ffd56b;}
#playFail .mt-lives-win.max{color:#7ce39a;letter-spacing:1.2px;}
#playFail .mt-coins-num{left:80.49%;color:#fff;}
#playFail .mt-coins-hit{left:76.22%;width:37.8%;height:46px;border:none;background:transparent;
  border-radius:18px;cursor:pointer;pointer-events:auto;transform:translate(-50%,calc(-50% - 1px));}
#playFail .mt-coins-hit:active{transform:translate(-50%,calc(-50% + 1px));}

/* ====================================================================
   LEVEL FAILED window (#playLevelFailed) — the prematch window reused
   after a real defeat: central frame shows the lost life (-1 heart),
   the head title shows the fail reason, RETRY restarts the level.
   Most rules are cloned from #playStart / #playFail; the block below
   only overrides what differs (dark life frame, heart, reason colour).
   ==================================================================== */
#playLevelFailed{
  --cap:#cdbfff;
  --play-top:#2fdd6d; --play-bottom:#12aa4c; --play-shadow:#0b7d35;
  --play-text-shadow:#0f552d;
}
/* z-index:5 — плашка (крестик z6) всегда ВЫШЕ мета-топбара (z4), см. #playFail */
#playLevelFailed .pm-wrap{position:relative;width:100%;max-width:392px;z-index:5;}

#playLevelFailed .pm-head-hex{position:absolute;display:block;left:-6%;top:8.33%;transform:translateY(-50%);
             width:53%;height:auto;z-index:4;
             filter:drop-shadow(0 6px 7px rgba(0,0,0,0.5));pointer-events:none;}
#playLevelFailed .pm-head-hex-outline{position:absolute;display:block;left:-6%;top:8.33%;transform:translateY(-50%);
             width:53%;height:auto;z-index:-1;pointer-events:none;}
#playLevelFailed .pm-head-lvl{position:absolute;left:20.5%;top:8.33%;transform:translate(-50%,-50%);
             display:flex;flex-direction:column;align-items:center;line-height:1;
             z-index:5;pointer-events:none;}
#playLevelFailed .pm-head-cap{font-size:12px;font-weight:800;letter-spacing:1.5px;color:var(--cap);
             margin-bottom:3px;text-shadow:0 1px 1px rgba(0,0,0,.5);}
#playLevelFailed .pm-head-num{font-size:68px;font-weight:900;color:#efffc9;
             -webkit-text-stroke:2.6px #14245e;paint-order:stroke;
             filter:drop-shadow(0 0.07em 0 rgba(0,0,0,.5));}
#playLevelFailed .pm-head-title{position:absolute;left:68%;top:8.33%;transform:translate(-50%,-50%);
               font-size:30px;font-weight:900;letter-spacing:.5px;
               -webkit-text-stroke:2px #14245e;paint-order:stroke;
               filter:drop-shadow(0 0.07em 0 rgba(0,0,0,.45));pointer-events:none;z-index:5;}
#playLevelFailed .pm-head-title.normal,#playLevelFailed .pm-head-title.hard,#playLevelFailed .pm-head-title.veryhard{color:#efffc9;}

#playLevelFailed .pm-close{position:absolute;z-index:6;top:1%;right:1.9%;
          width:40px;height:40px;border:none;border-radius:50%;cursor:pointer;padding:0;
          display:flex;align-items:center;justify-content:center;
          background:linear-gradient(180deg,#ff5a5a,#ec1c2e);
          box-shadow:0 4px 0 #b31221,0 0 0 1.5px #0f214e,0 4px 0 1.5px #0f214e,inset 0 2px 0 rgba(255,255,255,.35);
          transition:transform .08s,box-shadow .12s;}
#playLevelFailed .pm-close:active{transform:translateY(3px);
          box-shadow:0 1px 0 #b31221,0 0 0 1.5px #0f214e,0 1px 0 1.5px #0f214e,inset 0 2px 0 rgba(255,255,255,.3);}
#playLevelFailed .pm-close svg{width:17px;height:17px;filter:drop-shadow(0 2px 0 rgba(150,30,45,.55));}

#playLevelFailed .pm-box{position:relative;width:100%;filter:drop-shadow(0 14px 22px rgba(0,0,0,0.5));}
#playLevelFailed .pm-box svg.pm-plate{display:block;width:100%;height:auto;}
#playLevelFailed .pm-ov{position:absolute;}

#playLevelFailed .pm-frame{left:7.1%;right:7.1%;top:15.22%;height:60.87%;padding:14px;box-sizing:border-box;}
#playLevelFailed .pm-subframe{width:100%;height:100%;box-sizing:border-box;
             background:#f9efc9;border-radius:20px;border:2px solid #e4cf91;
             padding:20px 8px;display:flex;flex-direction:column;
             align-items:center;justify-content:center;gap:12px;
             box-shadow:inset 0 2px 4px rgba(255,255,255,.7),
                        inset 0 -3px 7px rgba(159,130,60,.35),
                        0 2px 0 rgba(0,0,0,.25);}
#playLevelFailed .pm-goal{display:flex;flex-direction:column;align-items:center;gap:12px;line-height:1;}
#playLevelFailed .pm-goal-cap{font-size:13px;font-weight:800;letter-spacing:2px;color:var(--cap);
             text-shadow:0 1px 1px rgba(0,0,0,.5);}
#playLevelFailed .pm-subframe .pm-goal-cap{color:#9c7a26;text-shadow:0 1px 0 rgba(255,255,255,.5);}
#playLevelFailed .pm-subframe .pm-goal-num{color:#fff;
             -webkit-text-stroke:2px #785f28;paint-order:stroke;
             filter:drop-shadow(0 0.07em 0 #785f28);}
#playLevelFailed .pm-goal-row{display:flex;align-items:center;gap:14px;}
#playLevelFailed .pm-goal-num{font-size:36px;font-weight:900;color:#fff;position:relative;top:-3px;}

#playLevelFailed .gp-block{width:54px;height:54px;border-radius:16px;position:relative;color:var(--c);flex:0 0 auto;}
#playLevelFailed .pm-goal-ico{width:54px;height:54px;object-fit:contain;flex:0 0 auto;pointer-events:none;
             /* cream outline + soft shadow, без url(#goalOutline) — см. #playStart */
             filter:drop-shadow(1px 0 0 #f2f9e2) drop-shadow(-1px 0 0 #f2f9e2)
                    drop-shadow(0 1px 0 #f2f9e2) drop-shadow(0 -1px 0 #f2f9e2)
                    drop-shadow(0 3px 3px rgba(0,0,0,.35));}
#playLevelFailed .gp-inner{position:absolute;inset:0;border-radius:inherit;overflow:hidden;
          background:var(--c);border:1px solid rgba(255,255,255,0.28);
          --wall:rgba(0,0,0,0.497);
          --wall:color-mix(in srgb, var(--c) 90%, #0a0c12);
          box-shadow:
            0 0 0 2px #f2f9e2,
            inset 0 2px 6px rgb(255,255,255),
            inset 0 -10px 10px rgba(255,255,255,0.3),
            inset 0 -32px 8px -16px var(--wall),
            inset 14px 0 30px -1px var(--wall),
            inset -14px 0 8px -10px var(--wall),
            inset 0 10px 38px -2px var(--wall),
            0 1px 1px -1px var(--c),
            0 8px 18px rgba(0,0,0,0.19);}
#playLevelFailed .gp-inner::before{content:'';position:absolute;inset:0;border-radius:inherit;pointer-events:none;
          background:linear-gradient(to bottom, rgba(255,255,255,0.28) 0%, rgba(255,255,255,0.07) 42%, rgba(255,255,255,0) 68%);}
#playLevelFailed .gp-inner::after{content:'';position:absolute;inset:0;border-radius:inherit;pointer-events:none;
          background:
            radial-gradient(circle at 82% 82%, rgba(255,255,255,0.30) 2%, rgba(255,255,255,0) 3%),
            radial-gradient(circle at 31% 27%, rgba(255,255,255,0.22) 0%, rgba(255,255,255,0) 6%),
            radial-gradient(circle at 71% 15%, rgba(255,255,255,0.40) 0%, rgba(255,255,255,0) 2%),
            radial-gradient(circle at 56% 38%, rgba(222,236,255,0.35) 0%, rgba(255,255,255,0) 3%),
            radial-gradient(140% 22% at 50% 6%, rgba(255,255,255,0.35) 0%, rgba(255,255,255,0) 30%);}

#playLevelFailed .pm-bsec{display:flex;flex-direction:column;align-items:center;gap:12px;}
#playLevelFailed .pm-sel-label{font-size:15px;font-weight:800;letter-spacing:.5px;color:#9c7a26;
              text-shadow:0 1px 0 rgba(255,255,255,.5);}
#playLevelFailed .pm-subframe2{background:#ebe0b6;border:2px solid #d9c98f;border-radius:16px;
              padding:18px 40px;
              box-shadow:0 0 0 2px #f2f9e2,inset 0 2px 4px rgba(150,120,50,.3),0 1px 0 rgba(255,255,255,.5);}
#playLevelFailed .pm-boosters{display:flex;justify-content:center;gap:8px;}
#playLevelFailed .pm-bstr-slot{position:relative;width:64px;height:68.2px;
              display:flex;align-items:center;justify-content:center;}
#playLevelFailed .pm-slot-svg{position:absolute;inset:0;width:100%;height:100%;
             filter:drop-shadow(0 1px 0 rgba(255,255,255,.5));}
#playLevelFailed .slot-floor{fill:url(#sqFloor);}
#playLevelFailed .slot-rim{fill:none;stroke:rgba(120,95,40,.5);stroke-width:1.5;}
#playLevelFailed .slot-outer{fill:none;stroke:#f2f9e2;stroke-width:1.5;}
#playLevelFailed .pm-bstr{position:relative;width:58px;height:60.2px;background:none;border:none;padding:0;
         display:flex;align-items:center;justify-content:center;cursor:pointer;user-select:none;
         transform:translateX(-0.25px);transition:transform .08s ease;}
#playLevelFailed .pm-bstr:active{transform:translate(-0.25px,3px);}
#playLevelFailed .pm-bstr.locked{cursor:default;}
#playLevelFailed .pm-bstr.locked:active{transform:translateX(-0.25px);}
#playLevelFailed .pm-bstr-svg{position:absolute;inset:0;width:100%;height:100%;}
#playLevelFailed .pm-bstr .sq-face{fill:url(#sqBlue);}
#playLevelFailed .pm-bstr.selected .sq-face{fill:url(#sqGreen);}
#playLevelFailed .pm-bstr .sq-base{fill:#1d3f8e;}
#playLevelFailed .pm-bstr.selected .sq-base{fill:#0b7d35;}
#playLevelFailed .pm-bstr-ico{position:relative;z-index:2;width:60%;height:60%;object-fit:contain;
             filter:drop-shadow(0 1px 1px rgba(0,0,0,.4));pointer-events:none;}
#playLevelFailed .pm-bstr-badge{position:absolute;z-index:3;top:0;right:2px;min-width:24px;height:24px;padding:0 6px;
         border-radius:12px;background:#ec1c2e;color:#fff;font-size:13px;font-weight:800;
         display:flex;align-items:center;justify-content:center;
         box-shadow:0 2px 0 rgba(0,0,0,.3);pointer-events:none;}
#playLevelFailed .pm-bstr.selected .pm-bstr-badge{background:#0f7a3f;font-size:15px;}
#playLevelFailed .pm-bstr-lockbig{position:relative;z-index:2;width:54%;height:54%;pointer-events:none;
         filter:drop-shadow(0 2px 1px rgba(0,0,0,.3));}

#playLevelFailed .pm-play{left:11.22%;right:11.22%;top:80.62%;height:12.32%;border:none;border-radius:18px;cursor:pointer;
         display:flex;align-items:center;justify-content:center;gap:14px;
         background:linear-gradient(180deg,var(--play-top),var(--play-bottom));
         color:#efffc9;font-size:44px;font-weight:900;letter-spacing:2px;line-height:1;
         -webkit-text-stroke:2px var(--play-text-shadow);paint-order:stroke;
         box-shadow:0 6px 0 var(--play-shadow),0 0 0 1.5px #0f214e,0 6px 0 1.5px #0f214e,inset 0 3px 0 rgba(255,255,255,.45);
         transition:transform .08s,box-shadow .12s;}
#playLevelFailed .pm-play:active{transform:translateY(4px);box-shadow:0 2px 0 var(--play-shadow),0 0 0 1.5px #0f214e,0 2px 0 1.5px #0f214e,inset 0 3px 0 rgba(255,255,255,.4);}
#playLevelFailed .pm-play-label{display:inline-flex;align-items:center;gap:14px;
               filter:drop-shadow(0 0.07em 0 var(--play-text-shadow));}
#playLevelFailed .pm-play svg{width:38px;height:38px;}

#playLevelFailed .pm-nolives{left:11.22%;right:11.22%;top:80.62%;height:12.32%;
         display:flex;align-items:center;justify-content:center;text-align:center;
         color:#ff8e80;font-size:15px;font-weight:700;line-height:1.3;}
#playLevelFailed .pm-play.hidden,#playLevelFailed .pm-nolives.hidden{display:none;}

/* meta top bar (lives + coins), cloned from the continue window */
#playLevelFailed.play-overlay{background:linear-gradient(180deg,#2c2658,#1d1840);
  backdrop-filter:none;-webkit-backdrop-filter:none;}
/* ===== Interlevel (meta) top bar — lives + coins ===== */
/* meta top bar — fixed at the top of the fail window; slides down on open */
#playLevelFailed .meta-top{position:fixed;top:16px;left:50%;transform:translate(-50%,-160%);
  width:100%;max-width:480px;padding:0 16px;box-sizing:border-box;z-index:4;
  pointer-events:none;}
#playLevelFailed.pm-anim-in .meta-top{animation:mt-drop .42s cubic-bezier(.22,.9,.32,1) .04s both;}
@keyframes mt-drop{from{transform:translate(-50%,-160%);}to{transform:translate(-50%,0);}}
#playLevelFailed .mt-wrap{position:relative;width:100%;}
#playLevelFailed .mt-frame{display:block;width:100%;height:auto;filter:drop-shadow(0 6px 5px rgba(0,0,0,0.5));}
#playLevelFailed .mt-ov{position:absolute;transform:translate(-50%,-50%);top:50%;pointer-events:none;}
#playLevelFailed .mt-avatar{left:12.60%;width:11.3%;height:auto;}

/* ====================================================================
   КК-trouble в гексе мета-топбара (loss) — MGM-выглядывание.
   Гекс ИДЕНТИЧЕН lc-topbar (viewBox -6 -4 492 140) → значения 1:1 из
   postmatch.css .lc-kk. Общие правила для обеих панелей (.meta-top).
   Техника: MGM_PEEK_TECHNIQUE.md. Играет ОДИН раз, замирает на кадре.
   ==================================================================== */
.meta-top .mt-kk{position:absolute;left:2.39%;top:-1.43%;width:22.0%;height:91.43%;
  display:none;pointer-events:none;z-index:3;
  clip-path:polygon(0% 0%,100% 0%,100% 51.56%,92.82% 51.56%,92.82% 74.84%,88.67% 80.94%,
                    50.57% 99.53%,42.25% 99.53%,4.16% 80.94%,0% 74.84%);}
.meta-top .mt-kk-vid{position:absolute;left:-6.95%;top:1.41%;width:116.42%;height:auto;display:block;}
.meta-top .mt-kk-rim{position:absolute;left:0;top:0;width:100%;height:auto;
  display:none;pointer-events:none;z-index:4;}
.meta-top .mt-wrap.mt-kk-on .mt-kk,
.meta-top .mt-wrap.mt-kk-on .mt-kk-rim{display:block;}
.meta-top .mt-wrap.mt-kk-on .mt-avatar{display:none;}
#playLevelFailed .mt-lives-num{left:31.3%;font-size:17px;font-weight:900;color:#fff;
  -webkit-text-stroke:0.7px #8f2438;text-shadow:0 1px 1px rgba(0,0,0,0.55);
  transform:translate(-50%,calc(-50% - 1.5px));font-variant-numeric:tabular-nums;}
#playLevelFailed .mt-slot-val{font-size:16px;font-weight:400;font-variant-numeric:tabular-nums;
  letter-spacing:.4px;white-space:nowrap;text-shadow:0 1px 1px rgba(0,0,0,0.55);}
#playLevelFailed .mt-lives-win{left:44.11%;color:#ffd56b;}
#playLevelFailed .mt-lives-win.max{color:#7ce39a;letter-spacing:1.2px;}
#playLevelFailed .mt-coins-num{left:80.49%;color:#fff;}
#playLevelFailed .mt-coins-hit{left:76.22%;width:37.8%;height:46px;border:none;background:transparent;
  border-radius:18px;cursor:pointer;pointer-events:auto;transform:translate(-50%,calc(-50% - 1px));}
#playLevelFailed .mt-coins-hit:active{transform:translate(-50%,calc(-50% + 1px));}

/* window + meta bar zoom/drop-in (re-fired on open) */
#playLevelFailed.pm-anim-in .pm-wrap{animation:pm-zoom-in .26s cubic-bezier(.22,.68,.36,1) both;will-change:transform,opacity;}
/* solid backdrop so the emptied field is fully hidden */
#playLevelFailed.play-overlay{background:linear-gradient(180deg,#2c2658,#1d1840);backdrop-filter:none;-webkit-backdrop-filter:none;}

/* fail reason title — narrower so "Out of moves" fits beside the hexagon */
#playLevelFailed .pm-head-title{left:67%;width:58%;text-align:center;white-space:normal;
         font-size:23px;line-height:1.05;color:#ffe1c2;}

/* main frame painted blue (matches the window plate) instead of cream */
#playLevelFailed .pm-subframe{background:linear-gradient(180deg,#3a6dd0,#2a55a8);border:2px solid #1c3b86;
         box-shadow:inset 0 2px 4px rgba(255,255,255,.45),inset 0 -3px 7px rgba(10,25,70,.45),0 2px 0 rgba(0,0,0,.25);}
#playLevelFailed .pm-sel-label{color:#eaf2ff;text-shadow:0 1px 1px rgba(0,0,0,.4);}
/* booster slots: same recipe as prematch, recoloured for the blue subframe.
   Prematch relationships kept 1:1 — floor slightly darker than the bg, outer
   stroke a light highlight (lighter than the bg), rim a translucent dark of
   the same family, weak bottom glow inside the pocket. */
#playLevelFailed .slot-floor{fill:url(#sqFloorDark);}
#playLevelFailed .slot-rim{stroke:rgba(10,24,66,.55);}
/* Outer ring pulled flush against the pocket edge (attribute transform is
   scale(1.05), which leaves a gap where the blue subframe showed through as a
   dark hairline — invisible in prematch only because its subframe is cream). */
#playLevelFailed .slot-outer{stroke:#6d97e4;stroke-width:2.5;
              transform:translate(50px,50px) scale(1.025) translate(-50px,-50px);}
/* no drop-shadow: under a visible light ring it read as a second (double) line */
#playLevelFailed .pm-slot-svg{filter:none;}
#playLevelFailed .pm-slot-svg rect{fill:url(#sqHoleDark);}
/* button face a touch brighter + base darker so the squircle pops off the
   blue pocket the way the blue button pops off the cream one in prematch */
#playLevelFailed .pm-bstr .sq-face{fill:url(#sqBlueBright);}
#playLevelFailed .pm-bstr.selected .sq-face{fill:url(#sqGreen);}
#playLevelFailed .pm-bstr .sq-base{fill:#142e6b;}
#playLevelFailed .pm-bstr.selected .sq-base{fill:#0b7d35;}

/* the lost-life block: dark sunken sub-frame, no cream cant */
#playLevelFailed .pm-subframe2{background:linear-gradient(180deg,#2c2360,#473c8a);border:none;
         box-shadow:0 0 0 2px #2c2360,inset 0 3px 7px rgba(0,0,0,.45),inset 0 1px 0 rgba(255,255,255,.12);}
#playLevelFailed .pm-goal{gap:18px;}
#playLevelFailed .pm-subframe2 .pm-goal-cap{color:#cdbfff;text-shadow:0 1px 1px rgba(0,0,0,.5);}
#playLevelFailed .pm-goal-row{position:relative;justify-content:center;}
/* viewBox is tightened to the heart shape, so the box now hugs it — keeps the
   shape ~the same visual size and lets the symmetric padding centre LIFE LOST. */
#playLevelFailed .pm-life-heart{width:76px;height:76px;flex:0 0 auto;filter:drop-shadow(0 4px 4px rgba(0,0,0,.3));}
/* "No lives" message: one line */
#playLevelFailed .pm-nolives{white-space:nowrap;font-size:14px;}
/* -1 centred inside the heart, white with a dark-red outline/shadow.
   Selector carries id+2-class specificity so it beats the cloned
   `#playLevelFailed .pm-subframe .pm-goal-num` rule (which would otherwise
   repaint the number brown). */
#playLevelFailed .pm-subframe2 .pm-life-num{position:absolute;left:50%;top:50%;
         transform:translate(-50%,-50%);
         font-size:30px;font-weight:900;color:#fff;
         -webkit-text-stroke:2.5px #961e2d;paint-order:stroke;
         filter:drop-shadow(0 2px 0 rgba(150,30,45,.55));}

/* ---- Timer booster (+25s): auto-fire FX --------------------------------- */
/* Spent auto booster: the button stays in the bar but goes grey + dead. */
.play-booster.used {
  filter: grayscale(1) brightness(.8);
  cursor: default;
  pointer-events: none;
}
.play-booster.used .play-booster-ico { opacity: .75; }
.play-booster.used .play-booster-count { background: #6b7280; }

/* Full-screen FX layer: hourglass flight, "+25 СЕК", sparks. Above the HUD,
   below nothing that matters mid-level (overlays are hidden while it plays). */
.tb-layer { position: fixed; inset: 0; z-index: 240; pointer-events: none; }

/* Flying hourglass — positioned every frame via transform (see tbFlyQuad). */
.tb-hourglass {
  position: absolute; left: 0; top: 0;
  width: 92px; height: 92px; object-fit: contain;
  will-change: transform, opacity;
  filter: drop-shadow(0 5px 9px rgba(0,0,0,.4));
}

/* "+25 СЕК" stamp: pops in with an overshoot, hangs, floats up and fades. */
.tb-plus {
  position: absolute;
  font-size: 46px; font-weight: 900; letter-spacing: 1px; white-space: nowrap;
  color: #ffdd55;
  -webkit-text-stroke: 2.5px #7a4a00; paint-order: stroke;
  text-shadow: 0 3px 0 rgba(122,74,0,.55), 0 0 26px rgba(255,200,60,.65);
  animation: tb-plus-in 1.25s cubic-bezier(.25,1,.4,1) both;
}
@keyframes tb-plus-in {
  0%   { opacity: 0; transform: translate(-50%,-50%) scale(.25); }
  16%  { opacity: 1; transform: translate(-50%,-50%) scale(1.22); }
  28%  { transform: translate(-50%,-50%) scale(1); }
  70%  { opacity: 1; transform: translate(-50%,-58%) scale(1); }
  100% { opacity: 0; transform: translate(-50%,-115%) scale(.9); }
}

/* Glowing spark flying into the HUD timer (path driven by tbFlyQuad). */
.tb-spark {
  position: absolute; left: 0; top: 0;
  width: 16px; height: 16px; border-radius: 50%;
  background: radial-gradient(circle, #fffbe8 0 30%, #ffd94d 55%, rgba(255,217,77,0) 72%);
  box-shadow: 0 0 14px 5px rgba(255,196,64,.75);
  will-change: transform;
}

/* HUD timer reactions: a tiny tick per arriving spark, a big pop + golden
   glow when the time is actually credited. Keyframes must carry the timer's
   own base transform (translate(-50%, calc(-50% - 2px))) or it would jump. */
.pt-ov.pt-timer.pt-timer-tick {
  animation: tb-timer-tick .18s ease-out;
}
@keyframes tb-timer-tick {
  0%, 100% { transform: translate(-50%, calc(-50% - 2px)) scale(1); }
  50%      { transform: translate(-50%, calc(-50% - 2px)) scale(1.07); }
}
.pt-ov.pt-timer.pt-timer-boost {
  animation: tb-timer-boost .55s cubic-bezier(.3,1.6,.4,1);
}
@keyframes tb-timer-boost {
  0%   { transform: translate(-50%, calc(-50% - 2px)) scale(1); }
  35%  { transform: translate(-50%, calc(-50% - 2px)) scale(1.24);
         box-shadow: 0 4px 0 var(--pt-timer-shadow), 0 0 26px rgba(255,220,90,.95),
                     inset 0 2px 0 rgba(255,255,255,.6); }
  100% { transform: translate(-50%, calc(-50% - 2px)) scale(1); }
}

/* ====================================================================
   ЭКСПЕРИМЕНТ: тайм-бонус (CFG.TIME_BONUS в play.js). Монеты из таймера
   встают на пустые клетки и ныряют за экран. Слой и траектории — JS
   (playTimeBonusFx); тут только внешний вид монет/хвоста/частиц.
   ==================================================================== */
.tz-layer { position: fixed; inset: 0; z-index: 240; pointer-events: none; }

/* Монета: спрайтшит level complete (20 кадров 5×4, листает JS). */
.tz-coin { position: absolute; left: 0; top: 0; will-change: transform; }
.tz-coin-spr {
  width: 100%; height: 100%;
  background-image: url("icons/UI/coin sprites.webp");
  background-repeat: no-repeat;
  will-change: transform, background-position;
  filter: drop-shadow(0 4px 7px rgba(0,0,0,.35));
}

/* Хвост-лента (а-ля Unity TrailRenderer): рисуется на общем canvas'е
   сужающимся полигоном по истории точек (drawTrail в play.js). */
.tz-canvas {
  position: absolute; inset: 0; width: 100%; height: 100%;
  mix-blend-mode: plus-lighter;
  pointer-events: none;
}

/* «Золотая пыль»: мелкие (1.5–3px, размер задаёт JS) пылинки вдоль полёта,
   отстают от монеты и медленно оседают. */
.tz-part {
  position: absolute; width: 2px; height: 2px; border-radius: 50%;
  background: radial-gradient(circle, #fffdf2 0 45%, #ffd94d 75%, rgba(255,217,77,0) 100%);
  box-shadow: 0 0 3px 1px rgba(255,206,76,.65);
  mix-blend-mode: plus-lighter;
  pointer-events: none; will-change: transform, opacity;
}

/* Вспышка на клетке в момент посадки монеты. */
.tz-land {
  position: absolute; border-radius: 50%;
  background: radial-gradient(circle, rgba(255,240,180,.9) 0 30%,
              rgba(255,205,70,.4) 60%, rgba(255,205,70,0) 75%);
  mix-blend-mode: plus-lighter;
  pointer-events: none; will-change: transform, opacity;
}

/* ====================================================================
   Buyable booster slot — unlocked but none owned. Shows the booster
   faded with a green (+) badge; tapping opens the booster shop.
   Applies on both the prematch (#playStart) and level-failed screens.
   ==================================================================== */
#playStart .pm-bstr.buyable,
#playLevelFailed .pm-bstr.buyable{cursor:pointer;}
#playStart .pm-bstr.buyable .pm-bstr-ico,
#playLevelFailed .pm-bstr.buyable .pm-bstr-ico{opacity:.4;filter:grayscale(.15) drop-shadow(0 1px 1px rgba(0,0,0,.3));}
#playStart .pm-bstr.buyable .sq-face,
#playLevelFailed .pm-bstr.buyable .sq-face{opacity:.72;}
#playStart .pm-bstr-badge.pm-bstr-plus,
#playLevelFailed .pm-bstr-badge.pm-bstr-plus{
         background:linear-gradient(180deg,#2fdd6d,#12aa4c);color:#fff;
         font-size:22px;font-weight:900;line-height:0;padding-bottom:2px;
         box-shadow:0 2px 0 #0b7d35,0 0 0 1.5px rgba(15,33,78,.5);}

/* ====================================================================
   Booster shop window (#playShop) — reuses the prematch plate, no
   hexagon/goal/booster-row. Title = booster name; the frame holds a big
   booster icon (X1 badge) + a short description; the bottom button buys
   one for coins (price white when affordable, red when not).
   ==================================================================== */
#playShop{
  --play-top:#2fdd6d; --play-bottom:#12aa4c; --play-shadow:#0b7d35;
  --play-text-shadow:#0f552d;
  z-index:210;
}
#playShop.play-overlay{background:linear-gradient(180deg,#2c2658,#1d1840);
  backdrop-filter:none;-webkit-backdrop-filter:none;}
#playShop.pm-anim-in .pm-wrap{animation:pm-zoom-in .26s cubic-bezier(.22,.68,.36,1) both;
  will-change:transform,opacity;}
#playShop .pm-wrap{position:relative;width:100%;max-width:392px;}
#playShop .pm-box{position:relative;width:100%;filter:drop-shadow(0 14px 22px rgba(0,0,0,0.5));}
#playShop .pm-box svg.pm-plate{display:block;width:100%;height:auto;}
#playShop .pm-ov{position:absolute;}

/* booster name title, centred where the hexagon/difficulty used to sit */
#playShop .pm-head-title{position:absolute;left:50%;top:8.33%;transform:translate(-50%,-50%);
         font-size:30px;font-weight:900;letter-spacing:.5px;white-space:nowrap;z-index:5;pointer-events:none;
         color:#efffc9;-webkit-text-stroke:2px #14245e;paint-order:stroke;
         filter:drop-shadow(0 0.07em 0 rgba(0,0,0,.45));}

#playShop .pm-close{position:absolute;z-index:6;top:1%;right:1.9%;
         width:40px;height:40px;border:none;border-radius:50%;cursor:pointer;padding:0;
         display:flex;align-items:center;justify-content:center;
         background:linear-gradient(180deg,#ff5a5a,#ec1c2e);
         box-shadow:0 4px 0 #b31221,0 0 0 1.5px #0f214e,0 4px 0 1.5px #0f214e,inset 0 2px 0 rgba(255,255,255,.35);
         transition:transform .08s,box-shadow .12s;}
#playShop .pm-close:active{transform:translateY(3px);
         box-shadow:0 1px 0 #b31221,0 0 0 1.5px #0f214e,0 1px 0 1.5px #0f214e,inset 0 2px 0 rgba(255,255,255,.3);}
#playShop .pm-close svg{width:17px;height:17px;filter:drop-shadow(0 2px 0 rgba(150,30,45,.55));}

/* big frame (dark socket): a cream card with the booster icon, description below */
#playShop .pm-frame--shop{left:7.1%;right:7.1%;top:15.22%;height:60.87%;padding:22px;box-sizing:border-box;
         display:flex;flex-direction:column;align-items:center;justify-content:flex-start;gap:0;}
#playShop .shop-card{box-sizing:border-box;width:100%;background:#f9efc9;border-radius:20px;border:2px solid #e4cf91;
         padding:22px 20px;display:flex;flex-direction:column;align-items:center;justify-content:center;
         box-shadow:inset 0 2px 4px rgba(255,255,255,.7),inset 0 -3px 7px rgba(159,130,60,.35),0 2px 0 rgba(0,0,0,.25);}
#playShop .shop-hero{position:relative;display:flex;align-items:center;justify-content:center;}
#playShop .shop-ico{width:150px;height:150px;object-fit:contain;filter:drop-shadow(0 6px 8px rgba(0,0,0,.28));}
#playShop .shop-x1{position:absolute;right:-6px;bottom:2px;min-width:36px;height:36px;padding:0 8px;
         display:flex;align-items:center;justify-content:center;border-radius:18px;
         background:linear-gradient(180deg,#ffd24a,#f0a81f);color:#5a3a08;
         font-size:19px;font-weight:900;letter-spacing:.5px;
         box-shadow:0 3px 0 rgba(0,0,0,.28),inset 0 1px 0 rgba(255,255,255,.5);}
#playShop .shop-desc{flex:1;display:flex;align-items:center;justify-content:center;
         max-width:280px;margin:14px 0 0;text-align:center;font-size:17px;font-weight:800;line-height:1.35;
         color:#ffe2c4;-webkit-text-stroke:1px #14245e;paint-order:stroke;filter:drop-shadow(0 0.06em 0 rgba(0,0,0,.45));}

/* buy button: label on top, coin price below (stacked) */
#playShop .pm-play--shop{left:11.22%;right:11.22%;top:80.62%;height:12.32%;border:none;border-radius:18px;cursor:pointer;
         display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;
         background:linear-gradient(180deg,var(--play-top),var(--play-bottom));color:#efffc9;line-height:1;
         box-shadow:0 6px 0 var(--play-shadow),0 0 0 1.5px #0f214e,0 6px 0 1.5px #0f214e,inset 0 3px 0 rgba(255,255,255,.45);
         transition:transform .08s,box-shadow .12s;}
#playShop .pm-play--shop:active{transform:translateY(4px);box-shadow:0 2px 0 var(--play-shadow),0 0 0 1.5px #0f214e,0 2px 0 1.5px #0f214e,inset 0 3px 0 rgba(255,255,255,.4);}
#playShop .pm-play-label{display:inline-flex;align-items:center;white-space:nowrap;
         font-size:26px;font-weight:900;letter-spacing:1px;
         -webkit-text-stroke:1.5px var(--play-text-shadow);paint-order:stroke;
         filter:drop-shadow(0 0.06em 0 var(--play-text-shadow));}
#playShop .shop-price{display:inline-flex;align-items:center;gap:6px;
         font-family:inherit;font-variant-numeric:lining-nums tabular-nums;font-size:19px;font-weight:900;
         -webkit-text-stroke:0.9px var(--play-text-shadow);paint-order:stroke;filter:drop-shadow(0 0.06em 0 var(--play-text-shadow));}
#playShop .shop-price svg{width:20px;height:20px;-webkit-text-stroke:0;filter:drop-shadow(0 1px 1px rgba(0,0,0,.35));}
/* price colour: white when affordable, red when the player can't afford it */
#playShop .shop-price b{color:#ffffff;}
#playShop .pm-play--shop.cant .shop-price b{color:#ff4d3d;-webkit-text-stroke-color:#5a0f0a;}

/* --- Booster shop: purchase confirmation ---------------------------------- */
/* checkmark badge (replaces the X1 corner badge once bought) */
#playShop .shop-check{display:none;position:absolute;right:-6px;bottom:2px;
         width:44px;height:44px;align-items:center;justify-content:center;border-radius:50%;
         background:linear-gradient(180deg,#2fdd6d,#12aa4c);
         box-shadow:0 3px 0 #0b7d35,0 0 0 2px rgba(255,255,255,.85),inset 0 2px 0 rgba(255,255,255,.4);}
#playShop .shop-check svg{width:26px;height:26px;}
#playShop.bought .shop-x1{display:none;}
#playShop.bought .shop-check{display:flex;animation:shop-pop .2s cubic-bezier(.2,.9,.35,1.4) both;}
@keyframes shop-pop{from{transform:scale(0);opacity:0;}to{transform:scale(1);opacity:1;}}

/* buy button switches to an inert checkmark once bought */
#playShop .shop-buy-check{display:none;color:#eafff0;}
#playShop .shop-buy-check svg{width:34px;height:34px;filter:drop-shadow(0 0.06em 0 var(--play-text-shadow));}
#playShop.bought .pm-play-label,
#playShop.bought .shop-price{display:none;}
#playShop.bought .shop-buy-check{display:inline-flex;animation:shop-pop .2s cubic-bezier(.2,.9,.35,1.4) both;}
#playShop.bought .pm-play--shop{cursor:default;pointer-events:none;filter:brightness(.98);}
#playShop.bought .pm-play--shop:active{transform:none;}

/* --- Booster shop: zoom-out close + purchase star swarm ------------------- */
@keyframes pm-zoom-out{from{opacity:1;transform:scale(var(--pm-scale, 1));}to{opacity:0;transform:scale(calc(var(--pm-scale, 1) * .9));}}
#playShop.pm-anim-out .pm-wrap{animation:pm-zoom-out .22s cubic-bezier(.4,0,.7,.4) both;
  will-change:transform,opacity;}
/* star sparkles that fly up over the booster icon on purchase */
.shop-star{position:fixed;z-index:10000;pointer-events:none;
  will-change:transform,opacity;filter:drop-shadow(0 0 4px rgba(255,220,120,.95));}
.shop-star svg{display:block;width:100%;height:100%;overflow:visible;}
/* pure-white flash of the booster icon on purchase (fades to reveal colour) */
#playShop .shop-ico-flash{position:absolute;left:0;top:0;width:150px;height:150px;
  object-fit:contain;pointer-events:none;z-index:3;
  filter:brightness(0) invert(1) drop-shadow(0 0 10px rgba(255,255,255,.9));}

/* ====================================================================
   Interlevel backdrop — cozy royal castle kitchen (vector/Disney).
   Shown behind the Level Complete (#playWin) and Level Failed
   (#playLevelFailed) windows between levels. `cover` + centred keeps the
   central hearth framed in both portrait and landscape; the warm dark
   gradient on top keeps the card/banner readable. Placed at EOF so it
   overrides the earlier solid-gradient backdrops on these overlays.
   ==================================================================== */
#playWin.play-overlay,
#playLevelFailed.play-overlay {
  background:
    linear-gradient(rgba(18, 11, 6, 0.42), rgba(18, 11, 6, 0.60)),
    url("backgrounds/castle_kitchen.webp") center center / cover no-repeat fixed;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}

/* ====================================================================
   Keyhole transitions (keyhole.js) — маска «замочная скважина».
   #khShutter — полноэкранная шторка поверх всего play-UI (оверлеи z200,
   конфетти z250, tb-layer z240 → шторка z320). Пока видима — глотает
   клики: ввод во время перехода заблокирован. Сам рисунок (виньетка +
   дыра-скважина) — инлайн-SVG, анимируется из keyhole.js.
   ==================================================================== */
#khShutter {
  position: fixed; inset: 0; z-index: 320;
  display: none; pointer-events: auto;
}
#khShutter svg { display: block; width: 100%; height: 100%; }

/* Prematch живёт на кухне (та же castle_kitchen, что за win/fail-экранами):
   keyhole открывает её, затем pm-anim-in приводит окно. pm-prematch уже
   прячет доску — фон меняем тем же классом (перещёлкивается за закрытой
   шторкой, скачка не видно). */
body.play-mode.pm-prematch {
  background-image:
    linear-gradient(rgba(18, 11, 6, 0.30), rgba(18, 11, 6, 0.52)),
    url("backgrounds/castle_kitchen.webp");
}

/* Пока скважина открывает новый экран, его UI придержан (opacity, чтобы
   layout/fitBoard мерились как обычно); снимается перед pm-anim-in /
   launch-анимацией — те стартуют со своих keyframe-состояний (both). */
.play-overlay.kh-hold .pm-wrap,
.play-overlay.kh-hold .meta-top { opacity: 0; }
body.kh-stage-hold .play-top,
body.kh-stage-hold #boardFrame,
body.kh-stage-hold .play-bottom { opacity: 0; }

/* Перед закрытием скважины текущее окно быстро растворяется (kh-out,
   см. dismissTopWindow в play.js) — шторка закрывается над голым фоном,
   а не над UI. transition в целевом состоянии срабатывает на добавление
   класса; pm-anim-in снимается до этого, чтобы animation не перебила. */
.play-overlay.kh-out .pm-wrap,
.play-overlay.kh-out .meta-top,
.play-overlay.kh-out .lc-wrap,
.play-overlay.kh-out .lc-topbar-wrap { opacity: 0; transition: opacity .18s ease; }

/* ====================================================================
   МОБИЛЬНЫЙ LANDSCAPE (телефон на боку, высота ≤ 540px).
   Колонка сохраняется, но HUD и бустеры ужимаются, чтобы доска получила
   максимум высоты (fitBoard() сам пересчитает --view-scale по resize).
   Плашки prematch/fail/shop (SVG 392×552 — выше вьюпорта) ужимаются
   через --pm-scale, вкомпонованный в pm-zoom-in/out (см. keyframes).
   Секция в КОНЦЕ файла: перебивает базовые правила той же специфичности.
   ==================================================================== */
/* Порог поднят 540->700: небольшие альбомные вьюпорты (напр. 800x600 и
   десктопные айфреймы) тоже получают колоночный HUD — поле на максимум. */
@media (orientation: landscape) and (max-height: 860px) {
  body.play-mode .app { padding: 4px 8px; gap: 2px; }

  /* --- верхний HUD: колонка у ЛЕВОГО края, ВНЕ потока — вся высота доске.
     Сам .play-top остаётся баром оригинальных пропорций (×0.6 → 312px):
     из SVG-рамки клипом оставлен только ГЕКС с КК — вся %-геометрия слоёв
     КК (pt-hexfx / pt-kk / pt-kk-rim) работает как в портрете без
     пересчёта. Остальные слоты разложены колонкой ПОД гексом абсолютными
     позициями (центр столбца x=36px). Бокс шире видимой части, поэтому
     pointer-events отдаём только кнопкам. --- */
  body.play-mode .play-top {
    position: fixed; transform: none;
    /* бокс встаёт так, что вершина гекса (5px от верха бокса) == верх доски;
       --board-top/-left/--hud-mid экспортирует fitBoard() (script.js) */
    top: calc(var(--board-top, 44px) - 5px);
    left: 8px;                                        /* фолбэк без env() */
    left: max(8px, env(safe-area-inset-left, 0px));   /* бровь/чёлка слева */
    width: 312px; max-width: none; margin: 0; z-index: 5;
    pointer-events: none;
    /* высота НЕ фиксируется: бокс = высоте рамки (in-flow svg), иначе
       %-геометрия слоёв КК расходится с масштабом рамки */
  }
  /* гекс со всеми слоями КК уезжает вправо, к верхне-левому углу доски:
     правая кромка гекса в 20px от видимой кромки дерева (гекс: 69.7px + 20);
     `translate` не конфликтует с transform-анимациями слоёв */
  .pt-frame, .pt-frame-m, .pt-hexfx, .pt-kk, .pt-kk-rim, .pt-lvl {
    translate: calc(var(--board-left, 233px) - 90px
                    - max(8px, env(safe-area-inset-left, 0px))) 0;
  }
  /* обод над КК: 66px = гекс с обводкой при ширине 312 (перемычка — с 66.0) */
  .pt-kk-rim { clip-path: inset(0 calc(100% - 66px) 0 0); }
  /* рамка: ЛЕВАЯ половина гекса (центр x=36px) + её зеркальная копия справа —
     правая грань портретного гекса вливается в плашку, в svg её нет */
  .pt-frame { clip-path: inset(0 calc(100% - 36px) 0 0); }
  .pt-frame-m {
    display: block; position: absolute; left: 0; top: 0;
    width: 100%; height: auto; pointer-events: none;
    clip-path: inset(0 calc(100% - 36px) 0 0);
    transform: scaleX(-1); transform-origin: 36px 50%;
    filter: drop-shadow(0 6px 5px rgba(0, 0, 0, 0.224));
  }
  /* колонка пилюль: по левому краю, центр по ВЕРТИКАЛИ экрана (без учёта
     гекса — он живёт у доски). Экранный top = play-top top + локальный top,
     поэтому из --hud-mid вычитается позиция бокса (--board-top - 5px) */
  .pt-timer  { left: 3px; transform: none;
               top: calc(var(--hud-mid, 188px) - 67px - var(--board-top, 44px));
               width: 58px; height: 30px; border-radius: 10px; }
  .pt-moves  { left: 3px; transform: none; width: 58px;
               top: calc(var(--hud-mid, 188px) - 29px - var(--board-top, 44px));
               box-sizing: border-box; padding: 4px 0;
               background: linear-gradient(180deg, #2c2360, #473c8a);
               border: 1.5px solid #241c52; border-radius: 12px; }
  .pt-btn    { width: 34px; height: 30px; border-radius: 10px; font-size: 14px;
               pointer-events: auto; }
  .pt-exit   { left: 3px; transform: none;
               top: calc(var(--hud-mid, 188px) + 9px - var(--board-top, 44px)); }
  .pt-replay { left: 3px; transform: none;
               top: calc(var(--hud-mid, 188px) + 47px - var(--board-top, 44px)); }
  .pt-exit:active, .pt-replay:active { transform: translateY(1px); }
  .pt-lvl-cap   { font-size: 7px; margin-bottom: 1px; }
  .pt-lvl-num   { font-size: 15px; }
  .pt-ic        { width: 14px; height: 14px; stroke-width: 2.2; }
  .pt-timer-cap { font-size: 6px; margin-bottom: 1px; }
  .pt-timer-val { font-size: 13px; }
  .pt-moves-cap { font-size: 6px; margin-bottom: 1px; }
  .pt-moves-num { font-size: 14px; }
  /* базовые keyframes таймера зашивают translate(-50%) центрированного
     гнезда — в колонке уносили бы пилюлю за край; scale-only варианты */
  .pt-timer.pt-timer-warn { animation-name: ptPulse-ls; }
  .pt-ov.pt-timer.pt-timer-tick { animation-name: tb-timer-tick-ls; }
  .pt-ov.pt-timer.pt-timer-boost { animation-name: tb-timer-boost-ls; }
  /* доска не должна заезжать под боковые колонки: сужаем stage полями
     (+ те же safe-area сдвиги, что и у колонок) */
  body.play-mode .stage {
    width: auto;               /* база даёт width:100% — с полями вылезала бы вправо */
    margin: 0 74px;
    margin-left:  calc(74px + env(safe-area-inset-left, 0px));
    margin-right: calc(74px + env(safe-area-inset-right, 0px));
  }

  /* --- бустеры: компактная вертикальная колонка у правого края, ВНЕ потока
     (панель больше не отнимает высоту у stage — fitBoard() увеличит доску;
     по бокам в landscape всё равно пусто) --- */
  body.play-mode .play-bottom {
    position: fixed;
    top: 50%;
    /* симметрия с левым блоком: зазор доска→бустеры == зазор пилюли→доска.
       Правый край пилюль = max(8,env)+3+58 = max(8,env)+61, значит
       left = board-right + (board-left − max(8,env) − 61).
       Фолбэк без var()/env(): просто правый край */
    right: 8px;
    right: auto;
    left: calc(var(--board-right, 580px) + var(--board-left, 233px)
               - max(8px, env(safe-area-inset-left, 0px)) - 61px);
    transform: translateY(-50%);
    flex-direction: column;
    gap: 8px; margin: 0; min-height: 0;
    z-index: 5;                /* под оверлеями (z 200) */
  }
  .play-booster {
    width: 42px; height: 42px;
    box-shadow:
      0 4px 0 #1d2c6b,
      0 6px 8px rgba(0,0,0,0.45),
      inset 0 3px 4px rgba(255,255,255,0.55),
      inset 0 -3px 6px rgba(0,0,0,0.40);
  }
  .play-booster-ico { width: 24px; height: 24px; }
  .play-booster-count { top: -4px; right: -4px; min-width: 14px; height: 14px; padding: 0 4px; font-size: 9px; border-radius: 7px; }

  /* --- плашки prematch / fail / level-failed / shop --- */
  body.play-mode { --pm-scale: 0.7; }
  #playStart .pm-wrap, #playFail .pm-wrap,
  #playLevelFailed .pm-wrap, #playShop .pm-wrap { transform: scale(var(--pm-scale)); }

  /* --- мета-топбар над fail-окнами: в альбоме плашка (центр) залезала под
     центрированный топбар (fixed, z-index 6) — его SVG-рамка перехватывала
     тапы по крестику плашки → софтлок. Паркуем топбар компактно у ЛЕВОГО
     края (центр остаётся плашке); drop-анимация без сдвига -50% --- */
  #playFail .meta-top, #playLevelFailed .meta-top {
    max-width: 230px; top: 4px; right: auto;
    left: 8px;                                        /* фолбэк без env() */
    left: max(8px, env(safe-area-inset-left, 0px));   /* бровь слева */
    padding: 0; transform: none;
  }
  #playFail.pm-anim-in .meta-top, #playLevelFailed.pm-anim-in .meta-top {
    animation: mt-drop-ls .42s cubic-bezier(.22,.9,.32,1) .04s both;
  }
  #playFail .mt-lives-num,  #playLevelFailed .mt-lives-num  { font-size: 11px; }
  #playFail .mt-slot-val,   #playLevelFailed .mt-slot-val   { font-size: 10px; }
  #playFail .mt-coins-hit,  #playLevelFailed .mt-coins-hit  { height: 26px; }
}
@keyframes mt-drop-ls { from { transform: translate(0,-160%); } to { transform: translate(0,0); } }
@keyframes ptPulse-ls { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.06); } }
@keyframes tb-timer-tick-ls { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.07); } }
@keyframes tb-timer-boost-ls {
  0%   { transform: scale(1); }
  35%  { transform: scale(1.24);
         box-shadow: 0 4px 0 var(--pt-timer-shadow), 0 0 26px rgba(255,220,90,.95),
                     inset 0 2px 0 rgba(255,255,255,.6); }
  100% { transform: scale(1); }
}

/* совсем низкие вьюпорты (iPhone SE и т.п. с браузерным хромом) */
@media (orientation: landscape) and (max-height: 420px) {
  body.play-mode { --pm-scale: 0.58; }
  /* (max-width для play-top убран: колонка фикс. 312px с клипом до гекса,
     сжатие ломало масштаб рамки против %-геометрии слоёв КК) */
}
@media (orientation: landscape) and (max-height: 350px) {
  body.play-mode { --pm-scale: 0.5; }
}

/* ====================================================================
   ПОРТРЕТ: fail-окна. На невысоких экранах (телефон с браузерным хромом)
   центрированная плашка поднималась под мета-топбар (fixed, z-index 6) —
   его SVG-рамка перехватывала тапы по крестику → тот же софтлок, что был
   в альбоме. Отдаём топбару его полосу: оверлей получает padding-top на
   высоту бара (ширина-зависимая: (100vw−32px)·140/492 + top 16 + зазор),
   плашка центрируется в остатке. На совсем невысоких — ужимается.
   ==================================================================== */
@media (orientation: portrait) {
  #playFail, #playLevelFailed {
    padding-top: min(calc((100vw - 32px) * 0.2846 + 24px), 152px);
    box-sizing: border-box;
  }
}
@media (orientation: portrait) and (max-height: 700px) {
  body.play-mode { --pm-scale: 0.88; }
  #playFail .pm-wrap, #playLevelFailed .pm-wrap { transform: scale(var(--pm-scale)); }
}
@media (orientation: portrait) and (max-height: 580px) {
  body.play-mode { --pm-scale: 0.8; }
}
