/* Whiskerloop's website.
 *
 * The room the game is set in is lit by a lamp: warm browns, amber, nothing
 * cool or clinical. The site is that room seen from further away - the same
 * palette as client/whiskerloop/style.css, deliberately, because a landing
 * page in different colours from the product is a page that sold you something
 * else.
 *
 * Motion here is never decoration. Every animated thing on this page is the
 * game actually playing itself, because the one hard thing about marketing a
 * new mechanic is that nobody knows what it is, and a sentence explaining it
 * will always lose to four cats turning to face each other. All of it stops
 * for prefers-reduced-motion.
 */

:root {
  --bg: #17120f;
  --bg-deep: #100c0a;
  --surface: #221a15;
  --surface-2: #2c221b;
  --line: #3d2f26;
  --text: #f3e9e0;
  --muted: #a99383;
  --accent: #f0a04b;
  --accent-2: #e8726a;
  --accent-ink: #2a1708;
  --good: #7fc98a;

  --shell: min(1180px, 100% - 48px);
  --radius: 18px;
  --radius-lg: 28px;

  /* One scale, fluid, so nothing needs a breakpoint to stay readable. */
  --step-6: clamp(2.6rem, 1.4rem + 5.4vw, 5.2rem);
  --step-5: clamp(2rem, 1.3rem + 3.2vw, 3.4rem);
  --step-4: clamp(1.5rem, 1.2rem + 1.5vw, 2.1rem);
  --step-3: clamp(1.2rem, 1.1rem + 0.6vw, 1.45rem);
  --step-2: clamp(1.02rem, 0.98rem + 0.3vw, 1.15rem);
  --step-1: 0.94rem;
  --step-0: 0.84rem;
}

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

/* The `hidden` attribute means nothing against a rule that sets `display`, and
   several things here are flex or grid. Without this the sign-in page showed an
   "or" divider and an empty 44px gap where a Google button would have gone on a
   deployment that has no Google client configured. */
[hidden] { display: none !important; }

html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
}

/* The lamp: a warm pool of light at the top of the page, so a dark layout does
   not read as a black rectangle.

   Painted straight into the body background rather than a fixed, composited
   pseudo-element. The fixed version cost a full-viewport layer that had to be
   recomposited on every scroll frame, and stacked under a blurred sticky
   header it was heavy enough to drop frames - it defeated a screenshot of this
   very page, which is a good sign of what it does to a mid-range phone. The
   glow belongs to the top of the document anyway, so scrolling away from it is
   the correct behaviour rather than a compromise. */
body {
  margin: 0;
  background:
    radial-gradient(1100px 620px at 22% -80px, rgba(240, 160, 75, .20), transparent 70%),
    radial-gradient(760px 520px at 84% -140px, rgba(232, 114, 106, .13), transparent 70%),
    var(--bg);
  background-repeat: no-repeat;
  color: var(--text);
  font: 400 var(--step-2)/1.6 ui-rounded, "SF Pro Rounded", "Segoe UI Variable",
        system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

main, header, footer { position: relative; z-index: 1; }

.shell { width: var(--shell); margin-inline: auto; }

h1, h2, h3 { line-height: 1.1; letter-spacing: -0.02em; margin: 0; font-weight: 800; }
p { margin: 0; }
a { color: inherit; }

/* --- navigation --------------------------------------------------------- */

/* Opaque rather than blurred. A backdrop-filter over a scrolling page re-blurs
   a changing backdrop every frame, which is the most expensive thing a sticky
   header can do, and at this opacity nobody can tell the difference. */
.nav {
  position: sticky; top: 0; z-index: 40;
  background: color-mix(in srgb, var(--bg) 94%, transparent);
  border-bottom: 1px solid transparent;
  transition: border-color .3s;
}
.nav.stuck { border-bottom-color: var(--line); }
.nav .shell {
  display: flex; align-items: center; gap: 10px;
  height: 66px;
}
.brand {
  display: flex; align-items: center; gap: 10px;
  font-weight: 800; font-size: 1.12rem; letter-spacing: -0.02em;
  text-decoration: none; margin-right: auto;
}
.brand svg { width: 32px; height: 32px; flex: none; }
.nav-links { display: flex; gap: 4px; align-items: center; }
.nav-links a {
  padding: 8px 12px; border-radius: 10px;
  color: var(--muted); text-decoration: none;
  font-size: var(--step-1); font-weight: 600;
  transition: color .2s, background .2s;
}
.nav-links a:hover { color: var(--text); background: var(--surface); }
@media (max-width: 760px) { .nav-links .hide-sm { display: none; } }

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

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  padding: 13px 22px; border-radius: 999px; border: 1px solid transparent;
  font: inherit; font-weight: 700; font-size: var(--step-1);
  text-decoration: none; cursor: pointer; white-space: nowrap;
  transition: transform .18s cubic-bezier(.34,1.56,.64,1), box-shadow .18s, background .18s;
}
.btn:active { transform: scale(.97); }
.btn-primary {
  background: var(--accent); color: var(--accent-ink);
  box-shadow: 0 8px 26px -10px rgba(240, 160, 75, .9);
}
.btn-primary:hover { transform: translateY(-2px); box-shadow: 0 14px 34px -12px rgba(240,160,75,.95); }
.btn-ghost { background: transparent; border-color: var(--line); color: var(--text); }
.btn-ghost:hover { background: var(--surface); border-color: var(--muted); }
.btn-lg { padding: 16px 30px; font-size: var(--step-2); }

