/* RECURSION — the second pocket world.

   It has to feel like somewhere else, not a reskin, so every axis is the
   inverse of UNDERFLOW. That one is magenta and gold, a single column, and it
   throws the app AWAY from the camera as it opens. This one is cyan and violet,
   a five-by-five field, and it pulls the app INTO itself — the game folding
   into its own centre, which is the word made literal. UNDERFLOW is a fall.
   This is an implosion. */

:root {
  --rc-cyan: #4fd8eb;
  --rc-violet: #7a4dff;
  --rc-hot: #ff4dd8;
}

/* ---------- the fold ---------- */

body.rc-active { overflow: hidden; }
/* Sucked into the middle rather than pushed off the front. */
body.rc-active #app {
  transition: transform 820ms cubic-bezier(0.7, 0, 0.3, 1), opacity 820ms ease, filter 820ms ease;
  transform: scale(0.18) rotate(6deg);
  opacity: 0;
  filter: blur(6px) hue-rotate(70deg);
  pointer-events: none;
}
body.rc-active #confetti { z-index: 260; }

.rc {
  position: fixed;
  inset: 0;
  z-index: 200;
  overflow: hidden;
  background: radial-gradient(120% 90% at 50% 50%, #0a0f1e 0%, #05060f 55%, #000 100%);
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: max(10px, env(safe-area-inset-top)) 10px max(10px, env(safe-area-inset-bottom));
  animation: rc-in 240ms ease both;
  /* One source of truth for the cell size: the grid lays out from it and the
     row callouts position from it, so a callout can never drift off its row. */
  --cs: clamp(38px, min(15vw, 10.5vh), 74px);
  --cgap: clamp(2px, 0.8vw, 5px);
}
@keyframes rc-in { from { opacity: 0; } to { opacity: 1; } }

.rc-field { position: absolute; inset: 0; width: 100%; height: 100%; }

.rc::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 40;
  pointer-events: none;
  background:
    radial-gradient(120% 110% at 50% 50%, transparent 46%, rgba(0, 0, 0, 0.76) 100%),
    repeating-linear-gradient(0deg, rgba(255, 255, 255, 0.026) 0 1px, transparent 1px 3px);
}

/* The whole world flinches on every strike and every link. */
.rc.shock { animation: rc-shock 200ms ease-out; }
@keyframes rc-shock {
  0% { transform: translate(0, 0) scale(1); }
  30% { transform: translate(-3px, 2px) scale(1.006); }
  60% { transform: translate(2px, -2px) scale(0.998); }
  100% { transform: translate(0, 0) scale(1); }
}
.rc.folding { animation: rc-fold 820ms cubic-bezier(0.7, 0, 0.3, 1); }
@keyframes rc-fold {
  0% { filter: invert(1) hue-rotate(180deg); transform: scale(1.4); }
  25% { filter: none; transform: scale(0.96); }
  45% { filter: invert(1); transform: scale(1.03); }
  65% { filter: none; transform: scale(0.99); }
  100% { filter: none; transform: scale(1); }
}

/* ---------- title ---------- */

.rc-title {
  position: relative;
  z-index: 30;
  text-align: center;
  opacity: 0;
  transform: scale(0.4);
  transition: opacity 460ms ease, transform 820ms cubic-bezier(0.16, 1, 0.3, 1);
  pointer-events: none;
}
.rc.titled .rc-title { opacity: 1; transform: scale(1); }
.rc.playing .rc-title {
  position: absolute;
  top: max(8px, env(safe-area-inset-top));
  left: 50%;
  opacity: 0.85;
  transform: translateX(-50%) scale(0.36);
  transform-origin: top center;
}
.rc-word {
  position: relative;
  font-family: var(--display);
  font-size: clamp(2rem, 11vw, 6.4rem);
  letter-spacing: 0.04em;
  color: #fff;
  text-shadow: 0 0 50px rgba(79, 216, 235, 0.75);
}
/* The word echoes itself, smaller and smaller, behind itself. */
.rc-word::before,
.rc-word::after {
  content: attr(data-t);
  position: absolute;
  inset: 0;
  mix-blend-mode: screen;
  transform-origin: center;
}
.rc-word::before { color: var(--rc-cyan); animation: rc-echo1 3.2s ease-in-out infinite; }
.rc-word::after { color: var(--rc-violet); animation: rc-echo2 3.2s ease-in-out infinite; }
@keyframes rc-echo1 { 0%, 100% { transform: scale(1.07); opacity: 0.5; } 50% { transform: scale(1.02); opacity: 0.24; } }
@keyframes rc-echo2 { 0%, 100% { transform: scale(0.93); opacity: 0.5; } 50% { transform: scale(0.98); opacity: 0.24; } }
.rc-sub {
  margin-top: 8px;
  font-family: var(--mono);
  font-size: clamp(0.55rem, 2.4vw, 0.8rem);
  letter-spacing: 0.26em;
  color: var(--dim);
}

