/* Shared with the macOS app's committed DESIGN.md: ink on paper, monospace,
   one green status dot as the only persistent color. */
:root {
  --paper: #F6F4EF;
  --ink: #1C1B19;
  --ink-dim: rgba(28, 27, 25, 0.58);
  --ink-faint: rgba(28, 27, 25, 0.14);
  --ink-soft: rgba(28, 27, 25, 0.07);
  --online: #00A63D;
  --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;

  /* Amber is the tip jar's color and nothing else's. It lives here rather than
     on the support page because the jar is now asked for in two places — the
     page itself and the bubble the dino puts up after a run — and a highlight
     that means "this is the one" has to be the same amber in both or it stops
     meaning anything. Nowhere outside a request for money may use it. */
  --gold: #E8A317;
  --gold-wash: rgba(232, 163, 23, 0.13);
  /* The one glow in the product. DESIGN.md bans shadows beyond the window's
     own, and this is the written exception: it burns for a few seconds on the
     screen that congratulates somebody, on the two things that screen is
     about — the dino and the box asking to keep it alive — and nowhere else.
     A permanent glow would be decoration; a glow that only ever appears at a
     win is punctuation. */
  --gold-glow: rgba(232, 163, 23, 0.34);
  --gold-glow-hot: rgba(232, 163, 23, 0.55);
}

@media (prefers-color-scheme: dark) {
  :root {
    --paper: #161514;
    --ink: #EDEBE6;
    --ink-dim: rgba(237, 235, 230, 0.58);
    --ink-faint: rgba(237, 235, 230, 0.16);
    --ink-soft: rgba(237, 235, 230, 0.08);
    --online: #35C46A;
    --gold: #F5B731;
    --gold-wash: rgba(245, 183, 49, 0.15);
    /* Amber on near-black carries further than amber on paper, so the dark
       glow is dialled back rather than up. */
    --gold-glow: rgba(245, 183, 49, 0.30);
    --gold-glow-hot: rgba(245, 183, 49, 0.48);
  }
}

* { box-sizing: border-box; }

html, body { height: 100%; }

body {
  margin: 0;
  /* The footer band bleeds past the page's gutters; clip the overhang so it
     never turns into a horizontal scrollbar. */
  overflow-x: clip;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--mono);
  font-size: 15px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

.page {
  min-height: 100svh;
  max-width: 1140px;
  margin: 0 auto;
  padding: clamp(20px, 3.5vh, 34px) clamp(20px, 5vw, 56px);
  display: grid;
  grid-template-rows: auto 1fr auto;
  gap: clamp(16px, 2.6vh, 32px);
}

/* ---- masthead ---- */

.masthead {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
}

.mark {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.16em;
  color: var(--ink);
  text-decoration: none;
}

.mark svg { display: block; }

/* The masthead is space-between with two children, so a second button has to
   be wrapped or the two end up at opposite ends of the bar. Wrapping rather
   than restyling the masthead keeps every page's mark hard left and its
   actions hard right, whether there are one of them or two. */
.masthead-actions {
  display: flex;
  align-items: center;
  gap: 10px;
}

.mark .ui-icon {
  width: 20px;
  height: 20px;
}

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

.btn {
  display: inline-block;
  font-family: var(--mono);
  font-size: 13px;
  font-weight: 600;
  text-decoration: none;
  padding: 9px 20px;
  border: 1.5px solid var(--ink);
  background: transparent;
  color: var(--ink);
  cursor: pointer;
  transition: background 0.14s ease, opacity 0.14s ease, transform 0.14s ease;
}

.btn:hover { background: var(--ink-soft); }
.btn:active { transform: translateY(1px); }

.btn:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 3px;
}

.btn-solid {
  background: var(--ink);
  color: var(--paper);
}

.btn-solid:hover {
  background: var(--ink);
  opacity: 0.86;
}

.btn-lg {
  font-size: 14px;
  padding: 13px 24px;
}

/* The game switcher is not a call to action. It was three bordered `.btn`s on
   both the homepage and /play, which put five to seven button shapes in one
   viewport and left the download — the thing the page is actually for — arguing
   with a game picker for the same attention. A text tab with an ink underline
   is still obviously a control, still 30px tall, and stops competing.

   Defined once here because the two pages had a copy each, and a switcher that
   drifts is how one page ends up looking like a different product. */
