/* App shell and the screens that are not the board. */

#app {
  position: relative;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  background: var(--color-bg);
}

/* The app's signature wallpaper: two copies of the meme collage side by side,
   scrolling left one full screen width every 80 seconds — the same figures as
   AnimatedBackground.kt. Dimmed against the navy ground so tiles and text stay
   legible over it, which the phone gets away with because its collage sits
   behind far less content. */
#app::before {
  content: '';
  position: fixed;
  top: 0;
  left: 0;
  /* Two screen-widths of collage, translated by one width per cycle. Animating
     `transform` hands the scroll to the compositor; the earlier
     `background-position` version repainted the whole viewport every frame,
     which a mid-range Android phone feels immediately. */
  width: 200vw;
  height: 100%;
  z-index: 0;
  pointer-events: none;
  background: url('../assets/ui/bg_main_2.webp') repeat-x;
  background-size: 100vw 100%;
  /* The collage is light greyscale, so it reads much louder over navy than it
     does on the phone, where far less text sits on top of it. */
  opacity: 0.2;
  will-change: transform;
  animation: bg-scroll 80s linear infinite;
}

/* A soft scrim over the wallpaper: darkest through the middle band where the
   HUD, tables and prose live, clearing towards the top and bottom edges so the
   collage still reads as a moving backdrop. */
#app::after {
  content: '';
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background: linear-gradient(
    to bottom,
    rgba(26, 26, 46, 0.25) 0%,
    rgba(26, 26, 46, 0.6) 35%,
    rgba(26, 26, 46, 0.6) 70%,
    rgba(26, 26, 46, 0.25) 100%);
}
@keyframes bg-scroll {
  from { transform: translate3d(0, 0, 0); }
  to { transform: translate3d(-100vw, 0, 0); }
}

/* Everything else rides above the wallpaper. */
.screen, #sound-toggle { z-index: 1; }

/* The board is sized to fit the viewport, so the game screen must never be
   able to scroll — a few stray pixels of overflow would shrink every tile. */
#app[data-screen='game'] {
  height: 100dvh;
  overflow: hidden;
}

.screen {
  position: relative;
  flex: 1;
  display: flex;
  flex-direction: column;
  min-height: 0;
  animation: screen-in 220ms ease;
}
@keyframes screen-in {
  from { opacity: 0; transform: translateY(6px); }
  to { opacity: 1; transform: none; }
}

/* Every screen's content sits on the same centred column. */
.screen-pad {
  width: 100%;
  max-width: var(--measure);
  margin-inline: auto;
  padding: clamp(24px, 5vw, 56px) clamp(20px, 6vw, 90px);
}

/* Top bar shared by the secondary screens (scores, progress, customize).
   Held to the same measure so the back button lines up with the content
   underneath it rather than floating out at the window edge. The extra right
   padding keeps the wordmark clear of the fixed sound toggle. */
.topbar {
  width: 100%;
  max-width: var(--measure);
  margin-inline: auto;
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 20px calc(clamp(20px, 6vw, 48px) + 52px) 0 clamp(20px, 6vw, 48px);
}
.topbar .spacer { margin-left: auto; }

.wordmark {
  font: 500 13px/1 var(--font-mono);
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--color-accent-bright);
  text-shadow: var(--glow-text);
}

/* — menu ————————————————————————————————————————— */

.menu {
  flex: 1;
  display: flex;
  align-items: center;
  gap: clamp(24px, 5vw, 64px);
  /* The copy and the deck read as one object, so they centre as a unit and
     stay a single gap apart. Pushing them to opposite ends of the column was
     tried, to fill the window the way the other screens do, and it just left a
     lake of wallpaper between them — this is the one screen where filling the
     measure costs more than it buys. */
  justify-content: center;
  width: 100%;
  max-width: var(--measure);
  margin-inline: auto;
  padding: 0 clamp(24px, 4vw, 56px);
}
/* Sized to its own widest line — the nowrap title — rather than to a round
   number, so there is no dead column between the copy and the deck. */
