/*
 * styles.css — the chrome around the canvas.
 *
 * Everything is sized for a thumb first: no interactive control is under 44px,
 * the dock buttons are 60px tall, and the whole HUD is pinned with
 * env(safe-area-inset-*) so nothing hides behind a notch or a home bar. The
 * canvas owns the middle of the screen; this file must never cover it.
 */

:root {
  --ink: #fdf3e3;
  --muted: #d7b795;
  --gold: #ffb43d;
  --gold-2: #ff8a1e;
  --panel: #2a1409;
  --panel-2: #3a1d0c;
  --edge: rgba(255, 190, 110, .22);
  --green: #33c25c;
  --safe-t: env(safe-area-inset-top, 0px);
  --safe-b: env(safe-area-inset-bottom, 0px);
  font-synthesis-weight: none;
}

* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }

html, body {
  margin: 0;
  height: 100%;
  overflow: hidden;
  background: #150a04;
  color: var(--ink);
  font-family: 'Trebuchet MS', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
  overscroll-behavior: none;
  touch-action: manipulation;
}

#game {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  touch-action: none;
}

.ui {
  position: fixed;
  inset: 0;
  display: flex;
  flex-direction: column;
  pointer-events: none;
  z-index: 2;
}
.ui > * { pointer-events: auto; }

/* ------------------------------------------------------------------- HUD */

.hud {
  display: flex;
  align-items: center;
  gap: .5rem;
  padding: calc(var(--safe-t) + 8px) 10px 8px;
}

.chip {
  display: flex;
  align-items: baseline;
  gap: .35rem;
  padding: .42rem .7rem;
  border-radius: 999px;
  background: linear-gradient(180deg, rgba(88, 45, 18, .92), rgba(46, 22, 9, .92));
  border: 1px solid var(--edge);
  box-shadow: 0 4px 14px rgba(0, 0, 0, .45), inset 0 1px 0 rgba(255, 210, 150, .16);
  font-size: .78rem;
  line-height: 1;
  white-space: nowrap;
}
.chip strong { font-size: 1rem; color: var(--gold); letter-spacing: .01em; }
.chip-key { color: var(--muted); font-size: .7rem; text-transform: uppercase; letter-spacing: .07em; }
.chip-mid { margin-right: auto; }

.hud-btns { display: flex; align-items: center; gap: .4rem; }

