/* The game screen: HUD, board and cards. The board cell size (--cw, --chh, whole pixels) comes from src/app/screen-game.js. */

#game {
  display: grid;
  padding: calc(var(--u) * 1.5) calc(var(--u) * 2);
}
.land #game {
  grid-template: 'top top top' auto 'left board right' 1fr / calc(var(--u) * 33) 1fr calc(var(--u) * 21);
}
.port #game {
  grid-template: 'top top' auto 'meter meter' auto 'board board' 1fr 'left right' auto / 1fr auto;
  row-gap: calc(var(--u) * 1);
}

/* ---- top bar ---- */
#g-top {
  grid-area: top;
  position: relative;
  display: grid;
  align-items: center;
  grid-template-columns: 1fr auto 1fr;
  gap: calc(var(--u) * 2);
  height: calc(var(--u) * 13);
}
#g-pause {
  grid-column: 1;
  justify-self: start;
}
#g-level {
  grid-column: 2;
}
#g-score {
  grid-column: 3;
  justify-self: end;
}
.land #g-meter {
  grid-area: top;
  justify-self: center;
  align-self: center;
}
.port #g-meter {
  grid-area: meter;
  justify-self: center;
}
.land #g-level {
  position: absolute;
  grid-column: 1 / -1;
  left: 50%;
  bottom: calc(var(--u) * -5.4);
  translate: -50% 0;
}
#g-level {
  --H: calc(var(--u) * 7.2);
  min-width: calc(var(--H) * 4);
  z-index: 2;
}

/* the meter: stars, the bar of moves and the number of moves on one parchment plate.
   In the plate art the paper goes from 25.5% to 88% of the height (the top ornament pushes it down), so the content is
   centered at 56.5% of the height, and every size is a share of the plate height (--mh) to stay clear of the frame.
   The whole block is centered between two equal margins. */
#g-meter {
  --mh: calc(var(--u) * 12.5);
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: calc(var(--mh) * 0.2);
  height: var(--mh);
  width: calc(var(--u) * 66);
  padding: calc(var(--mh) * 0.13) calc(var(--u) * 8) 0;
  background: var(--img-pill) center / 100% 100% no-repeat;
  z-index: 1;
}
.port #g-meter {
  --mh: calc(var(--u) * 14);
  width: calc(var(--u) * 82);
}
/* the stars give up width first when the word for "Moves" is long */
#g-meter .stars {
  display: flex;
  flex-direction: column;
  gap: calc(var(--mh) * 0.05);
  flex: 0 1 calc(var(--mh) * 1.45);
  min-width: calc(var(--mh) * 1.25);
}
/* the wider plate of the upright phone has room for a longer bar */
.port #g-meter .stars {
  flex-basis: calc(var(--mh) * 1.9);
}
#g-meter .stars > div {
  display: flex;
  justify-content: center;
  gap: calc(var(--mh) * 0.06);
}
#g-meter .stars img {
  width: calc(var(--mh) * 0.37);
  height: calc(var(--mh) * 0.37);
  transition: transform 0.2s;
}
#g-meter .bar {
  height: calc(var(--mh) * 0.105);
  border-radius: 99px;
  background: #4a2f8f;
  box-shadow: inset 0 0 0 calc(var(--u) * 0.3) #7a4a1a;
  overflow: hidden;
}
#g-meter .bar i {
  display: block;
  height: 100%;
  width: 100%;
  border-radius: 99px;
  background: linear-gradient(#ffe17a, #ffae1f);
  transform-origin: left;
  transition: transform 0.3s ease-out;
}
#g-meter .sep {
  flex: none;
  width: calc(var(--u) * 0.5);
  height: calc(var(--mh) * 0.36);
  background: rgba(150, 100, 45, 0.65);
  border-radius: 9px;
}
#g-meter .moves {
  display: flex;
  align-items: center;
  gap: calc(var(--mh) * 0.08);
  font-weight: 700;
  font-size: calc(var(--mh) * 0.32);
  white-space: nowrap;
}
#g-meter .moves img {
  height: calc(var(--mh) * 0.46);
}
#g-meter .moves b {
  font-size: calc(var(--mh) * 0.44);
  min-width: 1.2em;
  text-align: center;
}
#g-meter.low .moves b {
  color: #c8600a;
  animation: low-pulse 1.6s ease-in-out infinite;
}
@keyframes low-pulse {
  50% {
    transform: scale(1.18);
  }
}
#g-score {
  --H: calc(var(--u) * 10);
  min-width: calc(var(--u) * 28);
}
#g-score.bump {
  animation: bump var(--bump) ease-out;
}
@keyframes bump {
  40% {
    transform: scale(1.1);
  }
}
.port #g-score {
  --H: calc(var(--u) * 8);
  min-width: calc(var(--u) * 22);
}
.port #g-top {
  height: calc(var(--u) * 12);
}
.port #g-pause {
  --D: calc(var(--u) * 10.5);
}

