/*
 * Chalk, on the web.
 *
 * The Organic palette from the app, so the site and the product look like the
 * same thing: cream ground, terracotta and sage, over rounded corners, and
 * Caprasimo for anything that carries the personality.
 *
 * One stylesheet for four static pages. No build step, no framework, nothing
 * to keep up to date: these pages have to be reachable for as long as the app
 * is on sale, and the cheapest way to promise that is for them to be four
 * files anybody can host anywhere.
 */

:root {
  /* The reading column, shared by the text and by the screenshot rail so the
     two line up. */
  --col: 720px;

  --bg: #f5ead8;
  --surface: #fdfaf3;
  --raised: #e4d3b4;
  --line: rgba(32, 30, 29, 0.18);
  --ink: #201e1d;
  --ink-soft: #645c50;
  --ink-faint: #82796a;
  --terracotta: #b2622d;
  --terracotta-deep: #8c491a;
  --sage: #56633f;
  --radius: 28px;
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #15110d;
    --surface: #241d16;
    --raised: #372d22;
    --line: rgba(249, 244, 237, 0.16);
    --ink: #f7f1e7;
    --ink-soft: #c2b6a3;
    --ink-faint: #8e8373;
    --terracotta: #f6a06b;
    --terracotta-deep: #ffc6a5;
    --sage: #aebf92;
  }
}

* {
  box-sizing: border-box;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family:
    Figtree,
    -apple-system,
    BlinkMacSystemFont,
    'Segoe UI',
    system-ui,
    sans-serif;
  font-size: 17px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

.wrap {
  max-width: var(--col);
  margin: 0 auto;
  padding: 32px 20px 64px;
}

/* ── The header, on every page */

header.top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  margin-bottom: 40px;
}

.wordmark {
  font-family: Caprasimo, Georgia, serif;
  font-size: 26px;
  line-height: 1;
  color: var(--ink);
  text-decoration: none;
}

nav.top a {
  color: var(--ink-soft);
  text-decoration: none;
  font-size: 14px;
  font-weight: 600;
  margin-left: 18px;
}

nav.top a:hover,
nav.top a[aria-current='page'] {
  color: var(--terracotta);
}

/* ── Type */

h1 {
  font-family: Caprasimo, Georgia, serif;
  font-weight: 400;
  font-size: clamp(34px, 7vw, 52px);
  line-height: 1.06;
  margin: 0 0 8px;
}

h2 {
  font-family: Caprasimo, Georgia, serif;
  font-weight: 400;
  font-size: 24px;
  line-height: 1.15;
  margin: 40px 0 8px;
}

h3 {
  font-size: 17px;
  font-weight: 800;
  margin: 28px 0 4px;
}

.lede {
  font-size: 19px;
  color: var(--ink-soft);
  margin: 0 0 8px;
}

.rule {
  width: 64px;
  height: 4px;
  border-radius: 2px;
  background: var(--terracotta);
  margin: 22px auto 30px;
}

.updated {
  font-size: 14px;
  color: var(--ink-faint);
  margin: 0;
}

a {
  color: var(--terracotta-deep);
  text-decoration-thickness: 1px;
  text-underline-offset: 2px;
}

/* ── Blocks */

.card {
  background: var(--surface);
  border-radius: var(--radius);
  padding: 22px 24px;
  margin: 24px 0;
}

.note {
  background: var(--surface);
  border-radius: 999px;
  padding: 14px 26px;
  font-size: 15px;
  color: var(--ink-soft);
  text-align: center;
  display: block;
  width: fit-content;
  margin: 64px auto 0;
}

ul {
  padding-left: 22px;
}

li {
  margin: 6px 0;
}

.games {
  list-style: none;
  padding: 0;
  margin: 24px 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 10px;
}

.games li {
  background: var(--surface);
  border-radius: 18px;
  padding: 14px 18px;
  margin: 0;
}

.games strong {
  display: block;
  font-family: Caprasimo, Georgia, serif;
  font-weight: 400;
  font-size: 19px;
}

.games span {
  font-size: 14px;
  color: var(--ink-soft);
}

.pill {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  background: var(--terracotta);
  color: var(--bg);
  border-radius: 999px;
  padding: 14px 26px;
  font-weight: 800;
  text-decoration: none;
}

.pill:hover {
  opacity: 0.9;
}

footer.bottom {
  margin-top: 72px;
  justify-content: center;
  padding-top: 24px;
  border-top: 1px solid var(--line);
  font-size: 14px;
  color: var(--ink-faint);
  display: flex;
  gap: 18px;
  flex-wrap: wrap;
}

