:root {
  --bg: #11131a;
  --panel: #1a1e2a;
  --line: #2b3144;
  --text: #e8ecf5;
  --muted: #9aa3b8;
  --accent: #ffb454;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--bg);
  color: var(--text);
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
}

header {
  padding: 20px 16px 8px;
  text-align: center;
  max-width: 820px;
  margin: 0 auto;
}

h1 {
  margin: 0 0 6px;
  font-size: 1.8rem;
  letter-spacing: 0.02em;
}

.about {
  margin: 0 auto 6px;
  max-width: 54ch;
  color: var(--muted);
  font-size: 0.9rem;
  line-height: 1.45;
}

.status {
  margin: 0;
  font-size: 0.78rem;
  color: var(--accent);
  min-height: 1.1em;
}

main {
  padding: 12px;
}

/* The board is --cols by --rows cells, both written by app.js from the viewport size
   (one cell per 220px, 3..8 columns by 3..6 rows). The box follows that shape so the
   cells stay square, and never grows past the room left under the header. */
.grid {
  --gap: 8px;
  --cols: 3;
  --rows: 3;
  --chrome: 265px;
  position: relative;
  aspect-ratio: var(--cols) / var(--rows);
  width: min(92vw, calc((100vh - var(--chrome)) * var(--cols) / var(--rows)));
  margin: 0 auto;
}

/* Every cell but one holds a picture. Once a second a tile slides into the empty cell:
   app.js moves it by percent and the transition carries it there. */
.tile {
  position: absolute;
  display: block;
  text-decoration: none;
  transition: top 650ms cubic-bezier(0.65, 0, 0.35, 1),
              left 650ms cubic-bezier(0.65, 0, 0.35, 1);
}

.tile.hidden { display: none; }

/* The picture sits inside the cell with the gap around it. */
.frame {
  position: absolute;
  inset: calc(var(--gap) / 2);
  overflow: hidden;
  border-radius: 10px;
  background: var(--panel);
  border: 1px solid var(--line);
}

.tile img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  opacity: 0;
  transform: scale(1.04);
  transition: opacity 450ms ease, transform 450ms ease;
}

/* A new cat takes over one top-row tile by crossfade: .shown comes off (450ms fade out),
   the picture is swapped, and .shown goes back on (450ms fade in). */
.tile img.shown {
  opacity: 1;
  transform: scale(1);
}

.tile:hover img.shown {
  transform: scale(1.06);
}

.tile.empty .frame::after {
  content: "";
  position: absolute;
  inset: 0;
  background: repeating-linear-gradient(
    45deg, transparent, transparent 10px, rgba(255,255,255,0.025) 10px, rgba(255,255,255,0.025) 20px
  );
}

footer {
  padding: 10px 16px 28px;
  text-align: center;
  color: var(--muted);
  font-size: 0.75rem;
}

@media (max-width: 430px) {
  header { padding: 14px 12px 6px; }
  h1 { font-size: 1.35rem; }
  .about { font-size: 0.8rem; }
  .grid { --gap: 6px; --chrome: 230px; width: min(94vw, calc((100vh - var(--chrome)) * var(--cols) / var(--rows))); }
  main { padding: 8px; }
}

/* No sliding, no fading: the board still steps, three times slower (app.js), and the
   pictures simply appear. */
@media (prefers-reduced-motion: reduce) {
  .tile, .tile img { transition: none !important; }
  .tile:hover img.shown { transform: scale(1); }
}