/* ---- side columns (landscape) / bottom bar (portrait) ---- */
#g-left {
  grid-area: left;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: calc(var(--u) * 2);
  position: relative;
}
#g-right {
  grid-area: right;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: calc(var(--u) * 3);
}
.port #g-left {
  flex-direction: row;
  justify-content: flex-start;
  gap: calc(var(--u) * 0.5);
  min-width: 0;
}
.port #g-right {
  flex-direction: row;
  gap: calc(var(--u) * 1.5);
  padding-bottom: calc(var(--u) * 1);
}
.port #game .flick {
  width: calc(var(--u) * 22);
  flex: none;
}
.land #game .flick {
  width: calc(var(--u) * 31);
}
#g-streak {
  --H: calc(var(--u) * 9);
  min-width: 0;
  gap: calc(var(--u) * 0.4);
  transition: opacity 0.2s;
}
.port #g-streak {
  --H: calc(var(--u) * 7.5);
}
/* in portrait a word takes the place of the streak pill for a moment (they never sit on top of each other) */
.port #g-left:has(.word) #g-streak {
  opacity: 0;
}
#g-streak img {
  height: calc(var(--H) * 0.66);
  margin: 0 calc(var(--u) * -0.5);
  transition: transform 0.2s;
}
#g-streak img.on {
  animation: bump 0.3s ease-out;
}
#g-streak b {
  margin-left: calc(var(--u) * 1);
  min-width: 1.6em;
}

/* what the mascot asks for (world 2) */
#g-request {
  position: absolute;
  right: calc(var(--u) * -1);
  top: calc(var(--u) * 13);
  width: calc(var(--u) * 12.5);
  height: calc(var(--u) * 12.5);
  padding: calc(var(--u) * 1.6);
  border-radius: 50% 50% 50% 12%;
  background: #fff3d6;
  box-shadow:
    0 0 0 calc(var(--u) * 0.5) #c98a2e,
    0 calc(var(--u) * 0.6) calc(var(--u) * 1) var(--shadow);
  z-index: 1;
}
#g-request.x {
  animation: panel-in 0.3s cubic-bezier(0.3, 1.5, 0.5, 1) both;
}
#g-request img {
  width: 100%;
  height: 100%;
}
#g-request::after {
  content: '';
  position: absolute;
  right: calc(var(--u) * -2);
  top: calc(var(--u) * -2);
  width: calc(var(--u) * 5.5);
  height: calc(var(--u) * 5.5);
  background: url(../assets/ui/badge-star.webp) center / contain no-repeat;
}
.port #g-request {
  right: auto;
  left: calc(var(--u) * 16);
  top: calc(var(--u) * -8);
  width: calc(var(--u) * 10.5);
  height: calc(var(--u) * 10.5);
}