.vip-badge {
  display: none;
  padding: .3rem .5rem;
  border-radius: 8px;
  font-size: .64rem;
  font-weight: 800;
  letter-spacing: .1em;
  color: #2a1409;
  background: linear-gradient(180deg, #ffd97a, #ff9f1f);
  box-shadow: 0 3px 10px rgba(255, 150, 30, .4);
}
body.vip .vip-badge { display: inline-block; }

.round {
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  border: 1px solid var(--edge);
  background: linear-gradient(180deg, rgba(88, 45, 18, .92), rgba(46, 22, 9, .92));
  box-shadow: 0 4px 14px rgba(0, 0, 0, .45), inset 0 1px 0 rgba(255, 210, 150, .16);
  cursor: pointer;
  padding: 0;
}
.round svg { width: 22px; height: 22px; fill: var(--ink); stroke: var(--ink); }
.round svg .wave { stroke: var(--ink); }
.round svg .mute-x { display: none; }
.round.off svg .wave { display: none; }
.round.off svg .mute-x { display: block; }
.round.gift {
  background: linear-gradient(180deg, #ffd177, #ff8f1c);
  border-color: rgba(255, 226, 170, .6);
  animation: giftpulse 2.6s ease-in-out infinite;
}
.round.gift svg { fill: #4a2408; stroke: none; }
@keyframes giftpulse {
  0%, 100% { box-shadow: 0 4px 14px rgba(255, 150, 30, .35); }
  50% { box-shadow: 0 4px 22px rgba(255, 170, 60, .8); }
}

.best {
  margin: -2px 0 0;
  padding: 0 14px;
  font-size: .68rem;
  color: rgba(215, 183, 149, .75);
  pointer-events: none;
}
.best strong { color: var(--muted); }

/* ------------------------------------------------------------------ toast */

/* Pinned just above the dock, never over the board.
   At `top: 46%` this landed in the middle of the glasses — including on the one
   message that matters most, "here, a spare glass, on the house", where it
   covered the shelf the new glass had just appeared on. A message about the
   board must not hide the board. */
.toast {
  position: absolute;
  left: 50%;
  bottom: calc(var(--safe-b) + 92px);
  transform: translate(-50%, -6px);
  max-width: min(330px, 90vw);
  text-align: center;
  padding: .7rem 1rem;
  border-radius: 14px;
  background: rgba(24, 11, 4, .93);
  border: 1px solid var(--edge);
  color: var(--ink);
  font-size: .85rem;
  opacity: 0;
  transition: opacity .22s ease, transform .22s ease;
  pointer-events: none;
}
.toast.in { opacity: 1; transform: translate(-50%, 0); }

/* ------------------------------------------------------------------- dock */

.dock {
  margin-top: auto;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 8px;
  padding: 0 10px 4px;
}

.dock-btn {
  height: 60px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 3px;
  border-radius: 16px;
  border: 1px solid var(--edge);
  background: linear-gradient(180deg, rgba(92, 48, 19, .95), rgba(44, 21, 8, .95));
  box-shadow: 0 6px 18px rgba(0, 0, 0, .5), inset 0 1px 0 rgba(255, 210, 150, .18);
  color: var(--ink);
  font: inherit;
  font-size: .74rem;
  cursor: pointer;
  padding: 0;
}
.dock-btn svg { width: 21px; height: 21px; fill: none; stroke: var(--ink); }
.dock-btn b { color: var(--gold); }
.dock-btn:disabled { opacity: .42; }
.dock-btn:active { transform: translateY(1px); }
/* "+ Glass" is a paywall trigger sitting in the game's own toolbar. Painted
   solid gold it was the loudest thing on the screen — louder than Undo, louder
   than the board — which is how a puzzle starts reading like a shop. It keeps a
   gold outline so it is still findable, and the pulsing gift button in the HUD
   remains the one always-on offer surface. */
.dock-btn.locked {
  background: linear-gradient(180deg, rgba(92, 48, 19, .95), rgba(44, 21, 8, .95));
  border-color: rgba(255, 190, 110, .55);
  color: var(--gold);
}
.dock-btn.locked svg { stroke: var(--gold); }
.dock-btn.locked span { font-weight: 700; }

/* Fine print, not a site footer. These links have to exist — a game that takes
   money needs its terms, refund policy and privacy page reachable from the page
   that takes it, and on this zone in particular nothing legal gets quietly
   removed. But at .62rem in near-solid cream they read as the footer of a web
   page bolted under a game, which is one of the things that made the portfolio
   look templated. Same links, same position, a third of the visual weight. */
.legal {
  margin: 0;
  padding: 2px 10px calc(var(--safe-b) + 5px);
  text-align: center;
  font-size: .55rem;
  letter-spacing: .02em;
}
.legal a { color: rgba(215, 183, 149, .34); text-decoration: none; margin: 0 .38rem; }
.legal a:hover, .legal a:focus-visible { color: var(--gold); }

/* --------------------------------------------------------------- overlays */

/*
 * The offer used to be a centred card that covered ~82% of a 390x844 viewport:
 * a stranger's first painted frame was a wall of text over a game they could
 * not see. Standing instruction 24 asks for the popup AND for free play behind
 * it, and only the first half was being delivered.
 *
 * It is now a bottom sheet. The card is anchored to the dock, capped so the top
 * of the screen keeps showing the real board, and the scrim over the board is
 * light while the scrim under the card is heavy — so the glasses read as a live
 * game waiting rather than as a greyed-out screenshot.
 */
.sheet, .paywall {
  position: fixed;
  inset: 0;
  z-index: 20;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  padding: 10px;
  background:
    linear-gradient(180deg, rgba(12, 5, 2, .18) 0%, rgba(12, 5, 2, .34) 34%, rgba(12, 5, 2, .72) 62%);
  opacity: 0;
  transition: opacity .22s ease;
}
.sheet.in, .paywall.in { opacity: 1; }

.sheet-card, .pw-card {
  position: relative;
  width: min(400px, 100%);
  margin: 0 auto;
  max-height: calc(100dvh - 20px);
  overflow-y: auto;
  text-align: center;
  padding: 1.1rem 1.1rem calc(.9rem + var(--safe-b));
  border-radius: 24px;
  background: linear-gradient(180deg, var(--panel-2), var(--panel));
  border: 1px solid var(--edge);
  box-shadow: 0 -18px 60px rgba(0, 0, 0, .7), inset 0 1px 0 rgba(255, 210, 150, .16);
  transform: translateY(26px);
  transition: transform .26s cubic-bezier(.2, .9, .3, 1.2);
}
.sheet.in .sheet-card, .paywall.in .pw-card { transform: none; }

/* The arrival card is the one a stranger meets before playing a single move, so
   it is held to a hard ceiling: the board above it must stay on screen. The
   later cards (a jammed board, the level gate) are allowed to be taller —
   by then the player has seen the game and is reading, not glancing.
   The perk sub-labels fold away there and the legal row tightens to one line,
   but the legal row itself NEVER goes: merchant of record, refunds and the
   restore link sit next to a price, and hiding them to win vertical space would
   be trading a stranger's trust for a screenshot. */
.paywall[data-wall="arrival"] .pw-card { max-height: min(60dvh, 540px); }
/* The dead-board card is capped too, for a different reason: its whole argument
   is the board sitting above it with nothing left to pour. A card that covers
   the evidence is asking the player to take the jam on trust. */
.paywall[data-wall="stuck"] .pw-card { max-height: min(66dvh, 580px); }
.paywall[data-wall="arrival"] .pw-list li span,
.paywall[data-wall="stuck"] .pw-list li span { display: none; }
/* Collapse the vertical padding only — NOT the left padding, which is what the
   green tick sits in. Writing this as `padding: .3rem 0` put every tick on top
   of the first character of its own label. */
.paywall[data-wall="arrival"] .pw-list li,
.paywall[data-wall="stuck"] .pw-list li { padding-top: .3rem; padding-bottom: .3rem; }
.paywall[data-wall="arrival"] .pw-legal,
.paywall[data-wall="stuck"] .pw-legal { font-size: .6rem; line-height: 1.5; margin-top: .5rem; }
.paywall[data-wall="arrival"] .pw-sub { display: none; }

.stars { display: flex; justify-content: center; gap: .5rem; margin-bottom: .5rem; }
.star { width: 46px; height: 46px; fill: rgba(255, 255, 255, .13); transition: fill .3s ease, transform .3s cubic-bezier(.2,.9,.3,1.6); }
.star.on { fill: url(#g); fill: #ffc61a; filter: drop-shadow(0 3px 10px rgba(255, 180, 40, .6)); transform: scale(1.08); }

.sheet-card h2, .pw-card h2 { margin: .1rem 0 .3rem; font-size: 1.3rem; line-height: 1.2; }
.sheet-sub { margin: 0 0 .4rem; color: var(--muted); font-size: .88rem; }
/* How much free game is left, on the screen where they just succeeded — the
   moment a player is most willing to care about it. */
.sheet-run { margin: 0 0 .8rem; font-size: .75rem; color: var(--gold); }
.sheet-run:empty { display: none; }

.btn {
  display: block;
  width: 100%;
  padding: .95rem 1rem;
  margin-top: .5rem;
  border: 0;
  border-radius: 15px;
  font: inherit;
  font-size: 1rem;
  font-weight: 700;
  cursor: pointer;
  min-height: 52px;
}
.btn.primary {
  color: #3a1a06;
  background: linear-gradient(180deg, #ffd977, #ff981d);
  box-shadow: 0 10px 26px rgba(255, 150, 30, .38), inset 0 1px 0 rgba(255, 255, 255, .55);
}
.btn.primary:active { transform: translateY(1px); }
.btn.ghost { background: transparent; color: var(--muted); border: 1px solid var(--edge); font-weight: 600; }

/* ------------------------------------------------------------- gift pack */

.pw-close {
  position: absolute;
  top: 10px;
  right: 10px;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  border: 1px solid var(--edge);
  background: rgba(0, 0, 0, .3);
  display: grid;
  place-items: center;
  cursor: pointer;
  padding: 0;
}
.pw-close svg { width: 20px; height: 20px; stroke: var(--muted); fill: none; }

.pw-badge {
  display: inline-block;
  margin: 0 0 .55rem;
  padding: .3rem .66rem;
  border-radius: 999px;
  font-size: .62rem;
  font-weight: 800;
  letter-spacing: .14em;
  color: #3a1a06;
  background: linear-gradient(180deg, #ffe09a, #ffab2e);
}
.pw-kicker { margin: 0; font-size: .74rem; letter-spacing: .12em; text-transform: uppercase; color: var(--muted); }
.pw-sub { margin: .35rem 0 .9rem; color: var(--muted); font-size: .88rem; line-height: 1.45; }

/* Two columns, four short claims. The old list was four full sentences stacked
   vertically — ~230px of prose that nobody reads on an offer card and that was
   most of what pushed the board off screen. */
.pw-list {
  list-style: none;
  margin: 0 0 .7rem;
  padding: 0;
  text-align: left;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: .1rem .6rem;
}
.pw-list li {
  position: relative;
  padding: .36rem 0 .36rem 1.45rem;
  font-size: .78rem;
  line-height: 1.3;
  color: var(--muted);
}
.pw-list strong { display: block; color: var(--ink); font-size: .82rem; }
.pw-list li span { display: block; font-size: .68rem; opacity: .85; }
.pw-list li::before {
  content: '';
  position: absolute;
  left: 0;
  top: .62rem;
  width: 10px;
  height: 5px;
  border-left: 2.2px solid var(--green);
  border-bottom: 2.2px solid var(--green);
  transform: rotate(-45deg);
}

.pw-price { display: flex; align-items: baseline; justify-content: center; gap: .5rem; margin: .2rem 0 .1rem; }
.pw-price span { font-size: 1.85rem; font-weight: 800; color: var(--gold); }
.pw-price em { font-style: normal; font-size: .74rem; color: var(--muted); }

/* The catalogue price is $2.49 and Paddle's button reads "Pay $2.70" in a taxed
   territory. Nobody was lying, but a number that grows between the card and the
   card form is the single most conversion-destroying thing a small purchase can
   do, so the card says it first. */
.pw-tax { margin: .2rem 0 .55rem; font-size: .64rem; color: rgba(215, 183, 149, .62); line-height: 1.4; }

.pw-free { margin: .6rem 0 0; font-size: .72rem; color: rgba(215, 183, 149, .8); line-height: 1.45; }
.pw-error { margin: .55rem 0 0; font-size: .78rem; color: #ff9b8a; }

.pw-close-text {
  display: block;
  width: 100%;
  margin: .6rem 0 .2rem;
  padding: .8rem;
  min-height: 46px;
  border: 1px solid var(--edge);
  border-radius: 13px;
  background: transparent;
  color: var(--muted);
  font: inherit;
  font-size: .86rem;
  cursor: pointer;
}

.pw-legal { margin: .7rem 0 0; font-size: .64rem; color: rgba(215, 183, 149, .55); line-height: 1.6; }
.pw-legal a, .linkish { color: rgba(215, 183, 149, .8); }
.linkish { background: none; border: 0; padding: 0; font: inherit; font-size: inherit; text-decoration: underline; cursor: pointer; }
.pw-legal span { margin: 0 .28rem; }

/* ------------------------------------------------------ wider than a phone */

@media (min-width: 620px) {
  .hud, .dock, .legal { max-width: 520px; margin-left: auto; margin-right: auto; }
  .dock { padding-bottom: 8px; }
}

@media (prefers-reduced-motion: reduce) {
  .round.gift { animation: none; }
  .sheet-card, .pw-card, .toast, .star { transition: none; }
}

/* Static pages (terms, privacy, refunds, about, unlocked) reuse the palette. */
.page {
  position: relative;
  z-index: 1;
  max-width: 680px;
  margin: 0 auto;
  padding: 2rem 1.2rem 3rem;
  line-height: 1.65;
}
body.doc { overflow: auto; background: radial-gradient(120% 80% at 50% 0%, #3a1c0b 0%, #150a04 70%); }
.page h1 { font-size: 1.7rem; margin: 0 0 .3rem; }
.page h2 { font-size: 1.05rem; margin: 1.6rem 0 .4rem; color: var(--gold); }
.page p, .page li { color: var(--muted); font-size: .92rem; }
.page a { color: var(--gold); }
.page .back {
  display: inline-block;
  margin-bottom: 1.2rem;
  padding: .55rem 1.1rem;
  border-radius: 999px;
  background: linear-gradient(180deg, #ffd977, #ff981d);
  color: #3a1a06;
  text-decoration: none;
  font-weight: 700;
}
.page .meta { font-size: .74rem; color: rgba(215, 183, 149, .6); }