/* ---------- the board ---------- */

.rc-stage {
  position: relative;
  z-index: 32;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(8px, 2vh, 16px);
  animation: rc-stage-in 520ms cubic-bezier(0.16, 1, 0.3, 1) both;
}
@keyframes rc-stage-in { from { opacity: 0; transform: translateY(20px) scale(0.94); } to { opacity: 1; transform: none; } }

.rc-hud {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: clamp(14px, 5vw, 46px);
  width: 100%;
  font-family: var(--display);
}
.rc-hud > div { display: flex; flex-direction: column; align-items: center; gap: 2px; }
.rc-lbl { font-family: var(--mono); font-size: 0.5rem; letter-spacing: 0.2em; color: var(--dimmer, #5a586e); }
.rc-seeds b { font-size: clamp(0.8rem, 3.4vw, 1.2rem); color: var(--rc-cyan); letter-spacing: 0.16em; }
.rc-mult b { font-size: clamp(0.9rem, 3.6vw, 1.4rem); color: var(--gold); }
/* The depth counter is the drama. It grows and heats as the chain deepens. */
.rc-depth b {
  font-size: clamp(1.4rem, 6vw, 2.4rem);
  color: var(--ink);
  line-height: 1;
  transition: color 200ms ease, text-shadow 200ms ease, scale 200ms ease;
}
.rc-depth b.pop { animation: rc-depth-pop 320ms cubic-bezier(0.16, 1, 0.3, 1); }
@keyframes rc-depth-pop { 0% { scale: 1.7; filter: brightness(2.4); } 100% { scale: 1; filter: none; } }
.rc.lastseed .rc-seeds b { color: var(--gold); animation: pulse 900ms ease-in-out infinite; }

/* Depth drives the temperature of the whole world. */
.rc[data-depth="3"] .rc-depth b, .rc[data-depth="4"] .rc-depth b { color: var(--rc-cyan); text-shadow: 0 0 18px var(--rc-cyan); }
.rc[data-depth="5"] .rc-depth b, .rc[data-depth="6"] .rc-depth b { color: var(--gold); text-shadow: 0 0 22px var(--gold); scale: 1.1; }
.rc[data-depth="7"] .rc-depth b, .rc[data-depth="8"] .rc-depth b { color: var(--orange); text-shadow: 0 0 26px var(--orange); scale: 1.2; }
.rc[data-depth="9"] .rc-depth b, .rc[data-depth="10"] .rc-depth b,
.rc[data-depth="11"] .rc-depth b, .rc[data-depth="12"] .rc-depth b {
  color: var(--rc-hot); text-shadow: 0 0 34px var(--rc-hot), 0 0 60px var(--rc-hot); scale: 1.34;
}
.rc[data-depth="7"], .rc[data-depth="8"] { --rc-glow: var(--orange); }
.rc[data-depth="9"], .rc[data-depth="10"], .rc[data-depth="11"], .rc[data-depth="12"] { --rc-glow: var(--rc-hot); }
.rc[data-depth="9"]::after, .rc[data-depth="10"]::after,
.rc[data-depth="11"]::after, .rc[data-depth="12"]::after {
  background:
    radial-gradient(120% 110% at 50% 50%, transparent 34%, color-mix(in srgb, var(--rc-hot) 22%, rgba(0,0,0,0.8)) 100%),
    repeating-linear-gradient(0deg, rgba(255, 255, 255, 0.04) 0 1px, transparent 1px 3px);
}

.rc-grid {
  display: grid;
  grid-template-columns: repeat(5, var(--cs));
  grid-auto-rows: var(--cs);
  gap: var(--cgap);
  position: relative;
}
.rc-cell {
  display: grid;
  place-items: center;
  width: var(--cs);
  height: var(--cs);
  padding: 0;
  border: 0;
  pointer-events: none; /* the reel is the control; the board is the readout */
  font-family: var(--mono);
  font-weight: 700;
  font-size: calc(var(--cs) * 0.52);
  color: var(--ink);
  background: rgba(255, 255, 255, 0.045);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.1);
  transition: background 140ms ease, box-shadow 140ms ease, scale 140ms cubic-bezier(0.16, 1, 0.3, 1);
}
/* Everywhere the reel's current digit lives. This is the live readout, so it
   has to be loud — it flickers from set to set as the reel runs, which is both
   the strategy and most of the pleasure. */
.rc-cell.armed {
  background: color-mix(in srgb, var(--rc-cyan) 30%, transparent);
  box-shadow: inset 0 0 0 2px var(--rc-cyan), 0 0 26px color-mix(in srgb, var(--rc-cyan) 70%, transparent);
  scale: 1.09;
  color: #fff;
  transition: none; /* it changes every ~100ms; easing would smear it */
}
.rc-cell.igniting { animation: rc-ignite 300ms cubic-bezier(0.3, 0, 0.2, 1) forwards; }
@keyframes rc-ignite {
  0% { background: #fff; color: #05060f; scale: 1.3; box-shadow: 0 0 40px #fff; }
  100% { background: transparent; color: transparent; scale: 0.2; box-shadow: none; }
}
.rc-cell.paying {
  color: #05060f;
  animation: rc-pay 420ms cubic-bezier(0.3, 0, 0.2, 1) forwards;
}
.rc-cell.paying.common { background: var(--tier-common); }
.rc-cell.paying.uncommon { background: var(--tier-uncommon); }
.rc-cell.paying.rare { background: var(--tier-rare); }
.rc-cell.paying.epic { background: var(--tier-epic); }
.rc-cell.paying.mythic { background: var(--tier-mythic); }
@keyframes rc-pay {
  0% { scale: 1; filter: brightness(2.2); }
  40% { scale: 1.14; }
  100% { scale: 0.86; opacity: 0; }
}


.rc-hint {
  font-family: var(--display);
  font-size: clamp(0.5rem, 2.2vw, 0.72rem);
  letter-spacing: 0.18em;
  color: var(--dim);
  min-height: 1em;
}
.rc.lastseed .rc-hint { color: var(--gold); animation: pulse 900ms ease-in-out infinite; }
.rc.busy .rc-hint { opacity: 0.3; }

/* ---------- the picker ----------
   Lifted from UNDERFLOW so both worlds answer to the same verb: tap anywhere,
   stop the thing that is spinning. Nothing to aim at. */
.rc-picker {
  display: flex;
  align-items: center;
  gap: clamp(8px, 2.6vw, 16px);
}
.rc-slot {
  position: relative;
  display: block;
  width: calc(var(--cs) * 0.86);
  height: calc(var(--cs) * 1.12);
  overflow: hidden;
  background: rgba(79, 216, 235, 0.1);
  box-shadow: inset 0 0 0 1px var(--rc-cyan), 0 0 30px color-mix(in srgb, var(--rc-cyan) 40%, transparent);
  -webkit-mask-image: linear-gradient(180deg, transparent 0%, #000 24%, #000 76%, transparent 100%);
  mask-image: linear-gradient(180deg, transparent 0%, #000 24%, #000 76%, transparent 100%);
  transition: box-shadow 160ms ease, background 160ms ease;
}
.rc-slot[data-hot="1"] {
  background: rgba(255, 210, 63, 0.14);
  box-shadow: inset 0 0 0 1px var(--gold), 0 0 34px color-mix(in srgb, var(--gold) 50%, transparent);
}
.rc-reel { display: block; will-change: transform; }
.rc-reel b {
  display: block;
  height: calc(var(--cs) * 1.12);
  line-height: calc(var(--cs) * 1.12);
  font-family: var(--mono);
  font-weight: 700;
  font-size: calc(var(--cs) * 0.72);
  text-align: center;
  color: var(--ink);
}
.rc.spinning .rc-reel { filter: blur(0.6px); }
.rc-slot.locked { animation: rc-lock 320ms cubic-bezier(0.16, 1, 0.3, 1); }
@keyframes rc-lock {
  0% { scale: 1.22; filter: brightness(2.4); }
  100% { scale: 1; filter: none; }
}
.rc-picklabel {
  font-family: var(--display);
  font-size: clamp(0.5rem, 2.2vw, 0.72rem);
  letter-spacing: 0.18em;
  color: var(--rc-cyan);
}
.rc.spinning .rc-picklabel { animation: pulse 800ms ease-in-out infinite; }
.rc.busy .rc-picker { opacity: 0.25; transition: opacity 300ms ease; }
.rc-stage.resolved .rc-picker { opacity: 0.2; }

/* Row callouts fly off the row that paid, so the name is attached to the thing
   that earned it rather than floating in the middle of the screen. */
/* Pinned to the GRID, not the stage. Anchored to the stage, `top: 50%` was the
   centre of the HUD-plus-grid-plus-hint stack, which put every callout a
   consistent 12-20px off the row it was naming. */
.rc-board { position: relative; }
.rc-callouts { position: absolute; inset: 0; pointer-events: none; z-index: 36; }
.rc-callout {
  position: absolute;
  left: 50%;
  top: 0; /* set in px from the row's measured position */
  translate: -50% -50%;
  font-family: var(--display);
  font-size: clamp(0.7rem, 3vw, 1.1rem);
  letter-spacing: 0.05em;
  white-space: nowrap;
  color: var(--ct, var(--gold));
  text-shadow: 0 0 20px var(--ct, var(--gold));
  animation: rc-callout 1.1s cubic-bezier(0.16, 1, 0.3, 1) forwards;
}
.rc-callout.common { --ct: var(--tier-common); }
.rc-callout.uncommon { --ct: var(--tier-uncommon); }
.rc-callout.rare { --ct: var(--tier-rare); }
.rc-callout.epic { --ct: var(--tier-epic); }
.rc-callout.mythic { --ct: var(--tier-mythic); }
@keyframes rc-callout {
  0% { opacity: 0; scale: 2.2; filter: blur(8px); }
  22% { opacity: 1; scale: 1; filter: none; }
  70% { opacity: 1; translate: -50% -50%; }
  100% { opacity: 0; translate: -50% -180%; scale: 0.9; }
}

/* ---------- payout ---------- */

.rc-stage.resolved .rc-hud,
.rc-stage.resolved .rc-hint { opacity: 0.25; transition: opacity 400ms ease; }
.rc-stage.resolved .rc-grid { opacity: 0.25; filter: saturate(0.3); transition: opacity 500ms ease, filter 500ms ease; }

.rc-payout {
  position: relative;
  z-index: 34;
  margin-top: clamp(8px, 2vh, 20px);
  text-align: center;
  pointer-events: none;
  max-width: min(96vw, 640px);
  animation: rc-stage-in 420ms cubic-bezier(0.16, 1, 0.3, 1) both;
}
.rc-tier {
  font-family: var(--display);
  font-size: clamp(0.68rem, 3vw, 1.05rem);
  letter-spacing: 0.22em;
  color: var(--tc, var(--rc-cyan));
}
.rc-tier.pop { animation: rc-tier-pop 520ms cubic-bezier(0.16, 1, 0.3, 1); }
@keyframes rc-tier-pop {
  0% { scale: 0.5; filter: brightness(3); letter-spacing: 0.6em; }
  100% { scale: 1; filter: none; letter-spacing: 0.22em; }
}
.rc-total {
  font-family: var(--display);
  font-size: clamp(2.2rem, 12vw, 5.2rem);
  color: var(--ink);
  line-height: 1;
  text-shadow: 0 0 44px color-mix(in srgb, var(--tc, var(--rc-cyan)) 70%, transparent);
}
.rc-total.landed { animation: rc-land 620ms cubic-bezier(0.16, 1, 0.3, 1); }
@keyframes rc-land { 0% { scale: 1.26; filter: brightness(2.2); } 100% { scale: 1; filter: none; } }
.rc-breakdown {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 5px 14px;
  margin-top: 10px;
  font-family: var(--mono);
  font-size: clamp(0.5rem, 2.1vw, 0.68rem);
  color: var(--dim);
  letter-spacing: 0.06em;
}
.rc-breakdown b { color: var(--hit); font-weight: 700; }
.rc-breakdown .maxed { color: var(--rc-hot); }
.rc-breakdown .maxed b { color: var(--rc-hot); }

/* ---------- the return ---------- */

.rc.closing { animation: rc-out 720ms cubic-bezier(0.6, 0, 0.2, 1) forwards; }
@keyframes rc-out {
  0% { opacity: 1; transform: scale(1); filter: none; }
  100% { opacity: 0; transform: scale(2.6) rotate(-5deg); filter: blur(16px) brightness(1.8); }
}

/* ---------- reduced motion ----------
   Shortened, never skipped. The chain still resolves link by link with its
   sound and its callouts; what goes is the camera work and the flinching. */
@media (prefers-reduced-motion: reduce) {
  .rc.spinning .rc-picklabel { animation: none; }
  .rc-slot.locked { animation: none; }
  body.rc-active #app { transition: none; transform: none; opacity: 0; filter: none; }
  .rc, .rc-stage, .rc-payout { animation: none; }
  .rc.folding, .rc.shock { animation: none; }
  .rc-word::before, .rc-word::after { animation: none; }
  .rc.lastseed .rc-seeds b, .rc.lastseed .rc-hint { animation: none; }
  .rc-title, .rc.playing .rc-title { transition: opacity 200ms ease; transform: none; }
  .rc.playing .rc-title { display: none; }
  .rc.closing { animation: rc-fadeout 240ms ease forwards; }
  @keyframes rc-fadeout { to { opacity: 0; } }
}

/* ---------- short landscape ---------- */
@media (max-height: 460px) {
  /* The picker costs about 45px of height, which pushed the payout off the
     bottom of every landscape phone. Buy it back from the cells: five rows plus
     the reel all shrink together, so the proportions hold. */
  .rc { --cs: clamp(24px, 7.4vh, 44px); }
  .rc-stage { gap: 4px; }
  .rc-picklabel { display: none; }
  .rc-hint { font-size: 0.48rem; }
  .rc-lbl { font-size: 0.42rem; }
  .rc.playing .rc-title { display: none; }
  .rc-payout { margin-top: 6px; }
  .rc-total { font-size: clamp(1.6rem, 8vh, 3rem); }
  .rc-depth b { font-size: clamp(1rem, 5vh, 1.6rem); }
}

/* ---------- the chain counter, in the ordinary game ----------
   The trigger's whole value is that you watch it climb. Nine consecutive
   specials is 1 in 716 games, but a chain of four is 1 in 4 — so this is a
   familiar sight that occasionally, terrifyingly, keeps going. */

.chainmeter {
  display: inline-flex;
  align-items: baseline;
  gap: 5px;
  padding: 3px 9px;
  background: color-mix(in srgb, var(--rc-cyan) 12%, transparent);
  border: 1px solid color-mix(in srgb, var(--rc-cyan) 40%, transparent);
  clip-path: polygon(6px 0, 100% 0, calc(100% - 6px) 100%, 0 100%);
  font-family: var(--display);
  color: var(--rc-cyan);
  animation: chain-in 300ms cubic-bezier(0.16, 1, 0.3, 1) both;
}
@keyframes chain-in { from { opacity: 0; scale: 0.6; } to { opacity: 1; scale: 1; } }
.chainmeter .cmn { font-size: 0.82rem; line-height: 1; }
.chainmeter .cmlabel { font-size: 0.44rem; letter-spacing: 0.16em; opacity: 0.75; }

/* Six and up: it is getting genuinely unusual. */
.chainmeter.hot {
  color: var(--gold);
  border-color: color-mix(in srgb, var(--gold) 60%, transparent);
  background: color-mix(in srgb, var(--gold) 16%, transparent);
}
/* Eight: one special from the rarest thing in the game. */
.chainmeter.brink {
  color: var(--rc-hot);
  border-color: var(--rc-hot);
  background: color-mix(in srgb, var(--rc-hot) 24%, transparent);
  animation: chain-brink 620ms ease-in-out infinite;
}
@keyframes chain-brink {
  0%, 100% { box-shadow: 0 0 0 0 transparent; scale: 1; }
  50% { box-shadow: 0 0 26px color-mix(in srgb, var(--rc-hot) 85%, transparent); scale: 1.08; }
}

/* ---------- LOW GRAPHICS ----------
   The pocket worlds are the heaviest screens in the game: persistent blurs on
   the spinning reels, layered glows, and a starfield behind everything. The
   blanket in styles.css already removes the shadows and filters; these are the
   ambient loops, killed by name. Every outcome, digit and payout still renders. */
html[data-gfx='low'] .uf-word::before,
html[data-gfx='low'] .uf-word::after,
html[data-gfx='low'] .rc-word::before,
html[data-gfx='low'] .rc-word::after,
html[data-gfx='low'] .uf.hot .uf-meter,
html[data-gfx='low'] .uf.final .uf-hint,
html[data-gfx='low'] .rc.lastseed .rc-seeds b,
html[data-gfx='low'] .rc.lastseed .rc-hint,
html[data-gfx='low'] .rc.spinning .rc-picklabel,
html[data-gfx='low'] .faultmeter.brink,
html[data-gfx='low'] .panel.brink,
html[data-gfx='low'] .chainmeter.brink {
  animation: none !important;
}