/* power buttons */
.power {
  position: relative;
  width: calc(var(--u) * 16);
  display: flex;
  flex-direction: column;
  align-items: center;
  transition:
    transform 0.08s ease-out,
    filter 0.15s;
}
.power .ic {
  width: 100%;
  aspect-ratio: 1;
  background: center / contain no-repeat;
}
.power .name {
  --img: var(--img-btn-2);
  --H: calc(var(--u) * 6.4);
  --ka: 5.565;
  --kr: 0.95;
  margin-top: calc(var(--u) * -2.8);
  min-width: calc(var(--u) * 18);
  font-size: calc(var(--u) * 3.5);
  color: var(--cream);
  font-weight: 700;
  white-space: nowrap;
}
.power .n {
  position: absolute;
  right: calc(var(--u) * -0.5);
  top: calc(var(--u) * -0.5);
  min-width: calc(var(--u) * 5.2);
  height: calc(var(--u) * 5.2);
  padding: 0 calc(var(--u) * 1);
  border-radius: 99px;
  display: grid;
  place-items: center;
  background: #5a35c8;
  color: #fff;
  font-weight: 700;
  font-size: calc(var(--u) * 3.2);
  box-shadow: 0 0 0 calc(var(--u) * 0.45) var(--gold);
}
.power.empty {
  filter: grayscale(0.85) brightness(0.72);
}
.power.armed .ic {
  animation: armed 0.9s ease-in-out infinite;
}
@keyframes armed {
  50% {
    transform: scale(1.08);
    filter: drop-shadow(0 0 calc(var(--u) * 1.5) rgba(var(--glow-strong), 1));
  }
}
.port .power {
  width: calc(var(--u) * 14.5);
}
/* (no wider than its button plus a little: a long name such as "Leuchtfeuer" gets a smaller font, it does not reach the
   next button or leave the screen) */
.power .name {
  max-width: calc(100% + var(--u) * 2.5);
}
.port .power .name {
  --H: calc(var(--u) * 5.6);
  min-width: calc(var(--u) * 14.5);
  max-width: calc(100% + var(--u) * 1);
  font-size: calc(var(--u) * 3.2);
  margin-top: calc(var(--u) * -2.4);
}

/* ---- board ---- */
#g-boardbox {
  grid-area: board;
  position: relative;
  z-index: 0;
  display: grid;
  place-items: center;
  min-width: 0;
  min-height: 0;
}
.land #g-boardbox {
  margin: calc(var(--u) * 4.6) 0 calc(var(--u) * 1);
}
#g-top,
#g-meter {
  z-index: 2;
} /* the HUD stays above the board: the lanterns of a win rise behind it */
#board {
  position: relative;
  display: grid;
  grid-template-columns: repeat(var(--cols), var(--cw));
  grid-template-rows: repeat(var(--rows), var(--chh));
  gap: var(--gap);
  transition: transform var(--zoom-time) ease-out;
}
#board.zoom {
  transform: scale(var(--zoom));
}
#board.peeking,
#board.busy {
  pointer-events: none;
}

.card {
  position: relative;
  width: var(--cw);
  height: var(--chh);
  perspective: calc(var(--cw) * 5);
  z-index: 1;
  transition: rotate 0.25s ease-out;
}
/* cards waiting to be dealt */
.card.pre {
  opacity: 0;
}
/* the shadow under a card: it stays on the table and spreads while the card rises in the middle of a turn */
.card::before {
  content: '';
  position: absolute;
  left: 7%;
  right: 7%;
  bottom: -5%;
  height: 15%;
  border-radius: 50%;
  background: radial-gradient(closest-side, rgba(24, 12, 60, 0.5), transparent);
  z-index: -1;
  pointer-events: none;
  transition: opacity 0.2s;
}
.card.hop::before {
  animation: shadow-hop var(--flip) ease-out;
}
@keyframes shadow-hop {
  45% {
    translate: 0 calc(var(--chh) * var(--lift));
    scale: 1.22 1.3;
    opacity: 0.6;
  }
}
/* a card in the air (dealt, swapped, celebrating or leaving) has no shadow on the table */
.card.pre::before,
.card.deal::before,
.card.top::before,
.card.rise::before {
  opacity: 0;
}
/* world 4: every card leans with the wind for a moment */
#board.windy .card {
  rotate: calc(var(--wind, 1) * 2.5deg);
}
.card.top {
  z-index: 3;
}
.card .flipper {
  position: absolute;
  inset: 0;
  transform-style: preserve-3d;
  transition:
    transform var(--flip) cubic-bezier(0.3, 1.45, 0.5, 1),
    rotate 0.12s ease-out,
    scale 0.1s ease-out;
}
.card .face {
  position: absolute;
  inset: 0;
  background: center / 100% 100% no-repeat;
  -webkit-backface-visibility: hidden;
  backface-visibility: hidden;
}
.card .back {
  background-image: var(--back);
}
.card .front {
  background-image: var(--img-card-front);
  transform: rotateY(180deg);
  display: grid;
  place-items: center;
}
/* The face turned away is also switched off at the middle of the turn, so nothing depends on backface-visibility alone.
   The turn overshoots, so it passes 90° at 12% of its time, not at half: switching later leaves the card empty. */