footer.bottom a {
  color: var(--ink-soft);
  text-decoration: none;
}

footer.bottom a:hover {
  color: var(--terracotta);
}

/* ── Motion
 *
 * One idea, applied to everything: a block starts slightly low and faded, and
 * arrives when it is scrolled into view. The hero arrives on load.
 *
 * `.reveal` sets the resting state ONLY when the script is there to undo it,
 * which is what the `js` class on the root element means. Without it every
 * section is simply visible, so the page is never blank because a script
 * failed to run.
 */

.js .reveal {
  opacity: 0;
  transform: translateY(16px);
}

.js .reveal.in {
  opacity: 1;
  transform: none;
  transition:
    opacity 620ms cubic-bezier(0.2, 0.7, 0.2, 1),
    transform 620ms cubic-bezier(0.2, 0.7, 0.2, 1);
}

/* The games arrive one after another rather than all at once, which is the
   same stagger the app uses when a board mounts. */
.js .reveal.in .games li {
  animation: rise 520ms cubic-bezier(0.2, 0.7, 0.2, 1) both;
  animation-delay: calc(var(--i) * 45ms);
}

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

/* The wordmark carries the app's own icon. */
.wordmark {
  display: inline-flex;
  align-items: center;
  gap: 9px;
}

.wordmark img {
  width: 26px;
  height: 26px;
  border-radius: 24%;
}

/* Somebody who has asked for less movement gets none of it, and gets every
   section at rest and visible. */
@media (prefers-reduced-motion: reduce) {
  .js .reveal,
  .js .reveal.in {
    opacity: 1;
    transform: none;
    transition: none;
  }

  .js .reveal.in .games li {
    animation: none;
  }
}

/* The privacy, terms and contact pages are documents rather than a pitch, so
   they keep the left edge a reader's eye returns to on every line. Only the
   landing page is centred, and it is centred because it is mostly headings. */
.doc h1,
.doc p,
.doc h2 {
  text-align: left;
}

/* ── The hero
 *
 * Text on the left, a drifting wall of screens on the right, in the shape a
 * dozen app landing pages have settled on because it works: the words are the
 * thing you read, and the product is the thing you see behind them.
 *
 * The whole effect is CSS. An earlier version scrolled a rail with
 * requestAnimationFrame, which meant owning pause, resume, wrap-around and the
 * fact that `scrollLeft += 0.35` rounds to nothing every frame. Two keyframes
 * and a duplicated column do the same job and cannot drift out of sync with
 * themselves.
 */

.hero {
  position: relative;
  isolation: isolate;
  padding: 24px 0 8px;
  min-height: 72vh;
  display: grid;
  align-items: center;
}

.pitch {
  position: relative;
  z-index: 1;
  max-width: 30em;
}

.hero-mark {
  width: 104px;
  height: 104px;
  border-radius: 22%;
  display: block;
  margin: 0 0 26px;
}

@media (min-width: 940px) {
  .hero-mark {
    width: 124px;
    height: 124px;
  }
}

.eyebrow {
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--terracotta);
  margin: 0 0 14px;
}

.hero h1 {
  font-size: clamp(52px, 11vw, 92px);
  line-height: 0.98;
  margin: 0 0 16px;
}

.hero .lede {
  font-size: 19px;
  margin: 0 0 14px;
  max-width: 22em;
}

.hero-body {
  max-width: 26em;
  color: var(--ink-faint);
  font-size: 15px;
  margin: 0 0 28px;
}

.cta {
  display: flex;
  align-items: center;
  gap: 18px;
  flex-wrap: wrap;
}

/* Store buttons, in the shape the real badges will take, so swapping them in
   at launch changes the artwork and not the layout. */
.store {
  display: inline-grid;
  grid-template-columns: auto auto;
  grid-template-rows: auto auto;
  align-items: center;
  gap: 0 10px;
  padding: 11px 18px;
  border-radius: 16px;
  border: 1px solid var(--line);
  background: var(--surface);
  cursor: default;
}

.store-top {
  grid-column: 1;
  font-size: 11px;
  color: var(--ink-faint);
  line-height: 1.1;
}

.store-name {
  grid-column: 1;
  font-family: Caprasimo, Georgia, serif;
  font-size: 19px;
  line-height: 1.1;
  color: var(--ink);
}

.store-soon {
  grid-column: 2;
  grid-row: 1 / span 2;
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--terracotta);
  border: 1px solid var(--terracotta);
  border-radius: 999px;
  padding: 3px 9px;
}