.menu-copy { flex: none; width: min(max-content, 100%); }
.menu-title {
  /* Sized to keep the two-word wordmark on one line in a monospace face —
     the design's 92px was drawn against the shorter "Memery". */
  font: 500 clamp(38px, 6.2vw, 74px)/0.95 var(--font-mono);
  white-space: nowrap;
  letter-spacing: -0.05em;
  color: var(--color-text);
  margin: 0;
}
.menu-rule {
  height: 1px;
  width: min(400px, 100%);
  margin: 24px 0 20px;
  background: linear-gradient(to right, var(--color-accent), rgba(255, 215, 0, 0.15) 72%, transparent);
}
.menu-blurb {
  max-width: 340px;
  margin: 0 0 28px;
  font-size: 14px;
  line-height: 1.6;
  color: var(--color-text-muted);
}
.menu-actions { display: flex; flex-direction: column; align-items: flex-start; gap: 2px; }
.menu-actions .btn-primary {
  font-size: 17px;
  padding: 10px 22px;
  margin-bottom: 8px;
}
.menu-actions .btn-ghost { font-size: 15px; padding: 5px 8px 5px 0; }

/* Outbound link to the Android original, worded as meme-o-ree.web.app words it.
   Set apart from the menu's internal links so it is clear it leaves the app. */
.play-link {
  margin-top: 18px;
  padding: 9px 18px;
  font-size: 14px;
  color: var(--color-accent);
  border-color: var(--color-accent);
  text-decoration: none;
}
.play-link:hover { background: rgba(255, 215, 0, 0.16); }
.play-link:active { background: rgba(255, 215, 0, 0.26); }

.menu-deck { flex: 0 1 auto; display: flex; justify-content: center; align-items: center; }
.menu-deck-grid {
  display: grid;
  grid-template-columns: repeat(3, clamp(58px, 8vw, 128px));
  gap: 8px;
  transform: rotate(-6deg);
}
/* Decorative, but it speaks the board's own language: a face-down tile is dark
   and marked with a "?", a face-up one is white and carries art, and a matched
   one has receded. */
.menu-deck-grid > div {
  aspect-ratio: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--radius-md);
  background: var(--color-tile-back);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.14);
}
.menu-deck-grid > div::before {
  content: '?';
  font: 700 clamp(22px, 3.2vw, 52px)/1 var(--font-mono);
  color: var(--color-accent);
}
.menu-deck-grid > .face {
  background: var(--color-tile-face) center/84% no-repeat;
  box-shadow: 0 0 18px rgba(0, 0, 0, 0.6);
}
.menu-deck-grid > .matched {
  background: rgba(0, 0, 0, 0.35);
  box-shadow: inset 0 0 0 1px rgba(255, 215, 0, 0.25);
}
.menu-deck-grid > .face::before,
.menu-deck-grid > .matched::before { content: none; }

@media (max-width: 860px) {
  /* The deck is gone here, so there is nothing to balance the copy against —
     centre it rather than leaving it against the edge. */
  .menu { flex-direction: column; justify-content: center; text-align: center; padding-block: 40px; }
  .menu-copy { width: 100%; align-self: center; }
  .menu-deck { display: none; }
  .menu-blurb { margin-inline: auto; }
  .menu-rule {
    margin-inline: auto;
    background: linear-gradient(to right,
      transparent, var(--color-accent) 40%, var(--color-accent) 60%, transparent);
  }
  .menu-actions { align-items: center; }
  .menu-actions .btn-ghost { padding-inline: var(--space-1); }
}

/* — level select ——————————————————————————————————— */

.levels {
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
  text-align: center;
}
.levels-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 16px;
  width: 100%;
  max-width: var(--measure);
  margin-inline: auto;
}
.level-card {
  align-items: center;
  text-align: center;
  padding: 16px;
  border: 0;
  cursor: pointer;
  font: inherit;
  color: inherit;
  transition: box-shadow 140ms ease, transform 140ms ease;
}
.level-card:hover {
  transform: translateY(-2px);
  box-shadow: 0 0 0 1px var(--color-accent), var(--glow-accent);
}
.level-card:hover .card-kicker { color: var(--color-accent); }
/* Every preview is three rows of a fixed cell, so all four cards put their
   title and meta on the same baseline; only the width varies, which is what
   actually communicates "bigger board". */