.card .back,
.card .front {
  transition: visibility 0s linear calc(var(--flip) * 0.12);
}
.card .front,
.card.up .back,
.card.done .back {
  visibility: hidden;
}
.card.up .front,
.card.done .front {
  visibility: visible;
}
.card .fig {
  width: 64%;
  height: 64%;
  margin-top: 7%;
  object-fit: contain;
}
.card.shadow .front {
  background-image: var(--img-card-moon);
}
/* world 5: the silhouette is an ink copy over the picture. When the pair is found the ink is wiped away from the
   bottom up and the color fills the card. Until then the picture under it stays hidden (no colored fringe). */
.card .fig.ink {
  position: absolute;
  filter: var(--shadow-ink);
  clip-path: inset(0 0 0 0);
  transition: clip-path 0.45s ease-out 0.15s;
}
.card.shadow.done .fig.ink {
  clip-path: inset(0 0 100% 0);
}
.card.shadow:not(.done) .fig:not(.ink) {
  visibility: hidden;
}
.card.gold .back {
  background-image: var(--img-card-gold);
}
/* (--dir: the card turns from the side that was touched) */
.card.up .flipper,
.card.done .flipper {
  transform: rotateY(calc(180deg * var(--dir, 1)));
}
/* the hop of a turn: the card rises a little in the middle of the flip */
/* (hop, shake and pulse move the card with translate / scale, not transform: a swap animation may be running on it) */
.card.hop {
  animation: hop var(--flip) ease-out;
}
@keyframes hop {
  45% {
    translate: 0 calc(var(--chh) * var(--lift) * -1);
    scale: 1.04;
  }
  80% {
    translate: 0 0;
    scale: 1.02 0.975; /* it settles with a tiny squash */
  }
}
/* under the finger the card sinks a little and leans toward it (--ax, --ay, --lean come from the touch point) */
.card.press .flipper {
  scale: var(--press);
  rotate: var(--ax, 0) var(--ay, 0) 0 var(--lean, 0deg);
}
.card.done {
  pointer-events: none;
}

/* the pulse of a pair (the class is "pulse", not "pop": .pop is the popup and gave the card a dark veil) */
.card.pulse {
  animation: card-pop var(--pop) cubic-bezier(0.3, 1.6, 0.5, 1);
}
/* (it starts with a short squeeze: the anticipation before the burst) */
@keyframes card-pop {
  9% {
    scale: 0.96;
  }
  40% {
    scale: var(--pop-scale);
  }
}
/* the creature of a pair hops inside its frame (never more than 8%) */
.card.pulse .fig {
  animation: fig-hop var(--pop) cubic-bezier(0.3, 1.5, 0.5, 1);
}
@keyframes fig-hop {
  10% {
    translate: 0 2%;
    scale: 1.04 0.95;
  }
  42% {
    translate: 0 -8%;
    scale: 0.97 1.06;
  }
  72% {
    translate: 0 0;
    scale: 1.03 0.97;
  }
}
/* the wave of light of a long streak: each card swells once, later the farther it is (--wave) */
.card.ripple .flipper {
  animation: card-ripple 0.36s ease-out var(--wave, 0s) both;
}
@keyframes card-ripple {
  40% {
    scale: 1.045;
  }
}
/* a miss: the two cards shake their heads once, gently (no red, no buzz) */
.card.miss {
  animation: no var(--wobble) ease-in-out;
}
/* (they also lose a little color while they shake) */
@keyframes no {
  20% {
    translate: -6% 0;
    filter: saturate(0.55) brightness(0.96);
  }
  45% {
    translate: 5% 0;
    filter: saturate(0.55) brightness(0.96);
  }
  70% {
    translate: -3% 0;
    filter: saturate(0.55) brightness(0.96);
  }
  88% {
    translate: 1.5% 0;
  }
}
.card.swapped {
  animation: swapped 0.7s ease-in-out;
}
@keyframes swapped {
  35% {
    filter: brightness(1.6);
  }
}
/* a matched card keeps a warm light on its paper: it reads as "lit", not just "open" */
.card .front::after {
  content: '';
  position: absolute;
  inset: 10% 10% 9%;
  border-radius: 16%;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.4s;
  box-shadow: inset 0 0 calc(var(--cw) * 0.16) calc(var(--cw) * 0.03) rgba(255, 186, 60, 0.85);
}
.card.done .front::after {
  opacity: 1;
}
.card.hint .flipper {
  animation: hint 1.1s ease-in-out infinite;
}
@keyframes hint {
  50% {
    scale: 1.06;
  }
}

