/* =========================================================================
   WHAT'S THE GAME? — the parent site

   DESIGN SYSTEM — risograph print: flat spot colour on newsprint, heavy ink
   outlines, hard offset shadows. No gradients, no blur.

   Carried over from What's the Word? and What's the Number? unchanged, because
   this is where they came from and it should look it. The three moves that
   create the look:
     1. border: 2–2.5px solid var(--ink) on every raised element
     2. box-shadow: 5px 5px 0 var(--ink) — hard, no blur, no alpha
     3. :active { transform: translate(3px,3px); box-shadow: 2px 2px 0 }

   Contrast: the ratios beside each token are against --paper and they matter.
   --pink/--pink-deep exist because the bright one is a FILL that fails AA as
   text. The two tile tints are the corrected values from WTN's FOUNDATIONS §2
   — the obvious #ffe6f0 and #e4eaff both put --muted under 4.5:1. Check any
   new pair before adding it.

   Light only, deliberately. Both games are newsprint and have no dark mode;
   a dark parent would not be the same product family.
   ========================================================================= */

:root {
  --paper: #f6f1e4;
  --card: #fffdf6;
  --ink: #17173a;
  --muted: #6e6a80; /* 4.61 on paper */
  --yellow: #ffc42e;
  --pink: #ff2e7e;
  --pink-deep: #d31460; /* 4.61 on paper */
  --pink-tint: #fff0f5; /* --muted sits at 4.72 here */
  --blue: #2b57e6; /* 5.16 on paper */
  --blue-tint: #edf1ff;
  --green: #12a05f;
  --green-tint: #e8f7ef;
  --yellow-tint: #fff3cf;
  --dashed: #b9b4c4;

  --font-sans: "Space Grotesk", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --font-mono: "IBM Plex Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;

  --safe-bottom: env(safe-area-inset-bottom, 0px);
  --safe-top: env(safe-area-inset-top, 0px);
}

* {
  box-sizing: border-box;
}

html,
body {
  margin: 0;
  padding: 0;
}

body {
  background-color: var(--paper);
  background-image: radial-gradient(rgba(23, 23, 58, 0.07) 1px, transparent 1px);
  background-size: 4px 4px;
  color: var(--ink);
  font-family: var(--font-sans);
  -webkit-font-smoothing: antialiased;
  -webkit-tap-highlight-color: transparent;
  min-height: 100dvh;
}

/* 480px matches the games' .screen exactly, so opening the hub and opening a
   game feel like the same app at the same width. It widens to a two-up grid
   only once there is genuinely room for two full tiles side by side. */
.screen {
  max-width: 480px;
  margin: 0 auto;
  width: 100%;
  padding: calc(26px + var(--safe-top)) 18px calc(40px + var(--safe-bottom));
}

@media (min-width: 900px) {
  .screen {
    max-width: 940px;
    padding: calc(46px + var(--safe-top)) 40px calc(56px + var(--safe-bottom));
  }
}

/* ---------- BRAND ---------- */
.home-top {
  text-align: center;
  padding: 4px 0 0;
}

/* Word's mark is "?", Number's is "=". The parent's is the blank they both
   leave you — one bar, same yellow chip, same -3° tilt. */
.brand-mark {
  width: 52px;
  height: 52px;
  border-radius: 12px;
  background: var(--yellow);
  border: 2.5px solid var(--ink);
  box-shadow: 4px 4px 0 var(--ink);
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 0 auto 20px;
  transform: rotate(-3deg);
}
.brand-mark i {
  display: block;
  width: 26px;
  height: 6px;
  border-radius: 3px;
  background: var(--ink);
}