.cta-note {
  font-size: 13px;
  line-height: 1.4;
  color: var(--ink-faint);
  margin: 16px 0 0;
}

/* ── The wall
 *
 * Three columns of screens, tilted as one block and each drifting at its own
 * speed. The middle column runs the other way, which is what stops the three
 * reading as a single sheet sliding past.
 *
 * Every column holds its own tiles twice. The animation travels exactly -50%,
 * so the moment it ends the second copy is sitting where the first began and
 * the jump back is invisible.
 */

.collage {
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
  /* Faded at every edge, so the wall dissolves into the page instead of being
     cut off by a rectangle. */
  mask-image:
    linear-gradient(to bottom, transparent, #000 12%, #000 78%, transparent),
    linear-gradient(to right, transparent, #000 22%);
  mask-composite: intersect;
  -webkit-mask-composite: source-in;
  opacity: 0.35;
}

.tilt {
  /*
   * The tile size is declared rather than inferred.
   *
   * The travel has to be exactly one set of tiles plus the gap that follows
   * it, and a percentage of the track cannot say that: half of `2 sets + 3
   * gaps` is half a gap short, a third of `3 sets + 5 gaps` is worse. Fixed
   * numbers make the loop arithmetic exact and readable.
   *
   * 470 is 216 at the screenshots' own 480:1043, rounded. `object-fit` absorbs
   * the half pixel.
   */
  --tile-w: 190px;
  --tile-h: 413px;
  --tile-gap: 16px;
  /* Overridden per column, since they hold different numbers of screens. */
  --set: 4;
  position: absolute;
  top: 50%;
  left: 50%;
  display: flex;
  align-items: center;
  gap: var(--tile-gap);
  transform: translate(-50%, -50%) rotate(-10deg) scale(1.25);
}

.col {
  display: flex;
  flex-direction: column;
  gap: var(--tile-gap);
  animation: drift 58s linear infinite;

  /* Every column holds the same number of tiles, so they are the same height
     and none of them can run out from under the one beside it. The durations
     differ on purpose: three columns moving in lockstep read as one sheet. */
}

.col img {
  width: var(--tile-w);
  height: var(--tile-h);
  object-fit: cover;
  border-radius: 20px;
  border: 1px solid var(--line);
  box-shadow: 0 18px 40px rgba(0, 0, 0, 0.35);
}

.col.b {
  animation-duration: 44s;
  animation-direction: reverse;
}

.col.c {
  animation-duration: 50s;
}

@keyframes drift {
  from {
    transform: translateY(0);
  }
  to {
    /* One set of tiles and the gap after it, to the pixel. */
    transform: translateY(calc(-1 * var(--set) * (var(--tile-h) + var(--tile-gap))));
  }
}

/* Enough room for the wall to sit beside the words rather than behind them. */
@media (min-width: 940px) {
  .hero {
    min-height: 78vh;
  }

  .collage {
    /* Out to the right edge of the window, and starting at the middle of the
       column, so the words always have clear ground under them. */
    left: 46%;
    right: calc(50% - 50vw);
    opacity: 1;
    mask-image:
      linear-gradient(to bottom, transparent, #000 10%, #000 84%, transparent),
      linear-gradient(to right, transparent, #000 18%);
    mask-composite: intersect;
    -webkit-mask-composite: source-in;
  }

  .tilt {
    --tile-w: 216px;
    --tile-h: 470px;
  }
}

/* Somebody who asked for less movement gets a still wall. */
@media (prefers-reduced-motion: reduce) {
  .col {
    animation: none;
  }
}

/* ── The rest of the page, which is a document rather than a pitch */

.block {
  margin-top: 84px;
}

.block h2 {
  margin-top: 0;
}

.block p {
  max-width: 34em;
}

.rule {
  margin: 22px 0 30px;
}

.note {
  background: var(--surface);
  border-radius: 999px;
  padding: 14px 26px;
  font-size: 15px;
  color: var(--ink-soft);
  display: inline-block;
  margin-top: 56px;
}

.wordmark img,
.footmark img {
  flex: none;
  border-radius: 24%;
}

.footmark {
  display: inline-flex;
  align-items: center;
  gap: 7px;
}

@media (hover: hover) {
  .games li {
    transition:
      transform 220ms cubic-bezier(0.2, 0.7, 0.2, 1),
      background-color 220ms ease;
  }

  .games li:hover {
    transform: translateY(-2px);
    background-color: var(--raised);
  }
}