/* the deal at the start and the lanterns leaving at the end */
.card.deal {
  animation: deal var(--deal) cubic-bezier(0.3, 1.5, 0.5, 1) backwards;
}
/* (each card flies from the mascot: --fx, --fy = how far away he is, --fr = how tilted it leaves his hands) */
@keyframes deal {
  from {
    opacity: 0;
    transform: translate(var(--fx, 0), var(--fy, 50%)) rotate(var(--fr, 0deg)) scale(0.35);
  }
  35% {
    opacity: 1;
  }
}
.card.rise {
  animation: rise var(--rise) cubic-bezier(0.5, 0, 0.8, 0.5) forwards;
}
@keyframes rise {
  20% {
    transform: translateY(calc(var(--chh) * 0.06));
  }
  100% {
    transform: translateY(-110vh) rotate(var(--tilt, 4deg));
    opacity: 0.9;
  }
}

/* locked by vines (world 3) */
.card .vines {
  position: absolute;
  inset: -6%;
  background: url(../assets/ui/vines.webp) center / 100% 100% no-repeat;
  pointer-events: none;
  opacity: 0;
  scale: 1.25;
  transition:
    opacity 0.25s,
    scale 0.3s;
}
.card .vines::after {
  content: '';
  position: absolute;
  left: 50%;
  bottom: -4%;
  width: 34%;
  aspect-ratio: 1;
  translate: -50% 0;
  background: url(../assets/ui/lock.webp) center / contain no-repeat;
}
.card.locked .vines {
  opacity: 1;
  scale: 1;
}
.card.locked .back {
  filter: brightness(0.8);
}
.card.nope {
  animation: nope 0.3s ease-in-out;
}
@keyframes nope {
  30% {
    translate: -4% 0;
  }
  65% {
    translate: 4% 0;
  }
}

/* the star badge of a requested pair (world 2) */
.card .badge {
  position: absolute;
  right: -6%;
  top: -4%;
  width: 34%;
  aspect-ratio: 1;
  background: url(../assets/ui/badge-star.webp) center / contain no-repeat;
  scale: 0;
  transition: scale 0.25s cubic-bezier(0.3, 1.8, 0.5, 1);
  pointer-events: none;
  z-index: 2;
}
.card.wanted .badge {
  scale: 1;
}

/* a word that pops next to the mascot ("Trio!"): beside the board, never on the cards */
.word {
  position: absolute;
  font-size: calc(var(--u) * 7.5);
  pointer-events: none;
  z-index: 6;
  white-space: nowrap;
  animation: word 1s cubic-bezier(0.2, 1.4, 0.4, 1) forwards;
}
.word.small {
  font-size: calc(var(--u) * 5.2);
}
.land .word {
  left: 50%;
  top: calc(var(--u) * 5.5);
  translate: -50% -50%;
}
.port .word {
  left: calc(var(--u) * 20);
  top: 50%;
  translate: 0 -50%;
  transform-origin: left center;
}
@keyframes word {
  0% {
    opacity: 0;
    transform: scale(0.4);
  }
  22% {
    opacity: 1;
    transform: scale(1.1);
  }
  35% {
    transform: scale(1);
  }
  78% {
    opacity: 1;
    transform: scale(1);
  }
  100% {
    opacity: 0;
    transform: translateY(-45%);
  }
}