.tab {
  font-family: var(--mono);
  font-size: 12px;
  font-weight: 600;
  color: var(--ink-dim);
  background: none;
  border: 0;
  border-bottom: 2px solid transparent;
  padding: 6px 10px;
  cursor: pointer;
  transition: color 0.14s ease, border-color 0.14s ease;
}

.tab:hover { color: var(--ink); }
.tab[aria-selected="true"] { color: var(--ink); border-bottom-color: var(--ink); }

.tab:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 3px;
}

/* Product and platform marks are masks filled with currentColor, so the dino
   is paper-white on the solid Mac CTA and ink-dark in the masthead while both
   icons continue to work in dark mode without duplicate image files. */
.btn-with-icon {
  display: inline-flex;
  align-items: center;
  gap: 9px;
}

/* The one link inside a dim caption line, on both the homepage and /play.
   Ink rather than the dim it sits in, bold, and underlined at rest: it is
   asking for something, so it has to look clickable without a pointer, and it
   is the only thing on either page that does.

   Shared here rather than repeated per page because those two captions are the
   same sentence, and one of them drifting is how a product ends up asking for
   support in two different voices. */
/* The caption under a call to action. It was a page-local rule on the homepage
   and on /chrome, which was fine while it said something different on each;
   /play now carries the same sentence as the homepage, so the base belongs
   here. Both of those pages keep their own overrides — a page's inline
   `<style>` comes after this file and wins on source order. */
.meta {
  display: inline-flex;
  align-items: baseline;
  gap: 8px;
  margin: 0;
  font-size: 14px;
  color: var(--ink-dim);
}

/* A pixel heart, on the same grid the games are drawn on — chunky, square,
   crisp-edged — rather than a rounded vector heart borrowed from a like
   button. It is the only ornament on either page, so it has to look like it
   came out of this product. Ink, not dim: it leads the one line that asks. */
.meta-heart {
  width: 12px;
  height: auto;
  flex: none;
  align-self: center;
  fill: var(--ink);
  shape-rendering: crispEdges;
}

.meta-link {
  font-weight: 700;
  color: var(--ink);
  text-decoration: underline;
  text-decoration-thickness: 1.5px;
  text-underline-offset: 3px;
}

.meta-link:hover { text-decoration-thickness: 2.5px; }

.ui-icon {
  display: inline-block;
  width: 1.25em;
  height: 1.25em;
  flex: none;
  background: currentColor;
}

/* One mark everywhere: the same dino the app icon, the favicon, and the Mac
   menu bar use. Masked rather than drawn, so it takes currentColor. */
.dino-icon {
  -webkit-mask: url("icon-180.png") center / contain no-repeat;
  mask: url("icon-180.png") center / contain no-repeat;
}

.extension-icon {
  -webkit-mask: url("extension-puzzle.svg") center / contain no-repeat;
  mask: url("extension-puzzle.svg") center / contain no-repeat;
}

/* ---- the arcade window ---- */

.window {
  /* The anchor for the celebration screen, which is laid over the board it is
     about rather than beside it. */
  position: relative;
  width: 100%;
  background: var(--paper);
  border: 1px solid var(--ink-faint);
  border-radius: 14px;
  box-shadow: 0 18px 44px -22px rgba(0, 0, 0, 0.42);
  padding: 16px 20px 18px;
}

.window-bar {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  padding-bottom: 11px;
  border-bottom: 1px solid var(--ink-faint);
}

.state {
  font-size: 12.5px;
  font-weight: 700;
  letter-spacing: 0.14em;
}

.status {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 10.5px;
  color: var(--ink-dim);
}

.dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--ink);
  animation: pulse 1.2s ease-in-out infinite;
}

@keyframes pulse {
  0%, 100% { opacity: 0.75; }
  50% { opacity: 0.2; }
}

.game-title {
  text-align: center;
  font-size: 17px;
  font-weight: 700;
  letter-spacing: 0.3em;
  text-indent: 0.3em;
  margin: 15px 0 7px;
}

.readout {
  text-align: center;
  font-size: 11.5px;
  color: var(--ink-dim);
  margin-bottom: 12px;
  min-height: 1.4em;
  line-height: 1.4;
}