.level-preview {
  --preview-cell: clamp(18px, 1.5vw, 32px);
  display: grid;
  grid-auto-rows: var(--preview-cell);
  justify-content: center;
  gap: 2px;
  height: calc(var(--preview-cell) * 3 + 4px);
  margin: 6px 0 10px;
}
.level-preview > i {
  aspect-ratio: 1;
  border-radius: 2px;
  background: rgba(255, 215, 0, 0.3);
}

/* — data screens (scores, progress, customize) ——————————— */

/* Scores, Progress and Customize. Headings and prose centre; tabular data
   stays left-aligned inside the centred block, because centred columns of
   numbers are markedly harder to scan. */
.sheet {
  max-width: var(--measure-narrow);
  margin-inline: auto;
  text-align: center;
}
.section-head {
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: 12px;
  margin: 32px 0 10px;
}
.section-head h4 { margin: 0; }

.table { width: 100%; border-collapse: collapse; font-size: 14px; }
.table th {
  text-align: left;
  padding: var(--space-2);
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-text-muted);
  font-weight: 500;
}
.table td { padding: var(--space-2); text-align: left; }
.table thead tr {
  background: linear-gradient(to right,
    transparent, var(--color-divider) 48px,
    var(--color-divider) calc(100% - 48px), transparent) no-repeat bottom / 100% 1px;
}
.table tbody tr {
  background: linear-gradient(to right,
    transparent, rgba(255, 255, 255, 0.12) 48px,
    rgba(255, 255, 255, 0.12) calc(100% - 48px), transparent) no-repeat bottom / 100% 1px;
}
.rank { color: var(--color-accent); width: 2.5em; }
.empty { font-size: 13px; color: var(--color-text-faint); padding: 10px 0; }

