﻿/* Layout base and the shared pieces: stage, buttons, ribbons, panels, popups.
   Every size is a multiple of --u, the stage unit set by src/app/layout.js:
   landscape stage = 160u x 90u at least, portrait stage = 90u x 160u at least. */

* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}
html,
body {
  height: 100%;
  overflow: hidden;
  background: var(--night);
}
body {
  font: 600 calc(var(--u) * 3.6) / 1.15 var(--font);
  color: var(--ink);
  -webkit-user-select: none;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
  overscroll-behavior: none;
}
button {
  font: inherit;
  color: inherit;
  border: 0;
  background: none;
  cursor: pointer;
}
img {
  display: block;
  -webkit-user-drag: none;
  pointer-events: none;
}

/* the background picture covers the whole window and never stretches out of proportion */
/* (#bg2: the background of the screen that is arriving, shown inside the growing circle of the transition) */
#bg,
#bg2 {
  position: fixed;
  inset: 0;
  background: var(--night) center / cover no-repeat;
}
#bg.dim::after,
#bg.tint::after,
#bg2.dim::after,
#bg2.tint::after {
  content: '';
  position: absolute;
  inset: 0;
  background: rgba(14, 8, 48, 0.35);
}
#bg.tint::after,
#bg2.tint::after {
  background: rgba(24, 10, 86, 0.26);
}
/* The light of the lanterns. It is a layer of its own right above the background picture, blended as light ("screen"):
   with the usual blending, amber over the indigo night turns into a dull dark patch instead of a glow. */
#glows {
  position: fixed;
  inset: 0;
  pointer-events: none;
  mix-blend-mode: screen;
}
#glows i {
  position: absolute;
  border-radius: 50%;
  translate: -50% -50%;
  opacity: 0;
  transition: opacity 0.35s;
  background: radial-gradient(closest-side, rgba(var(--glow), 0.95), rgba(var(--glow), 0.42) 50%, transparent);
}
#glows i.up {
  opacity: 0.5;
}
/* a lit lantern breathes, each one in its own time (--ph) */
#glows i.done {
  opacity: 0.85;
  animation: lit var(--breathe) ease-in-out var(--ph, 0s) infinite;
}
@keyframes lit {
  50% {
    opacity: 0.74;
    scale: 1.035;
  }
}
/* the light behind the whole board: it grows with every pair found, until the scene is lit for the win */
#glows em {
  position: absolute;
  border-radius: 50%;
  translate: -50% -50%;
  opacity: 0;
  transition: opacity 0.7s ease-out;
  background: radial-gradient(closest-side, rgba(var(--glow), 0.55), rgba(var(--glow), 0.2) 55%, transparent);
}
/* fireflies drifting behind the board, each with its own path and pace */
#glows .fly {
  position: absolute;
  width: calc(var(--u) * 1.5);
  aspect-ratio: 1;
  border-radius: 50%;
  background: radial-gradient(closest-side, #fffbd6, rgba(var(--glow-strong), 0.8) 40%, transparent);
  animation:
    fly-wander var(--wander) ease-in-out var(--ph) infinite alternate,
    fly-glow 5.5s ease-in-out var(--ph) infinite;
}
@keyframes fly-wander {
  to {
    transform: translate(var(--wx), var(--wy));
  }
}
@keyframes fly-glow {
  0%,
  100% {
    opacity: 0.15;
  }
  50% {
    opacity: 0.85;
  }
}
/* a shooting star crossing the sky (a pair found at the first try) */
#glows s {
  position: absolute;
  left: -14%;
  width: calc(var(--u) * 22);
  height: calc(var(--u) * 0.7);
  border-radius: 99px;
  rotate: 14deg;
  background: linear-gradient(90deg, transparent, rgba(255, 244, 200, 0.9) 80%, #fff);
  animation: shoot 0.9s ease-in forwards;
}
@keyframes shoot {
  from {
    opacity: 0;
  }
  15% {
    opacity: 1;
  }
  to {
    opacity: 0;
    transform: translateX(130vw);
  }
}
#glows.peeking i.up {
  animation: glow-breathe 1.5s ease-in-out infinite;
}
@keyframes glow-breathe {
  50% {
    opacity: 0.85;
  }
}
#glows i.rise {
  animation: glow-rise var(--rise) cubic-bezier(0.5, 0, 0.8, 0.5) forwards;
}
@keyframes glow-rise {
  to {
    transform: translateY(-110vh);
    opacity: 0;
  }
}
/* the burst of rays of a pair: behind the card, opening outward, turning only a little */
#glows b {
  position: absolute;
  border-radius: 50%;
  translate: -50% -50%;
  opacity: 0;
  animation: rays var(--rays) ease-out forwards;
  background: repeating-conic-gradient(from 0deg, rgba(var(--glow-strong), 0.75) 0 9deg, transparent 9deg 30deg);
  -webkit-mask-image: radial-gradient(circle, #000 20%, rgba(0, 0, 0, 0.5) 44%, transparent 68%);
  mask-image: radial-gradient(circle, #000 20%, rgba(0, 0, 0, 0.5) 44%, transparent 68%);
}
@keyframes rays {
  0% {
    opacity: 0;
    scale: 0.5;
  }
  22% {
    opacity: 1;
  }
  100% {
    opacity: 0;
    scale: 1.15;
    rotate: var(--rays-turn);
  }
}
#fx {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  z-index: 50;
}