/* --- hero --------------------------------------------------------------- */

.hero { padding: clamp(36px, 7vw, 88px) 0 clamp(40px, 6vw, 80px); }
.hero .shell {
  display: grid; gap: clamp(32px, 5vw, 60px);
  grid-template-columns: 1fr;
  align-items: center;
}
@media (min-width: 900px) {
  .hero .shell { grid-template-columns: 1.02fr 0.98fr; }
}

/* On a phone the board goes above the buttons.
   Stacked in source order it landed below two calls to action and three
   reassurances - off the bottom of the screen - so the one thing that explains
   what this game even is was the one thing a phone visitor never saw. The
   board is the pitch; the buttons only matter once it has been made. */
/* Stacked on a phone: what it is called and what you do, then the board, then
   the buttons.

   In source order the board sat below both calls to action and three
   reassurances, off the bottom of the screen - so the one thing that explains
   this game without words was the one thing a phone visitor never saw. Putting
   it first instead pushed the name and the pitch off screen, which is the
   opposite mistake. The buttons are what can wait: nobody presses them before
   the pitch has been made. */
@media (max-width: 899px) {
  .hero .shell { display: flex; flex-direction: column; gap: 26px; }
  .hero-stage { order: 1; }
  .hero-act { order: 2; }
  .hero .headline { margin-bottom: 14px; }
  .hero .lede { margin-bottom: 0; }
}

@media (min-width: 900px) {
  /* Back to two columns: the text and its buttons on the left, board on the
     right. The wrapper only exists for the stacked case. */
  .hero .shell { grid-template-areas: "words stage" "act stage"; align-items: center; }
  .hero .shell > div:first-child { grid-area: words; }
  .hero-act { grid-area: act; margin-top: 30px; }
  .hero-stage { grid-area: stage; }
}

.eyebrow {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 6px 14px 6px 8px; border-radius: 999px;
  background: var(--surface); border: 1px solid var(--line);
  color: var(--muted); font-size: var(--step-0); font-weight: 700;
  letter-spacing: .02em; margin-bottom: 20px;
}
.eyebrow b { color: var(--accent); }
.eyebrow .dot {
  width: 7px; height: 7px; border-radius: 50%; background: var(--good);
  margin-left: 6px;
}