.chart { display: block; width: 100%; height: auto; overflow: visible; }
.chart .grid { stroke: rgba(255, 255, 255, 0.18); stroke-width: 1; }
.chart .line {
  fill: none;
  stroke: var(--color-accent);
  stroke-width: 2;
  stroke-linejoin: round;
  filter: drop-shadow(0 0 6px rgba(255, 215, 0, 0.5));
}
.chart .area { fill: url(#chart-fade); }
.chart .dot { fill: var(--color-accent); }
.chart text { font: 10px var(--font-mono); fill: rgba(255, 255, 255, 0.55); }

/* An empty screen has nothing to anchor to, so it centres on both axes. */
.empty-state {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
}

/* — result ————————————————————————————————————————— */

.result {
  /* Full-bleed on purpose: capping the width here clipped the radial glow into
     a visible rectangle. Both columns are fixed width, so centring the flex row
     is enough to centre the content. */
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: clamp(28px, 6vw, 130px);
  padding: clamp(28px, 5vw, 56px) clamp(20px, 6vw, 90px);
}
.result-main { flex: none; width: min(560px, 100%); text-align: center; }
/* The phone puts the rage face on a slowly turning six-colour wheel inside a
   black-bordered band; the wheel is 2.5x the band's long edge so only its
   middle shows. One turn every 25 seconds. */
.result-wheel {
  position: relative;
  display: grid;
  place-items: center;
  width: min(100%, 560px);
  height: clamp(160px, 13vw, 215px);
  margin: 0 auto 16px;
  overflow: hidden;
  border: 2px solid #000;
}
.result-wheel::before {
  content: '';
  position: absolute;
  width: 250%;
  aspect-ratio: 1;
  border-radius: 50%;
  background: conic-gradient(
    #ff00ff 0deg 60deg, #0000ff 60deg 120deg, #00ff00 120deg 180deg,
    #ffff00 180deg 240deg, #ff8000 240deg 300deg, #ff0000 300deg 360deg);
  animation: wheel-spin 25s linear infinite;
}
@keyframes wheel-spin { to { transform: rotate(360deg); } }

.result-face {
  position: relative;
  width: clamp(120px, 9vw, 168px);
  height: clamp(120px, 9vw, 168px);
  filter: drop-shadow(0 2px 6px rgba(0, 0, 0, 0.5));
}

@media (prefers-reduced-motion: reduce) {
  .result-wheel::before { animation: none; }
}
.result-score {
  font: 500 clamp(48px, 8vw, 74px)/1 var(--font-mono);
  letter-spacing: -0.04em;
  font-variant-numeric: tabular-nums;
  margin: 16px 0 6px;
  color: var(--color-accent);
  text-shadow: 0 0 26px rgba(255, 215, 0, 0.45);
}
.result-verdict {
  max-width: 330px;
  margin: 0 auto 26px;
  font-size: 13.5px;
  color: var(--color-text-muted);
}
.result-actions { display: flex; flex-wrap: wrap; justify-content: center; gap: 10px; }
.result-side {
  /* Not flex:1 — that let this column swallow the slack and shove the score
     block to the left edge. */
  flex: 0 1 620px;
  text-align: left;
  display: flex;
  flex-direction: column;
  gap: 16px;
}
.breakdown { display: flex; flex-direction: column; gap: 6px; }
.breakdown-head {
  display: flex;
  justify-content: space-between;
  font: 500 11px/1 var(--font-mono);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--color-text-muted);
}
.breakdown-head b { color: var(--color-text); font-weight: 500; font-variant-numeric: tabular-nums; }
.result-clock {
  display: flex;
  justify-content: space-between;
  padding-top: 12px;
  font-size: 12px;
  color: var(--color-text-faint);
  border-top: 1px solid var(--color-divider);
}
.result-clock b { color: var(--color-text); font-weight: 400; font-variant-numeric: tabular-nums; }

@media (max-width: 860px) {
  .result { flex-direction: column; align-items: stretch; justify-content: center; }
  .result-main, .result-side { width: 100%; max-width: none; }
}

/* — customize ————————————————————————————————————— */

.tile-grid {
  display: grid;
  /* Capped like the board, at the same 128px, which is where the 106x106 art
     draws life size — past that it only gets softer. auto-fit (not auto-fill)
     collapses the empty tracks so a short row centres instead of packing left. */
  grid-template-columns: repeat(auto-fit, minmax(96px, 128px));
  justify-content: center;
  gap: 10px;
  margin-top: 16px;
}
.tile-cell {
  position: relative;
  aspect-ratio: 1;
  padding: 0;
  border: 0;
  border-radius: var(--radius-md);
  background: var(--color-tile-face) center/84% no-repeat;
  box-shadow: 0 0 16px rgba(0, 0, 0, 0.55);
  cursor: pointer;
}
.tile-cell::after {
  content: '×';
  position: absolute;
  top: 4px;
  right: 4px;
  width: 20px;
  height: 20px;
  display: grid;
  place-items: center;
  font: 500 15px/1 var(--font-body);
  color: var(--color-text);
  background: rgba(13, 14, 23, 0.75);
  border-radius: 50%;
  opacity: 0;
  transition: opacity 120ms ease;
}
.tile-cell:hover::after, .tile-cell:focus-visible::after { opacity: 1; }

.storage-gauge { max-width: 320px; margin: 20px auto 0; }
.storage-gauge .kicker { display: block; margin-bottom: 6px; }

/* Cropper */
.crop-stage {
  position: relative;
  width: min(420px, 78vw);
  aspect-ratio: 1;
  overflow: hidden;
  border-radius: var(--radius-md);
  background: var(--color-bg);
  box-shadow: inset 0 0 0 1px var(--color-divider);
  touch-action: none;
  cursor: grab;
}
.crop-stage:active { cursor: grabbing; }
.crop-stage canvas { width: 100%; height: 100%; display: block; }
.crop-controls { display: flex; align-items: center; gap: 12px; font-size: 12px; }
.crop-controls input[type='range'] { flex: 1; accent-color: var(--color-accent-bright); }

/* Global sound toggle — one button for every screen. */
#sound-toggle {
  position: fixed;
  top: 16px;
  right: 16px;
  z-index: 40;
  font-size: 16px;
  line-height: 1;
  background: rgba(13, 14, 23, 0.6);
  backdrop-filter: blur(4px);
}

/* Confetti canvases sit above whatever hosts them, and never take clicks. */
.confetti-canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  z-index: 5;
}

@media (prefers-reduced-motion: reduce) {
  .screen { animation: none; }
  #app::before { animation: none; }
  * { transition-duration: 1ms !important; }
}