/* Pongosaurus: each half hugs the board's center line — Earth's score ends
   where the villain's begins — and the long villain label wraps under itself
   without pushing the scores around. */
.readout.split {
  display: flex;
  gap: 18px;
}

.readout.split span:first-child { flex: 1; text-align: right; }
.readout.split span:last-child { flex: 1; text-align: left; }

canvas {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid var(--ink-faint);
  touch-action: none;
}

/* ---- footer ---- */

/* The band belongs to the studio, not to this site, so it carries
   blacktop.social's own values verbatim and stays dark in both themes. */
footer {
  --bt-ground: #08090B;
  --bt-ink: #F2EFE6;
  --bt-dim: #A9A69C;
  --bt-rule: rgba(242, 239, 230, 0.22);

  position: relative;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 16px;
  flex-wrap: wrap;
  padding: clamp(18px, 3vh, 26px) 0;
  /* Sits flush against the bottom of the page rather than floating above it. */
  margin-bottom: calc(-1 * clamp(20px, 3.5vh, 34px));
  font-size: 12.5px;
  color: var(--bt-dim);
}

/* Paints the ground past .page's gutters so the band runs edge to edge while
   its contents stay on the page's own grid. body clips the overhang. */
footer::before {
  content: "";
  position: absolute;
  inset: 0 calc(50% - 50vw);
  background: var(--bt-ground);
  z-index: -1;
}

/* Two stacked lines: the studio it belongs to, then the person who made it.
   Both names stay underlined, since they're the only outbound links here. */
footer .credit { line-height: 1.7; }

footer .credit a {
  color: var(--bt-ink);
  border-bottom-color: var(--bt-rule);
}

footer nav {
  display: flex;
  gap: 18px;
  justify-content: flex-end;
}

/* Equal side columns, so the sun sits dead centre rather than wherever the
   two text blocks happen to leave it. They wrap before they squash. */
footer .credit,
footer nav {
  flex: 1 1 0;
  min-width: max-content;
}

/* On a phone the nav takes a line of its own.

   It never fitted beside the credit at any link count — `flex: 1 1 0` leaves it
   about 90px there, and `min-width: max-content` then pushed it past the page
   edge, where `body`'s clip quietly ate the last link.

   Full-width basis so it wraps below the credit and the sun instead of being
   squeezed beside them, then `wrap` lets the links themselves fold onto a
   second row if they need to. Left-aligned, because a right-aligned ragged
   block under a left-aligned credit reads as a mistake. */
@media (max-width: 620px) {
  footer nav {
    flex: 1 0 100%;
    flex-wrap: wrap;
    justify-content: flex-start;
    min-width: 0;
    row-gap: 10px;
  }
}

footer a {
  color: var(--bt-dim);
  text-decoration: none;
  border-bottom: 1px dashed transparent;
}

footer a:hover {
  color: var(--bt-ink);
  border-bottom-color: var(--bt-rule);
}

/* The sun is the studio's own mark, so it links home to Blacktop Social.
   Declared after footer a so the ring wins over that rule's bottom border. */
footer .sun {
  display: grid;
  place-items: center;
  width: 35px;
  height: 35px;
  flex: none;
  border: 1px solid var(--bt-rule);
  border-radius: 50%;
  transition: color 0.14s ease, border-color 0.14s ease;
}

footer .sun:hover {
  color: var(--bt-ink);
  border-color: var(--bt-ink);
}

footer .sun svg {
  width: 17px;
  height: 17px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
}

/* On a phone the masthead keeps one action, and it is not this one. /play's is
   "Download for Mac", which alongside Support and the wordmark runs past 390px
   and wraps its own label onto two lines. The footer carries support on every
   page, so nothing becomes unreachable.

   Down here rather than beside `.masthead-actions`, because `.btn` sets
   `display: inline-block` at the same specificity and would win on source
   order — a `display: none` that quietly does nothing is worse than no rule. */
@media (max-width: 480px) {
  .support-tab { display: none; }
}