/* a screen is the stage: centered, with whole-pixel edges */
.screen {
  position: fixed;
  left: var(--sx);
  top: var(--sy);
  width: var(--sw);
  height: var(--sh);
}
/* the screen that is leaving: it stays in view, under the new one, until the circle of the transition covers it */
.screen.out {
  pointer-events: none;
}
/* the ring of light at the edge of that circle. It is drawn small and scaled up (will-change keeps it cheap). */
.iris {
  position: fixed;
  width: 512px;
  height: 512px;
  margin: -256px 0 0 -256px;
  border-radius: 50%;
  pointer-events: none;
  z-index: 5;
  will-change: transform;
  background: radial-gradient(closest-side, transparent 86%, rgba(255, 200, 96, 0.5) 93%, rgba(255, 240, 190, 0.95) 97.5%, transparent 100%);
}
@keyframes screen-in {
  from {
    opacity: 0;
  }
}
@keyframes screen-out {
  to {
    opacity: 0;
  }
}

/* ---- text ---- */
.t-title {
  color: var(--cream);
  font-weight: 700;
  -webkit-text-stroke: calc(var(--u) * 0.7) var(--outline-red);
  paint-order: stroke fill;
  letter-spacing: 0.01em;
  white-space: nowrap;
}
.t-light {
  color: var(--cream);
  font-weight: 700;
  -webkit-text-stroke: calc(var(--u) * 0.6) var(--outline-indigo);
  paint-order: stroke fill;
}
/* loose text over the scene ("Tap to start", "+200", "Trio!"): white, so it reads on any background */
.t-glow {
  color: #fff;
  font-weight: 700;
  -webkit-text-stroke: calc(var(--u) * 0.7) #3b1c78;
  paint-order: stroke fill;
  text-shadow: 0 0 calc(var(--u) * 2) rgba(var(--glow), 0.9);
}

/* ---- stretchable art: the plain middle of the picture stretches, the two ends are the whole picture with a mask.
   Per piece: --H height, --ka picture width / height, --kr where the plain middle starts (x height),
   --sq squeeze of the ends (1 = as drawn). Safe to animate with scale: there is no sliced border. ---- */