/* Reachable by assistive tech, invisible on screen. Used for the headline's
   stable name while the visible one is mid-animation. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.brand-title {
  font-weight: 700;
  font-size: 34px;
  line-height: 0.95;
  letter-spacing: -0.035em;
  margin: 0;
  text-transform: uppercase;
  text-wrap: balance;
}
.brand-sub {
  color: var(--muted);
  font-size: 14.5px;
  margin: 13px 0 0;
  font-weight: 500;
}

@media (min-width: 900px) {
  .brand-mark {
    width: 58px;
    height: 58px;
  }
  .brand-mark i {
    width: 29px;
    height: 7px;
  }
  .brand-title {
    font-size: 46px;
  }
  .brand-title br {
    display: none;
  }
}

/* The wordmark is a sentence with a blank in it, and the blank is the whole
   idea: each game finishes it. app.js retypes this through the live games and
   rests on "Game". Held still under prefers-reduced-motion.

   THE BLANK IS A FIXED-WIDTH BOX, and that is load-bearing. With the word at
   its natural width the whole centred headline re-centres on every keystroke —
   measured at ~87px of travel on desktop as "Number" erases, which is far more
   distracting than the hard swap this animation replaced. Reserving the widest
   word's width means "WHAT'S THE" and the "?" never move: only the letters and
   the caret do, which is what typing actually looks like.

   The "?" sits INSIDE the box, after the caret, so it slides along with the
   word the way it would in any text field: "GAME|?" backspaces to "GAM|?".
   Keeping it outside left a growing gap between the word and its own question
   mark, which read as a spacing bug. The leftover width then falls after the
   "?", where it is simply invisible.

   The cost is that a short word sits up to half a word-width left of true
   centre — about 27px on desktop for "GAME" against the reserved "NUMBER".
   That is a static offset nobody can see without a ruler, traded against 87px
   of motion that everybody could.

   min-width here is the no-JS fallback in ch; app.js replaces it with a
   measured pixel width, because Space Grotesk is proportional and ch is only
   an approximation of the widest word. */
.brand-blank {
  display: inline-block;
  min-width: 7ch;
  text-align: left;
  /* Belt and braces: if the measured width is ever a pixel short, the caret
     must not wrap onto a second line inside the box. */
  white-space: nowrap;
}
.brand-blank [data-slot] {
  color: var(--pink-deep);
}
.brand-caret {
  display: inline-block;
  width: 0.5ch;
  background: var(--ink);
  color: transparent;
  margin-left: 0.06em;
  margin-right: 0.1em;
  animation: blink 1.05s step-end infinite;
}
/* Solid while characters are being added or removed. A cursor that blinks
   mid-keystroke looks broken; real ones hold steady until you stop typing. */
.brand-caret.is-moving {
  animation: none;
  opacity: 1;
}
@keyframes blink {
  0%,
  100% {
    opacity: 1;
  }
  50% {
    opacity: 0;
  }
}

/* Both games roll at midnight IST, so one countdown is true for both. It is
   also the only thing on the page that changes on its own, which is most of
   why the page is worth opening twice. */