/* the hand of the first level */
#g-hand {
  position: absolute;
  width: calc(var(--cw) * 0.7);
  aspect-ratio: 1;
  background: url(../assets/ui/hand.webp) center / contain no-repeat;
  pointer-events: none;
  z-index: 7;
  transition:
    left 0.45s cubic-bezier(0.4, 0, 0.2, 1),
    top 0.45s cubic-bezier(0.4, 0, 0.2, 1);
  animation: hand 1.1s ease-in-out infinite;
}
/* a ring opens under the fingertip: "tap here" */
#g-hand::before {
  content: '';
  position: absolute;
  left: 14%;
  top: 10%;
  width: 60%;
  aspect-ratio: 1;
  translate: -50% -50%;
  border-radius: 50%;
  border: calc(var(--u) * 0.6) solid rgba(var(--glow-strong), 0.95);
  animation: ripple 1.1s ease-out infinite;
}
@keyframes ripple {
  from {
    scale: 0.25;
    opacity: 1;
  }
  to {
    scale: 1.3;
    opacity: 0;
  }
}
/* the first level: nothing but the cards, the hand and the mascot until the first pair is found */
#g-meter,
#g-right,
#g-score,
#g-level {
  transition: opacity 0.4s;
}
.guided #g-meter,
.guided #g-right,
.guided #g-streak,
.guided #g-score,
.guided #g-level {
  opacity: 0;
  pointer-events: none;
}
@keyframes hand {
  50% {
    transform: translate(-8%, -10%) scale(0.94);
  }
}