h1.headline { font-size: var(--step-6); margin-bottom: 18px; }
h1.headline .glow {
  background: linear-gradient(105deg, var(--accent) 10%, #ffd9a0 55%, var(--accent-2) 95%);
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
.lede { font-size: var(--step-3); color: var(--muted); max-width: 46ch; margin-bottom: 30px; }
/* Said to somebody the page recognises, above the button they came for. It
   only ever appears when there is something true to put in it. */
.welcome {
  margin: 0 0 12px; font-size: 14.5px; font-weight: 600;
  color: var(--accent, #f0a04b);
}

.cta-row { display: flex; flex-wrap: wrap; gap: 12px; align-items: center; }
.reassure {
  margin-top: 20px; color: var(--muted); font-size: var(--step-1);
  display: flex; flex-wrap: wrap; gap: 6px 16px;
}
.reassure span { display: inline-flex; align-items: center; gap: 7px; }
.reassure svg { width: 15px; height: 15px; color: var(--good); flex: none; }

/* --- the board that plays itself ---------------------------------------- */

/* The hero's whole job. A still screenshot of this game looks like cats on a
   grid and explains nothing; watching one turn and a circle close explains it
   in four seconds without a word of copy. */
.stage {
  position: relative;
  padding: clamp(14px, 2.4vw, 22px);
  border-radius: var(--radius-lg);
  background: linear-gradient(160deg, var(--surface-2), var(--surface));
  border: 1px solid var(--line);
  box-shadow: 0 40px 90px -50px #000, 0 0 0 1px rgba(255,255,255,.02) inset;
}
.stage::after {
  content: "";
  position: absolute; inset: 0; border-radius: inherit;
  background: radial-gradient(70% 50% at 50% 0%, rgba(240,160,75,.10), transparent 70%);
  pointer-events: none;
}
.board {
  position: relative;
  display: grid; gap: clamp(3px, .6vw, 6px);
  aspect-ratio: 1;
  grid-auto-rows: 1fr;
}
.cell {
  position: relative;
  border-radius: clamp(7px, 1.2vw, 11px);
  background: #2a201a;
  display: grid; place-items: center;
}
.cell.alt { background: #2f2420; }
.cell.has-prop { background: #3a2c22; }
.cell svg { width: 88%; height: 88%; display: block; }
.cell .cat { transition: transform .42s cubic-bezier(.34,1.3,.64,1); }
.gazes { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }

.stage-caption {
  margin-top: 14px; text-align: center;
  color: var(--muted); font-size: var(--step-1); font-weight: 600;
  min-height: 1.6em;
}
.stage-caption b { color: var(--text); }

/* --- generic section ---------------------------------------------------- */

section { padding: clamp(48px, 8vw, 104px) 0; }
.section-head { max-width: 62ch; margin-bottom: clamp(28px, 4vw, 48px); }
.section-head h2 { font-size: var(--step-5); margin-bottom: 14px; }
.section-head p { color: var(--muted); font-size: var(--step-3); }
.kicker {
  display: block; color: var(--accent); font-weight: 800;
  font-size: var(--step-0); letter-spacing: .12em; text-transform: uppercase;
  margin-bottom: 12px;
}

/* --- the three rules ---------------------------------------------------- */

.rules { display: grid; gap: 18px; grid-template-columns: 1fr; }
@media (min-width: 780px) { .rules { grid-template-columns: repeat(3, 1fr); } }

.rule {
  padding: 22px; border-radius: var(--radius);
  background: var(--surface); border: 1px solid var(--line);
  display: flex; flex-direction: column; gap: 14px;
}
.rule .mini {
  /* position: relative because the gaze overlay is absolutely positioned
     against it; without it the lines anchor to the page and are drawn
     somewhere else entirely. grid-auto-rows keeps the rows square rather than
     letting them size to the cats inside them. */
  position: relative;
  aspect-ratio: 1; border-radius: 12px; overflow: hidden;
  background: #211914; display: grid; gap: 4px; padding: 8px;
  grid-auto-rows: 1fr;
}
.rule h3 { font-size: var(--step-3); }
.rule p { color: var(--muted); font-size: var(--step-1); }
.rule .n {
  width: 26px; height: 26px; border-radius: 8px; flex: none;
  display: grid; place-items: center;
  background: var(--accent); color: var(--accent-ink);
  font-weight: 800; font-size: 0.85rem;
}
.rule-head { display: flex; align-items: center; gap: 10px; }

/* --- the promise -------------------------------------------------------- */

.promise {
  border-radius: var(--radius-lg);
  padding: clamp(30px, 5vw, 64px);
  background:
    radial-gradient(90% 120% at 10% 0%, rgba(240,160,75,.14), transparent 60%),
    var(--surface);
  border: 1px solid var(--line);
  text-align: center;
}
.promise h2 { font-size: var(--step-5); margin-bottom: 16px; }
.promise p { color: var(--muted); font-size: var(--step-3); max-width: 60ch; margin-inline: auto; }

/* --- feature grid ------------------------------------------------------- */

.features { display: grid; gap: 16px; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); }
/* Five things in a room: one row on a wide screen rather than four and an
   orphan. */
.features.five { grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); }
.feature {
  padding: 22px; border-radius: var(--radius);
  background: var(--surface); border: 1px solid var(--line);
  transition: transform .2s, border-color .2s;
}
.feature:hover { transform: translateY(-3px); border-color: var(--muted); }
.feature .icon { font-size: 1.6rem; line-height: 1; margin-bottom: 12px; display: block; }
.feature h3 { font-size: var(--step-2); margin-bottom: 7px; }
.feature p { color: var(--muted); font-size: var(--step-1); }

/* --- the cats ----------------------------------------------------------- */

.coats { display: grid; gap: 16px; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); }
.coat-set {
  padding: 18px; border-radius: var(--radius);
  background: var(--surface); border: 1px solid var(--line);
}
.coat-set h3 { font-size: var(--step-2); margin-bottom: 4px; }
.coat-set p { color: var(--muted); font-size: var(--step-0); margin-bottom: 14px; }
.coat-strip { display: flex; gap: 2px; }
.coat-strip span { flex: 1; aspect-ratio: 1; display: grid; place-items: center; }
.coat-strip svg { width: 100%; height: 100%; }

/* --- languages ---------------------------------------------------------- */

.langs { display: flex; flex-wrap: wrap; gap: 10px; }
.lang {
  padding: 10px 18px; border-radius: 999px;
  background: var(--surface); border: 1px solid var(--line);
  font-weight: 700; font-size: var(--step-1);
}
.lang small { color: var(--muted); font-weight: 600; margin-left: 6px; }

/* --- get it ------------------------------------------------------------- */

.platforms { display: grid; gap: 14px; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); }
.platform {
  padding: 22px; border-radius: var(--radius);
  background: var(--surface); border: 1px solid var(--line);
  display: flex; flex-direction: column; gap: 10px;
}
.platform h3 { font-size: var(--step-2); display: flex; align-items: center; gap: 9px; }
/* Wrapped in <i> so a translation can replace the word without touching the
   icon beside it. Not emphasis - the same trick as the game's tool buttons. */
.platform h3 i, .eyebrow i, .reassure i { font-style: normal; }
.platform p { color: var(--muted); font-size: var(--step-1); flex: 1; }
.platform .btn { align-self: flex-start; }
.pill-soon {
  font-size: var(--step-0); font-weight: 700; color: var(--muted);
  border: 1px solid var(--line); border-radius: 999px; padding: 4px 11px;
  align-self: flex-start;
}

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

footer {
  border-top: 1px solid var(--line);
  padding: 44px 0 56px; margin-top: 30px;
  color: var(--muted); font-size: var(--step-1);
}
.foot { display: flex; flex-wrap: wrap; gap: 22px; justify-content: space-between; }
.foot-links { display: flex; flex-wrap: wrap; gap: 8px 20px; }
.foot-links a { text-decoration: none; }
.foot-version { flex-basis: 100%; font-size: 12px; color: var(--muted); font-variant-numeric: tabular-nums; }
.foot-links a:hover { color: var(--text); text-decoration: underline; }

/* --- entrances ---------------------------------------------------------- */

/* Opacity and a small lift only. Anything that moves an element far enough to
   notice fights the reader on a long page. */
.rise { opacity: 0; transform: translateY(14px); transition: opacity .6s ease, transform .6s cubic-bezier(.22,1,.36,1); }
.rise.seen { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) { .rise { opacity: 1; transform: none; } }

/* --- the light theme ---------------------------------------------------- */

@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) {
    --bg: #fbf5ee; --bg-deep: #f3e7da;
    --surface: #fffaf4; --surface-2: #f6ece0;
    --line: #e4d3c0; --text: #2a1f18; --muted: #7b6553;
    --accent: #c9761f; --accent-ink: #fff6ea;
  }
  :root:not([data-theme="dark"]) .cell { background: #f6ece0; }
  :root:not([data-theme="dark"]) .cell.alt { background: #efe2d2; }
  :root:not([data-theme="dark"]) .cell.has-prop { background: #e6d4bd; }
  :root:not([data-theme="dark"]) .rule .mini { background: #f6ece0; }
  :root:not([data-theme="dark"]) .stage { box-shadow: 0 40px 90px -60px #b08050; }
}