.wing {
  position: relative;
  isolation: isolate;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: var(--H);
  padding: 0 calc(var(--H) * var(--kr) * 0.9);
  background: var(--img) var(--mid, 50%) center / 2000% 100% no-repeat content-box;
  --sq: 1;
}
.wing::before,
.wing::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background: var(--img) left center / calc(var(--H) * var(--ka) * var(--sq)) 100% no-repeat;
  -webkit-mask-image: linear-gradient(90deg, #000 calc(var(--H) * var(--kr)), transparent calc(var(--H) * var(--kr) * 1.3));
  mask-image: linear-gradient(90deg, #000 calc(var(--H) * var(--kr)), transparent calc(var(--H) * var(--kr) * 1.3));
}
.wing::after {
  background-position: right center;
  -webkit-mask-image: linear-gradient(270deg, #000 calc(var(--H) * var(--kr)), transparent calc(var(--H) * var(--kr) * 1.3));
  mask-image: linear-gradient(270deg, #000 calc(var(--H) * var(--kr)), transparent calc(var(--H) * var(--kr) * 1.3));
}

/* ---- buttons ---- */
.btn {
  --img: var(--img-btn);
  --H: calc(var(--u) * 11);
  --ka: 5.54;
  --kr: 0.95;
  min-width: calc(var(--H) * 3.4);
  gap: calc(var(--u) * 1.6);
  font-weight: 700;
  font-size: calc(var(--H) * 0.44);
  color: var(--ink);
  white-space: nowrap;
  transition:
    transform 0.08s ease-out,
    filter 0.08s;
}
.btn > * {
  transform: translateY(-3%);
}
.btn.two {
  --img: var(--img-btn-2);
  --ka: 5.565;
  color: var(--cream);
  -webkit-text-stroke: calc(var(--H) * 0.07) var(--outline-indigo);
  paint-order: stroke fill;
}
.btn.big {
  --H: calc(var(--u) * 15);
}
.btn.small {
  --H: max(calc(var(--u) * 8.5), 50px); /* 44 px for a finger after the panel shrinks to fit */
}
.btn img {
  height: calc(var(--H) * 0.5);
  width: auto;
}
.btn:active,
.round:active,
.tap:active {
  transform: translateY(calc(var(--u) * 0.5)) scale(0.97);
  filter: brightness(0.94);
}
@media (hover: hover) {
  .btn:hover,
  .round:hover {
    transform: translateY(calc(var(--u) * -0.3));
    filter: brightness(1.06);
  }
  .btn:active,
  .round:active {
    transform: translateY(calc(var(--u) * 0.5)) scale(0.97);
    filter: brightness(0.94);
  }
}
.btn[disabled],
.round[disabled] {
  filter: grayscale(0.7) brightness(0.75);
  pointer-events: none;
}

/* round icon buttons: the icon is part of the picture */
.round {
  --D: calc(var(--u) * 9.5);
  width: var(--D);
  height: var(--D);
  flex: none;
  background: center / contain no-repeat;
  transition:
    transform 0.08s ease-out,
    filter 0.08s;
}
/* on a phone held upright every round button is at least 44 px */
.port .round {
  --D: calc(var(--u) * 10.5);
}
.round.off {
  filter: grayscale(0.9) brightness(0.7);
}
.link {
  color: var(--ink);
  font-weight: 700;
  text-decoration: underline;
  text-underline-offset: 0.2em;
  padding: calc(var(--u) * 1.5) calc(var(--u) * 4);
}
/* every small control answers a finger of 44 px, even where it is drawn smaller: an invisible margin around it takes the
   touch (:where keeps the position of the controls placed elsewhere; the margin only grows, it never shrinks the button) */
:where(.round, .toggle, .link) {
  position: relative;
}
:is(.round, .toggle, .link)::before {
  content: '';
  position: absolute;
  inset: min(0px, calc(50% - 22px)) min(0px, calc(50% - 22px));
}

/* ---- ribbons (straight cloth: the text sits on the cloth, which is the upper three quarters of the picture) ---- */
.ribbon {
  --img: var(--img-ribbon);
  --H: calc(var(--u) * 12);
  --ka: 7.235;
  --sq: 0.6;
  --kr: 1.3;
  min-width: calc(var(--H) * 4.4);
  font-size: calc(var(--H) * 0.4);
}
.ribbon > span {
  transform: translateY(-27%);
}
.ribbon.soft {
  --img: var(--img-ribbon-soft);
}
.ribbon.soft > span {
  -webkit-text-stroke-color: #8a3a06;
}
.ribbon.name {
  --img: var(--img-ribbon-name);
  --H: calc(var(--u) * 8);
  --ka: 8.185;
  --sq: 0.5;
  --kr: 1.36;
  min-width: calc(var(--H) * 5);
  font-size: calc(var(--H) * 0.42);
  color: var(--ink);
  font-weight: 700;
  white-space: nowrap;
}
.ribbon.name > span {
  transform: translateY(-13%);
}

/* ---- HUD pills ---- */
.pill {
  --img: var(--img-pill);
  --H: calc(var(--u) * 9);
  --ka: 5.12;
  --kr: 0.86;
  --mid: 28%;
  gap: calc(var(--u) * 1.2);
  font-weight: 700;
  font-size: calc(var(--H) * 0.46);
  color: var(--ink);
  white-space: nowrap;
}
/* in the plate art the paper is 62% of the height and its middle sits at 56.5% (the top ornament pushes it down) */
.pill img {
  height: calc(var(--H) * 0.5);
  width: auto;
}
.pill > * {
  translate: 0 calc(var(--H) * 0.065);
}

/* ---- popups ---- */
.pop {
  position: fixed;
  inset: 0;
  z-index: 20;
  display: grid;
  place-items: center;
  font-size: calc(var(--u) * 3.6);
}
/* on a phone held upright the panels use a bigger unit, so texts and buttons are comfortable to read and tap */
.port .pop {
  --u: calc(var(--u0) * 1.22);
}
.pop::before {
  content: '';
  position: absolute;
  inset: 0;
  background: var(--veil);
  animation: screen-in var(--panel-in) both;
}
.pop.out {
  pointer-events: none;
}
.pop.out::before {
  animation: screen-out var(--panel-out) forwards;
}
.pop.out .panel,
.pop.out .show {
  animation: panel-out var(--panel-out) ease-in forwards;
}
.panel {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(var(--u) * 2.2);
  width: calc(var(--u) * 70);
  max-width: calc(var(--sw) - var(--u) * 6);
  padding: calc(var(--u) * 10) calc(var(--u) * 7.5) calc(var(--u) * 7.5);
  background: var(--img-panel) center / 100% 100% no-repeat;
  animation: panel-in var(--panel-in) cubic-bezier(0.3, 1.5, 0.5, 1) both;
}
/* the panel drawn again in place (after a language change) does not play its entrance */
.pop.still:not(.out) .panel {
  animation: none;
}
.panel.wide {
  width: calc(var(--u) * 96);
  background-image: var(--img-panel-wide);
}
.panel > .ribbon {
  position: absolute;
  left: 50%;
  top: 0;
  translate: -50% -42%;
}
.panel > .close {
  position: absolute;
  right: calc(var(--u) * -1.5);
  top: calc(var(--u) * -1.5);
  --D: calc(var(--u) * 8.5);
}
.panel > .back {
  position: absolute;
  left: calc(var(--u) * -1.5);
  top: calc(var(--u) * -1.5);
  --D: calc(var(--u) * 8.5);
}
.panel .stack {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(var(--u) * 1.8);
  width: 100%;
}
.panel .row {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: calc(var(--u) * 2);
}
.show {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(var(--u) * 2.5);
  animation: panel-in var(--panel-in) cubic-bezier(0.3, 1.5, 0.5, 1) both;
}
@keyframes panel-in {
  from {
    opacity: 0;
    transform: scale(0.82) translateY(calc(var(--u) * 4));
  }
}
@keyframes panel-out {
  to {
    opacity: 0;
    transform: scale(0.92);
  }
}

/* a soft plate inside a panel (a row of the result, a goal) */
.plate {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: calc(var(--u) * 2);
  min-height: calc(var(--u) * 8.5);
  width: 100%;
  padding: calc(var(--u) * 1) calc(var(--u) * 3);
  border-radius: calc(var(--u) * 4.5);
  background: rgba(255, 235, 190, 0.75);
  box-shadow: inset 0 0 0 calc(var(--u) * 0.35) rgba(214, 160, 70, 0.75);
  font-weight: 700;
}
.plate img {
  height: calc(var(--u) * 6);
  width: auto;
}
.plate > img + span {
  padding-left: calc(var(--u) * 2);
  border-left: calc(var(--u) * 0.3) solid rgba(170, 120, 60, 0.45);
}

/* light rays behind something: they open and fade, turning only a little */
.rays {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 240%;
  aspect-ratio: 1;
  translate: -50% -50%;
  pointer-events: none;
  opacity: 0;
  z-index: -1;
  border-radius: 50%;
  background: repeating-conic-gradient(from 0deg, rgba(var(--glow-strong), 0.6) 0 9deg, transparent 9deg 30deg);
  -webkit-mask-image: radial-gradient(circle, #000 18%, rgba(0, 0, 0, 0.5) 42%, transparent 68%);
  mask-image: radial-gradient(circle, #000 18%, rgba(0, 0, 0, 0.5) 42%, transparent 68%);
}
.rays.hold {
  opacity: 0.7;
  animation: rays-hold 9s linear infinite;
}
@keyframes rays-hold {
  to {
    rotate: 40deg;
  }
}

/* the mascot */
.flick {
  width: calc(var(--u) * 30);
  aspect-ratio: 1;
  background: center / contain no-repeat;
  animation: bob var(--bob) ease-in-out infinite;
  /* he leans toward the card being turned */
  transition:
    rotate 0.25s ease-out,
    translate 0.25s ease-out;
}
@keyframes bob {
  50% {
    transform: translateY(calc(var(--u) * -1.2));
  }
}

/* "Reduce motion": the state stays, the movement goes */
.calm .screen,
.calm .panel,
.calm .show,
.calm .pop::before {
  animation-duration: 0.01s !important;
}
.calm .flick,
.calm .rays.hold,
.calm #glows.peeking i.up,
.calm #glows i.done,
.calm #glows .fly {
  animation: none !important;
}

/* End of css/base.css */