/* the beam of the Beacon power */
.beam {
  position: absolute;
  height: calc(var(--u) * 3.2);
  border-radius: 99px;
  transform-origin: left center;
  background: linear-gradient(90deg, rgba(var(--glow-strong), 0.5), #fff8dc 85%, #fff);
  box-shadow: 0 0 calc(var(--u) * 2) rgba(var(--glow-strong), 0.9);
  pointer-events: none;
  z-index: 5;
  animation: beam 0.8s ease-out forwards;
}
/* it travels from the chosen card to its twin (the first 35% = FEEL.beacon.travel), stays a moment and fades */
@keyframes beam {
  0% {
    opacity: 1;
    scale: 0 1;
  }
  35% {
    opacity: 1;
    scale: 1 1;
  }
  65% {
    opacity: 1;
    scale: 1 1;
  }
  100% {
    opacity: 0;
    scale: 1 0.3;
  }
}
.gust {
  position: absolute;
  aspect-ratio: 1;
  translate: -50% -50%;
  background: url(../assets/ui/wind.webp) center / contain no-repeat;
  pointer-events: none;
  z-index: 4;
  opacity: 0;
  animation: gust calc(var(--warn) + 0.5s) ease-in-out forwards;
}
@keyframes gust {
  0% {
    opacity: 0;
    transform: translateX(-35%) scale(0.7);
  }
  30%,
  70% {
    opacity: 0.9;
  }
  100% {
    opacity: 0;
    transform: translateX(35%) scale(1.05);
  }
}

/* the points of a pair, rising small above it */
.plus {
  position: absolute;
  translate: -50% -70%;
  font-size: calc(var(--cw) * 0.26);
  font-weight: 700;
  white-space: nowrap;
  pointer-events: none;
  z-index: 6;
  animation: plus var(--plus) ease-out forwards;
}
@keyframes plus {
  0% {
    opacity: 0;
    transform: translateY(40%) scale(0.6);
  }
  18% {
    opacity: 1;
    transform: translateY(0) scale(1.1);
  }
  30% {
    transform: scale(1);
  }
  70% {
    opacity: 1;
  }
  100% {
    opacity: 0;
    transform: translateY(-90%);
  }
}
/* the orb of the score swallows each point of light */
#g-score img.gulp {
  animation: gulp 0.2s ease-out;
}
@keyframes gulp {
  40% {
    scale: 1.2 0.86;
  }
}
/* the last moves: the bar turns orange and the plate breathes at each move (nothing red, nothing over the screen) */
#g-meter.low .bar i {
  background: linear-gradient(#ffc27a, #f47a1f);
}
#g-meter.breath {
  animation: meter-breath 0.32s ease-out;
}
@keyframes meter-breath {
  40% {
    scale: 1.035;
  }
}
/* the ring that empties around the mascot while the cards are open */
.timering {
  position: absolute;
  aspect-ratio: 1;
  translate: -50% -50%;
  rotate: -90deg;
  overflow: visible;
  pointer-events: none;
  z-index: -1;
}
.timering circle {
  fill: none;
  stroke-width: 4;
  stroke-linecap: round;
}
.timering .rail {
  stroke: rgba(255, 240, 190, 0.22);
}
.timering .left {
  stroke: rgba(var(--glow-strong), 0.95);
  stroke-dasharray: 100;
  animation: drain var(--t) linear forwards;
}
@keyframes drain {
  to {
    stroke-dashoffset: 100;
  }
}
/* the ring that closes on the card chosen for the Beacon */
.aim {
  position: absolute;
  width: calc(var(--cw) * 1.2);
  aspect-ratio: 1;
  translate: -50% -50%;
  border-radius: 50%;
  border: calc(var(--u) * 0.6) solid rgba(var(--glow-strong), 0.95);
  pointer-events: none;
  z-index: 5;
  animation: aim var(--aim) ease-in forwards;
}
@keyframes aim {
  from {
    scale: 2;
    opacity: 0;
  }
  70% {
    opacity: 1;
  }
  to {
    scale: 0.9;
    opacity: 0;
  }
}
/* the lantern festival of a three-star win: the lanterns rise behind the result panel and can be caught */
.festival {
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
}
.flantern {
  position: absolute;
  top: 100%;
  width: calc(var(--u) * 13);
  aspect-ratio: 1;
  translate: -50% 0;
  background: url(../assets/ui/lantern.webp) center / contain no-repeat;
  filter: drop-shadow(0 0 calc(var(--u) * 1.6) rgba(var(--glow-strong), 0.9));
  pointer-events: auto;
  animation: fest-rise linear forwards;
}
/* its hint, for a moment, where the panel leaves room */
.festhint {
  position: absolute;
  z-index: 1;
  max-width: calc(var(--u) * 36);
  font-size: calc(var(--u) * 4.6);
  line-height: 1.1;
  text-align: center;
  word-break: keep-all; /* Japanese breaks only where the text allows it, never inside a word */
  pointer-events: none;
  animation: festhint 2.5s ease-out forwards;
}
.land .festhint {
  right: calc(var(--sx) + var(--u) * 5);
  top: calc(var(--sy) + var(--u) * 16);
}
.port .festhint {
  left: 50%;
  bottom: calc(var(--sy) + var(--u) * 4);
  max-width: 84%;
  translate: -50% 0;
}
@keyframes festhint {
  0% {
    opacity: 0;
    scale: 0.6;
  }
  12% {
    opacity: 1;
    scale: 1.08;
  }
  20% {
    scale: 1;
  }
  80% {
    opacity: 1;
  }
  100% {
    opacity: 0;
  }
}
@keyframes fest-rise {
  to {
    transform: translate(var(--sway, 0), calc(var(--sh) * -1.25));
  }
}
/* with "Reduce motion" the lanterns appear in place instead of rising */
.flantern.still {
  translate: -50% -50%;
  animation-name: fest-still;
}
@keyframes fest-still {
  0% {
    opacity: 0;
    scale: 0.6;
  }
  15% {
    opacity: 1;
    scale: 1;
  }
  85% {
    opacity: 1;
  }
  100% {
    opacity: 0;
  }
}

/* Reduce motion */
.calm .card.hop::before,
.calm .card.pulse .fig,
.calm .card.ripple .flipper,
.calm #g-score img.gulp,
.calm #g-meter.breath,
.calm .aim,
.calm .card.hop,
.calm .card.pulse,
.calm .card.miss,
.calm .card.nope,
.calm .card.hint .flipper,
.calm #g-hand,
.calm #g-hand::before,
.calm .power.armed .ic,
.calm .gust {
  animation: none !important;
}
.calm .card.deal,
.calm .card.rise {
  animation-duration: 0.01s !important;
}
.calm .card.rise {
  opacity: 0.25;
}
.calm #board.zoom {
  transform: none;
}
.calm .card.press .flipper {
  rotate: none;
}
.calm #board.windy .card {
  rotate: none;
}
.calm .plus {
  animation-name: plus-calm;
}
@keyframes plus-calm {
  70% {
    opacity: 1;
  }
  100% {
    opacity: 0;
  }
}

/* End of css/game.css */
