/* Brand palette sampled pixel-for-pixel from the logo artwork. */
:root {
  --plum: #942b69;
  --magenta: #da0b8c;
  --orange: #f05523;
  --crimson: #ea1c24;
  --paper: #fbfafc;

  --logo-width: clamp(11rem, 34vw, 20rem);
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

html,
body {
  height: 100%;
  margin: 0;
}

body {
  background: var(--paper);
  /* Blobs are painted with translucent colour and can extend past the viewport;
     clip sideways only, since the game may need vertical room on short screens. */
  overflow-x: hidden;
  font-family: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
}

main {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(1.25rem, 3.5vh, 2.25rem);
  padding: clamp(1.25rem, 4vh, 2.5rem) 1rem 1rem;
}

.lockup {
  display: flex;
  flex-direction: column;
  align-items: center;
}

.logo {
  width: var(--logo-width);
  height: auto;
  /* Lifts the mark off the drifting colour behind it. */
  filter: drop-shadow(0 18px 42px rgb(60 10 44 / 0.16));
  animation: rise 1200ms cubic-bezier(0.22, 1, 0.36, 1) both;
}

.tagline {
  margin: clamp(0.7rem, 1.6vh, 1.1rem) 0 0;
  color: var(--plum);
  font-size: clamp(0.66rem, 1.5vw, 0.86rem);
  font-weight: 500;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  /* The tracking adds space after the final letter; pull it back so the line
     stays optically centred under the mark. */
  text-indent: 0.3em;
  text-align: center;
  opacity: 0.92;
  animation: rise 1200ms cubic-bezier(0.22, 1, 0.36, 1) 260ms both;
}

footer {
  position: relative;
  z-index: 1;
  padding: clamp(1.1rem, 3vh, 2rem) 1.5rem clamp(1.6rem, 4vh, 2.4rem);
  text-align: center;
  /* In normal flow now — fixed positioning would overlay the board on short
     screens. */
}

.contact {
  display: inline-block;
  padding: 0.45em 0.2em;
  color: var(--plum);
  font-size: clamp(0.78rem, 1.4vw, 0.92rem);
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  text-indent: 0.14em;
  text-decoration: none;
  opacity: 0.78;
  transition: opacity 180ms ease, border-color 180ms ease;
  border-bottom: 1px solid rgb(148 43 105 / 0.35);
  animation: rise 1200ms cubic-bezier(0.22, 1, 0.36, 1) 520ms both;
}

.contact:hover,
.contact:focus-visible {
  opacity: 1;
  border-bottom-color: rgb(148 43 105 / 0.9);
}

.contact:focus-visible {
  outline: 2px solid var(--plum);
  outline-offset: 4px;
  border-radius: 2px;
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ---------- animated background ---------- */

.backdrop {
  position: fixed;
  inset: 0;
  overflow: hidden;
  /* Isolates the blend modes below from the page content. */
  isolation: isolate;
}

.blob {
  position: absolute;
  display: block;
  border-radius: 50%;
  /* Soft-edged radial fills rather than filter: blur() — same look, far cheaper
     to composite on a page that animates continuously.
     The colour stop ends at 50%: a softer falloff spreads the blob so thin that
     even large movements are imperceptible. */
  mix-blend-mode: multiply;
  will-change: transform, opacity;
}

.blob--plum {
  top: -18vmax;
  left: -14vmax;
  width: 52vmax;
  height: 52vmax;
  background: radial-gradient(circle at 50% 50%, rgb(148 43 105 / 0.42), rgb(148 43 105 / 0) 50%);
  animation: drift-a 19s ease-in-out infinite;
}

.blob--magenta {
  bottom: -20vmax;
  left: -12vmax;
  width: 46vmax;
  height: 46vmax;
  background: radial-gradient(circle at 50% 50%, rgb(218 11 140 / 0.36), rgb(218 11 140 / 0) 50%);
  animation: drift-b 23s ease-in-out infinite;
}

.blob--orange {
  top: -14vmax;
  right: -16vmax;
  width: 44vmax;
  height: 44vmax;
  background: radial-gradient(circle at 50% 50%, rgb(240 85 35 / 0.36), rgb(240 85 35 / 0) 50%);
  animation: drift-c 17s ease-in-out infinite;
}

.blob--crimson {
  right: -18vmax;
  bottom: -18vmax;
  width: 50vmax;
  height: 50vmax;
  background: radial-gradient(circle at 50% 50%, rgb(234 28 36 / 0.34), rgb(234 28 36 / 0) 50%);
  animation: drift-d 26s ease-in-out infinite;
}

/* A rotating sweep keeps the field from ever looking static. */
.sheen {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 190vmax;
  height: 190vmax;
  margin: -95vmax 0 0 -95vmax;
  background: conic-gradient(
    from 0deg,
    rgb(148 43 105 / 0.10),
    rgb(240 85 35 / 0.07),
    rgb(218 11 140 / 0.10),
    rgb(234 28 36 / 0.07),
    rgb(148 43 105 / 0.10)
  );
  animation: spin 38s linear infinite;
  will-change: transform;
}

/* Breaks up gradient banding on wide, flat colour fields. */
.grain {
  position: absolute;
  inset: 0;
  opacity: 0.12;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)' opacity='0.42'/%3E%3C/svg%3E");
}

/* Travel is a large fraction of each blob's own size, so the colour visibly
   sweeps across the page rather than nudging. Opacity shifts alongside it to
   make the movement read even where the travel is toward the viewport edge. */
@keyframes drift-a {
  0%, 100% { transform: translate3d(0, 0, 0) scale(1); opacity: 1; }
  30% { transform: translate3d(46vw, 14vh, 0) scale(1.28); opacity: 0.75; }
  62% { transform: translate3d(22vw, 46vh, 0) scale(0.86); opacity: 1; }
}

@keyframes drift-b {
  0%, 100% { transform: translate3d(0, 0, 0) scale(1); opacity: 0.95; }
  35% { transform: translate3d(54vw, -30vh, 0) scale(1.22); opacity: 1; }
  70% { transform: translate3d(16vw, -12vh, 0) scale(0.84); opacity: 0.8; }
}

@keyframes drift-c {
  0%, 100% { transform: translate3d(0, 0, 0) scale(1); opacity: 1; }
  33% { transform: translate3d(-50vw, 32vh, 0) scale(0.82); opacity: 0.78; }
  66% { transform: translate3d(-18vw, 12vh, 0) scale(1.3); opacity: 1; }
}

@keyframes drift-d {
  0%, 100% { transform: translate3d(0, 0, 0) scale(1); opacity: 0.9; }
  40% { transform: translate3d(-38vw, -40vh, 0) scale(1.24); opacity: 1; }
  75% { transform: translate3d(-56vw, -10vh, 0) scale(0.88); opacity: 0.82; }
}

@keyframes spin {
  to { transform: rotate(360deg); }
}

@keyframes rise {
  from {
    opacity: 0;
    transform: translateY(14px) scale(0.985);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

/* Motion is decorative here, so honour the preference completely: the palette
   stays, the movement stops. */
@media (prefers-reduced-motion: reduce) {
  .blob,
  .sheen,
  .logo,
  .tagline,
  .contact {
    animation: none !important;
  }
}

/* ---------- game ---------- */

.game {
  --cell: clamp(15px, min(3.4vw, 3.1vh), 30px);
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: auto auto;
  align-items: start;
  gap: clamp(0.75rem, 2vw, 1.4rem);
}

.game__board {
  position: relative;
  border-radius: 10px;
  /* Frosted plate so the drifting blobs stay visible but never fight the
     bricks for attention. */
  background: rgb(255 255 255 / 0.62);
  backdrop-filter: blur(6px);
  box-shadow:
    0 1px 0 rgb(255 255 255 / 0.7) inset,
    0 14px 40px rgb(60 10 44 / 0.13);
  border: 1px solid rgb(148 43 105 / 0.16);
  padding: 6px;
}

#board {
  display: block;
  width: calc(var(--cell) * 10);
  height: calc(var(--cell) * 20);
  border-radius: 5px;
  touch-action: none; /* swipe gestures drive the piece, not the page */
}

/* ---------- side panel ---------- */

.game__side {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  min-width: clamp(6.5rem, 16vw, 9rem);
}

.stat {
  padding: 0.5rem 0.7rem;
  border-radius: 8px;
  background: rgb(255 255 255 / 0.62);
  border: 1px solid rgb(148 43 105 / 0.16);
  backdrop-filter: blur(6px);
}

.stat--split {
  display: flex;
  justify-content: space-between;
  gap: 0.5rem;
}

.stat--next { display: flex; flex-direction: column; gap: 0.25rem; }

.stat__label {
  display: block;
  font-size: 0.6rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: rgb(60 10 44 / 0.55);
}

.stat__value {
  display: block;
  font-size: clamp(0.95rem, 2.4vw, 1.2rem);
  font-weight: 600;
  color: var(--plum);
  font-variant-numeric: tabular-nums;
}

#next { display: block; width: 100%; height: clamp(48px, 9vw, 68px); }

/* ---------- buttons ---------- */

.btn {
  font: inherit;
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 0.6em 1.1em;
  border-radius: 8px;
  border: 1px solid transparent;
  cursor: pointer;
  transition: opacity 150ms ease, transform 120ms ease;
}

.btn:disabled { opacity: 0.4; cursor: not-allowed; }
.btn:not(:disabled):active { transform: translateY(1px); }

.btn--primary { background: var(--plum); color: #fff; }
.btn--primary:hover:not(:disabled) { background: #a83278; }

.btn--ghost {
  background: rgb(255 255 255 / 0.62);
  border-color: rgb(148 43 105 / 0.24);
  color: var(--plum);
  backdrop-filter: blur(6px);
}

.btn:focus-visible,
.pad__btn:focus-visible,
.contact:focus-visible {
  outline: 2px solid var(--plum);
  outline-offset: 2px;
}

/* ---------- overlay ---------- */

.overlay {
  position: absolute;
  inset: 6px;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  padding: 1rem;
  border-radius: 5px;
  background: rgb(255 255 255 / 0.9);
  backdrop-filter: blur(3px);
  text-align: center;
}

.overlay[hidden] { display: none; }

.overlay__title {
  margin: 0;
  font-size: clamp(1.1rem, 3.4vw, 1.5rem);
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--plum);
}

.overlay__body {
  margin: 0;
  max-width: 22ch;
  font-size: 0.8rem;
  line-height: 1.5;
  color: rgb(60 10 44 / 0.7);
}

.overlay__keys {
  display: none;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.2rem 0.6rem;
  margin: 0.4rem 0 0;
  font-size: 0.62rem;
  letter-spacing: 0.04em;
  color: rgb(60 10 44 / 0.5);
}

/* Key hints only help where there is a keyboard. */
@media (hover: hover) and (pointer: fine) {
  .overlay__keys { display: flex; }
}

/* ---------- touch pad ---------- */

.pad {
  display: none;
  grid-column: 1 / -1;
  grid-template-columns: repeat(4, 1fr);
  gap: 0.45rem;
  width: 100%;
}

.pad__btn {
  font: inherit;
  font-size: 1.15rem;
  font-weight: 600;
  color: var(--plum);
  padding: 0.7em 0;
  border-radius: 10px;
  border: 1px solid rgb(148 43 105 / 0.22);
  background: rgb(255 255 255 / 0.72);
  backdrop-filter: blur(6px);
  cursor: pointer;
  touch-action: manipulation;
  user-select: none;
}

.pad__btn:active { background: rgb(148 43 105 / 0.12); }
.pad__btn--wide { grid-column: span 4; font-size: 0.8rem; letter-spacing: 0.1em; text-transform: uppercase; }

/* Coarse pointer means no keyboard to rely on, so the pad becomes the control
   surface. */
@media (pointer: coarse) {
  .pad { display: grid; }
}

/* Narrow screens: keep the panel beside the board rather than beneath it, and
   let the board claim every pixel the rail does not need. Sized off both the
   remaining width and the viewport height so it never pushes the touch pad off
   screen. */
@media (max-width: 34rem) {
  .game {
    --rail: clamp(4.1rem, 21vw, 5.4rem);
    --board-w: min(calc(100vw - var(--rail) - 2.6rem), calc(58svh / 2));
    grid-template-columns: auto var(--rail);
    justify-content: center;
    gap: 0.55rem;
  }

  #board {
    width: var(--board-w);
    height: calc(var(--board-w) * 2);
  }

  .game__board { padding: 4px; }

  .game__side {
    min-width: 0;
    gap: 0.35rem;
  }

  .stat { padding: 0.35rem 0.45rem; border-radius: 7px; }

  /* Stacked rather than side by side — the rail is too narrow for two columns. */
  .stat--split { flex-direction: column; gap: 0.35rem; }

  .stat__label { font-size: 0.5rem; letter-spacing: 0.12em; }
  .stat__value { font-size: 0.92rem; }

  #next { height: 34px; }

  .game__side .btn--ghost {
    padding: 0.5em 0.4em;
    font-size: 0.6rem;
    letter-spacing: 0.06em;
  }

  .pad { margin-top: 0.15rem; }

  /* Tighten the vertical rhythm so the lockup, board, pad and contact link all
     land inside one screen without scrolling. */
  main { gap: 0.75rem; padding-top: 0.9rem; }
  .tagline { margin-top: 0.5rem; }
  footer { padding: 0.7rem 1.5rem 1rem; }
}

/* Very short phones: trade a little board height for the controls. */
@media (max-width: 34rem) and (max-height: 700px) {
  .game { --board-w: min(calc(100vw - var(--rail) - 2.6rem), calc(50svh / 2)); }
}