.drop-badge {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  background: var(--yellow);
  color: var(--ink);
  border: 2px solid var(--ink);
  padding: 6px 13px;
  border-radius: 999px;
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.04em;
  margin: 20px auto 0;
}
.drop-badge b {
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

/* ---------- TILES ---------- */
.game-stack {
  display: flex;
  flex-direction: column;
  gap: 14px;
  margin-top: 24px;
}
@media (min-width: 900px) {
  .game-stack {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 18px;
    margin-top: 30px;
    align-items: start;
  }
}

.game-tile {
  display: block;
  text-align: left;
  text-decoration: none;
  color: var(--ink);
  border: 2.5px solid var(--ink);
  border-radius: 16px;
  background: var(--card);
  padding: 16px 17px;
  box-shadow: 5px 5px 0 var(--ink);
  transition:
    transform 0.12s ease,
    box-shadow 0.12s ease;
}
.game-tile:hover {
  transform: translate(-1px, -1px);
  box-shadow: 6px 6px 0 var(--ink);
}
.game-tile:active {
  transform: translate(3px, 3px);
  box-shadow: 2px 2px 0 var(--ink);
}
.game-tile:focus-visible {
  outline: 3px solid var(--blue);
  outline-offset: 3px;
}
.tint-pink {
  background: var(--pink-tint);
}
.tint-blue {
  background: var(--blue-tint);
}
.tint-green {
  background: var(--green-tint);
}
.tint-yellow {
  background: var(--yellow-tint);
}

.tile-top {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 10px;
  min-height: 18px;
}
.tile-eyebrow {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.1em;
  font-weight: 600;
  color: var(--muted);
}

.tile-title {
  font-weight: 700;
  font-size: 21px;
  margin: 9px 0 0;
  letter-spacing: -0.025em;
  display: flex;
  align-items: center;
  gap: 8px;
}
.tile-chip {
  width: 24px;
  height: 24px;
  border-radius: 6px;
  background: var(--yellow);
  border: 2px solid var(--ink);
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 3px;
  font-family: var(--font-mono);
  font-weight: 700;
  font-size: 14px;
  flex: none;
}
.tile-chip i {
  display: block;
  width: 12px;
  height: 3px;
  border-radius: 2px;
  background: var(--ink);
}
/* A mark that is artwork rather than a character: it fills the chip instead of
   sitting on the yellow ground, so each game keeps its own identity. Stays
   full-colour on the "soon" tile too — a named game that is genuinely coming
   should look like itself, not like an empty slot. */
.tile-chip-art {
  background: var(--card);
  padding: 0;
  overflow: hidden;
  gap: 0;
}
.tile-chip-art svg {
  display: block;
  width: 100%;
  height: 100%;
}
/* Two classes, so this beats `.game-soon .tile-chip` regardless of which
   block is written first. Artwork should not sit in a dashed cage. */
.game-soon .tile-chip.tile-chip-art {
  background: var(--card);
  border-style: solid;
  border-color: var(--ink);
}

.tile-desc {
  color: var(--muted);
  font-size: 13.5px;
  margin: 5px 0 0;
  line-height: 1.45;
}

/* Each tile carries a miniature of its own board — the fastest way to say what
   a game is without a screenshot. Neither preview can spoil a daily: the word
   board is always empty, and the equation is not from the live pool. */
.tile-preview {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-top: 13px;
  flex-wrap: wrap;
}
.pv-cell {
  width: 26px;
  height: 30px;
  border: 2px solid var(--ink);
  border-radius: 5px;
  background: var(--card);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-mono);
  font-weight: 700;
  font-size: 14px;
}
/* What's the Book?'s board: a rule per letter, grouped into words. The gap
   between words has to read as clearly wider than the gap between letters, or
   the shape stops being a title and becomes a queue of dashes.

   Two classes, not one: the narrow-screen media query further down sets
   `.tile-preview { gap: 4px }`, and a single class here loses to it on source
   order — which is exactly how this shipped as one long run of dashes. */
.tile-preview.tile-preview-blanks {
  gap: 15px;
}
.pv-word {
  display: flex;
  gap: 4px;
}
.pv-blank {
  width: 15px;
  height: 3px;
  border-radius: 2px;
  background: var(--ink);
}

.pv-cell-blank {
  border-style: dashed;
  border-color: var(--dashed);
  background: transparent;
}
.pv-op {
  width: 26px;
  height: 30px;
  border: 2px dashed var(--dashed);
  border-radius: 5px;
  background: transparent;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-mono);
  font-weight: 700;
  font-size: 14px;
  color: var(--dashed);
}
.pv-eq {
  font-family: var(--font-mono);
  font-weight: 700;
  font-size: 15px;
  color: var(--muted);
  padding: 0 1px;
}
.pv-target {
  border-color: var(--blue);
  background: var(--blue);
  color: var(--card);
  /* Targets run to three digits. A fixed width either clips them or wastes
     the room the operators need to stay on one line. */
  width: auto;
  min-width: 26px;
  padding: 0 6px;
}

/* A five-number equation is eleven items wide and has to survive a 375px
   screen inside a padded tile — about 300px of usable width. At 23px cells
   and 4px gaps it lands at ~288px and stays on one line; at the default 26/6
   the target wrapped onto a row of its own. */