/* ---- the ask ----
   ......................................................................
   Two shapes, because a run can end two ways and they are not the same
   occasion.

   A run that merely ended gets `.dino-says` — a bubble beside the board, the
   dino asking a small question with the game still visible and still
   playable underneath. Pressing space to go again is a legitimate answer.

   A run that was WON gets `.fossil` — a screen, over the board, that stops
   everything for a second to say what just happened. It exists because the
   moment exists: clearing a Minesweeptor board or beating a record you
   already held is the best thing that happens in this product, and it used
   to pass with a line of grey text under the canvas. The tip inside it is
   there because reciprocity needs the payoff to have landed first; the
   celebration is not decoration around an ask, it is the thing being
   celebrated, and the ask is allowed to sit next to it.

   Both are built by tipjar.js and shipped to /play and to the extension's
   offline window from here, so the two surfaces cannot drift. */

.dino-says {
  display: flex;
  align-items: center;
  gap: 14px;
  width: 100%;
  margin-top: 16px;
}

/* `.dino-says` sets display: flex at the same specificity the attribute would
   have to beat, so the hidden state has to be spelled out or the bubble is
   never actually hidden. */
.dino-says[hidden] { display: none; }

.says-mark {
  width: 30px;
  height: 30px;
  color: var(--ink);
}

.bubble {
  position: relative;
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 10px 18px;
  padding: 11px 14px;
  border: 1.5px solid var(--ink);
  border-radius: 4px;
  background: var(--paper);
  animation: says-in 0.18s ease-out;
}

/* Two triangles, the ink one behind the paper one, which is how a speech tail
   keeps a 1.5px outline all the way around a corner it does not have. */
.bubble::before,
.bubble::after {
  content: "";
  position: absolute;
  top: 50%;
  margin-top: -7px;
  width: 0;
  height: 0;
  border: 7px solid transparent;
}

.bubble::before { left: -14px; border-right-color: var(--ink); }
.bubble::after { left: -11.5px; border-right-color: var(--paper); }

@keyframes says-in {
  from { opacity: 0; transform: translateY(4px); }
}

.says { margin: 0; font-size: 12.5px; }

.says-actions {
  display: flex;
  align-items: center;
  gap: 8px;
}

/* Same reason `.dino-says[hidden]` exists: an author display rule outranks the
   user agent's own [hidden]. Both the three-amount row and the single queued
   one are swapped by the attribute. */
.says-actions[hidden] { display: none; }

/* Each amount is the whole transaction — the tile is the link, there is no
   confirm step — which is the same bargain /404bc/support now makes. */
.tip {
  font-size: 13px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  text-decoration: none;
  color: var(--ink);
  border: 1.5px solid var(--ink-faint);
  border-radius: 4px;
  padding: 5px 11px;
  transition: background 0.14s ease, border-color 0.14s ease;
}

.tip:hover { background: var(--ink-soft); border-color: var(--ink); }
.tip:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }

/* The one amber outside the tip jar's own page, and it means the same thing
   in both places: this is the one most people pick. */
.tip-pick {
  border-color: var(--gold);
  background: var(--gold-wash);
  box-shadow: 0 0 10px var(--gold-glow);
}

.tip-pick:hover { border-color: var(--gold); background: var(--gold-wash); }

.says-no {
  font: inherit;
  font-size: 11.5px;
  color: var(--ink-dim);
  background: none;
  border: 0;
  padding: 4px 2px;
  cursor: pointer;
  text-decoration: underline;
  text-decoration-color: var(--ink-faint);
  text-underline-offset: 3px;
}

.says-no:hover { color: var(--ink); }
.says-no:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }

@media (max-width: 560px) {
  .bubble { justify-content: flex-start; }
  .says { flex-basis: 100%; }
}

/* ---- the celebration ---- */

/* Over the board rather than under it: what just happened happened there, and
   a congratulation that appears somewhere else is a notification. Guarded
   against [hidden] for the same reason `.dino-says` is — an author display
   rule beats the user agent's `[hidden] { display: none }`. */
.fossil:not([hidden]) {
  position: absolute;
  inset: 0;
  display: grid;
  place-content: center;
  padding: 16px;
  text-align: center;
  background: color-mix(in srgb, var(--paper) 90%, transparent);
  backdrop-filter: blur(3px);
  border-radius: 14px;
  z-index: 3;
}

.fossil-inner {
  display: grid;
  justify-items: center;
  gap: 12px;
  animation: fossil-in 0.26s cubic-bezier(0.16, 1, 0.3, 1);
}

@keyframes fossil-in {
  from { opacity: 0; transform: scale(0.94); }
}