@media (max-width: 430px) {
  .tile-preview {
    gap: 4px;
  }
  .pv-cell,
  .pv-op {
    width: 23px;
    height: 28px;
    font-size: 13px;
  }
  .pv-target {
    width: auto;
    min-width: 23px;
    padding: 0 5px;
  }
}

.tile-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-top: 14px;
  padding-top: 11px;
  border-top: 2px dashed var(--dashed);
}
.tile-host {
  font-family: var(--font-mono);
  font-size: 10.5px;
  color: var(--muted);
  letter-spacing: 0.02em;
}
.tile-play {
  font-family: var(--font-mono);
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.08em;
}
.tint-pink .tile-play {
  color: var(--pink-deep);
}
.tint-blue .tile-play {
  color: var(--blue);
}
.tint-green .tile-play {
  color: var(--green);
}

/* The placeholder. Dashed and shadowless so it reads as an empty slot rather
   than a tile that failed to load. */
.game-soon {
  border: 2.5px dashed var(--dashed);
  border-radius: 16px;
  background: transparent;
  padding: 16px 17px;
}
/* Full ink, not muted. The dashed border and missing shadow already say "not
   playable yet"; greying the name as well made a real, finished game look
   like an empty slot. The anonymous placeholder that used to live here did
   want to look empty — this does not. */
.game-soon .tile-title {
  color: var(--ink);
}
.game-soon .tile-chip {
  background: transparent;
  border-style: dashed;
  border-color: var(--dashed);
}
.game-soon .tile-chip i {
  background: var(--dashed);
}

/* ---------- NOTIFY ---------- */
.notify {
  margin-top: 22px;
  border: 2.5px solid var(--ink);
  border-radius: 16px;
  background: var(--card);
  box-shadow: 5px 5px 0 var(--ink);
  padding: 16px 17px;
}
@media (min-width: 900px) {
  .notify {
    margin-top: 0;
  }
}
.notify h2 {
  font-size: 16px;
  font-weight: 700;
  letter-spacing: -0.02em;
  margin: 0;
}
.notify p {
  color: var(--muted);
  font-size: 13px;
  margin: 5px 0 0;
}
.notify-form {
  display: flex;
  gap: 8px;
  margin-top: 12px;
}
.notify-input {
  flex: 1;
  min-width: 0;
  border: 2px solid var(--ink);
  border-radius: 10px;
  background: var(--paper);
  padding: 9px 11px;
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--ink);
}
.notify-input::placeholder {
  color: var(--muted);
}
.notify-input:focus-visible {
  outline: 3px solid var(--blue);
  outline-offset: 1px;
}
.notify-btn {
  border: 2px solid var(--ink);
  border-radius: 10px;
  background: var(--yellow);
  color: var(--ink);
  padding: 9px 15px;
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.07em;
  box-shadow: 3px 3px 0 var(--ink);
  cursor: pointer;
  white-space: nowrap;
}
.notify-btn:active {
  transform: translate(2px, 2px);
  box-shadow: 1px 1px 0 var(--ink);
}
.notify-btn:disabled {
  opacity: 0.55;
  cursor: default;
}
.notify-btn:focus-visible {
  outline: 3px solid var(--blue);
  outline-offset: 2px;
}
/* One line under the form, coloured by outcome. Reserved so a message does not
   shove the footer down when it appears. */
.notify-msg {
  font-family: var(--font-mono);
  font-size: 11px;
  margin: 9px 0 0;
  min-height: 15px;
  color: var(--muted);
}
.notify-msg.is-ok {
  color: var(--green);
}
.notify-msg.is-err {
  color: var(--pink-deep);
}

/* ---------- FOOT ---------- */
.home-foot {
  margin-top: 24px;
  text-align: center;
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--muted);
  letter-spacing: 0.06em;
}
.home-foot span {
  color: var(--dashed);
  padding: 0 6px;
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation: none !important;
    transition: none !important;
  }
}