/* The filter sits on the wrapper, not on the mark. `.ui-icon` is a coloured
   box with the dino punched out of it by a mask, and CSS applies filters
   before masks — a drop-shadow on the mark itself would be the shadow of a
   square. On the parent it follows the silhouette. */
.fossil-dino {
  filter: drop-shadow(0 0 12px var(--gold-glow-hot));
  animation: fossil-hop 2.6s ease-in-out infinite;
}

.fossil-dino .ui-icon {
  width: 46px;
  height: 46px;
  color: var(--gold);
}

@keyframes fossil-hop {
  0%, 88%, 100% { transform: translateY(0); }
  92% { transform: translateY(-5px); }
  96% { transform: translateY(0); }
}

.fossil-title {
  margin: 0;
  font-size: 16px;
  font-weight: 700;
  letter-spacing: 0.26em;
  text-indent: 0.26em;
  color: var(--ink);
}

.fossil-line {
  margin: 0;
  font-size: 12px;
  color: var(--ink-dim);
  font-variant-numeric: tabular-nums;
}

/* Hidden when the celebration has nothing to ask for — a win inside the three
   quiet days is still a win, and gets its screen without the box. */
.tip-box[hidden] { display: none; }

/* The donation box. It glows because this is the one screen in 404 B.C. that
   is allowed to want something, and because a box that appears for four
   seconds has to be found in one glance or it may as well not have appeared.
   Amber, on its own, breathing slowly — no second highlight anywhere on this
   screen competes with it. */
.tip-box {
  display: grid;
  justify-items: center;
  gap: 10px;
  margin-top: 4px;
  padding: 13px 16px 15px;
  border: 1.5px solid var(--gold);
  border-radius: 4px;
  background: var(--gold-wash);
  animation:
    ask-in 0.24s cubic-bezier(0.16, 1, 0.3, 1),
    gold-breathe 2.8s ease-in-out infinite;
}

/* The box is not part of the celebration's own entrance — it arrives a second
   later, once the win has been read — so it gets its own, smaller one. */
@keyframes ask-in {
  from { opacity: 0; transform: translateY(6px); }
}

@keyframes gold-breathe {
  0%, 100% { box-shadow: 0 0 0 3px var(--gold-wash), 0 0 16px var(--gold-glow); }
  50% { box-shadow: 0 0 0 5px var(--gold-wash), 0 0 34px var(--gold-glow-hot); }
}

.tip-line {
  margin: 0;
  font-size: 12px;
  color: var(--ink);
  max-width: 30ch;
}

/* The decline sits away from the thing it declines. Without the box above it
   — a win inside the quiet days gets no ask — it would otherwise land against
   the stat line and read as part of it. */
.fossil-inner .says-no { margin-top: 4px; }

.tip-row {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  flex-wrap: wrap;
}

.tip-row[hidden] { display: none; }

/* Only ever present when the wifi is down, which on the Mac app and the
   extension is most of the time this screen is up. It says what tapping an
   amount will actually do, because during an outage it cannot do the usual
   thing. */
.tip-note {
  margin: -2px 0 0;
  font-size: 11px;
  color: var(--ink-dim);
}

/* Inside the box the amber ring has nothing to distinguish itself from, so
   the pick earns its emphasis by being the filled one. */
.tip-box .tip { border-color: var(--gold); background: var(--paper); }
.tip-box .tip-pick { background: var(--gold); border-color: var(--gold); color: #1C1B19; box-shadow: none; }
.tip-box .tip-pick:hover { background: var(--gold); }

@media (max-width: 430px) {
  .fossil-title { font-size: 14px; letter-spacing: 0.18em; text-indent: 0.18em; }
  .tip-box { padding: 11px 12px 13px; }
  .fossil-dino .ui-icon { width: 38px; height: 38px; }
  .tip { padding: 5px 9px; }
}


@media (prefers-reduced-motion: reduce) {
  .dot { animation: none; opacity: 0.7; }
  .btn, .tab, .tip { transition: none; }

  /* The glow stays — it is the thing that says "this one" — but it stops
     moving, and the screen arrives instead of growing. */
  .bubble, .fossil-inner, .fossil-dino { animation: none; }
  .tip-box, .tip-box:not([hidden]) { animation: none; }
}
