@font-face {
  font-family: "Baloo 2";
  src: url("fonts/baloo2-500Medium.woff2") format("woff2");
  font-weight: 500;
  font-display: swap;
}
@font-face {
  font-family: "Baloo 2";
  src: url("fonts/baloo2-600SemiBold.woff2") format("woff2");
  font-weight: 600;
  font-display: swap;
}
@font-face {
  font-family: "Baloo 2";
  src: url("fonts/baloo2-800ExtraBold.woff2") format("woff2");
  font-weight: 800;
  font-display: swap;
}

/* The app's own colours, from src/theme.ts, and the night the icon's plum gives. */
:root {
  --cream: #fff5ea;
  --coral: #f4574a;
  --coral-dark: #d9402f;
  --coral-soft: #fcd3c4;
  --brown: #5c1f14;
  --brown-soft: #9a6a5e;
  --plum: #4b033c;
  --night: #2c0730;
  --dusk-rose: #f6cfd6;
  --gold: #ffe3a8;
  /* Slow out, with a little overshoot: how things in the app arrive. */
  --pop: cubic-bezier(0.2, 1.4, 0.4, 1);
  /* How wide the scene is on an upright screen: the screen's width on a phone,
     and on anything bigger about half the screen's height, which keeps a
     phone's proportions. Everything in the scene is sized from it. */
  --stage: min(100vw, max(440px, 52svh));
}

* {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--night);
  color: var(--cream);
  font-family: "Baloo 2", ui-rounded, "Segoe UI", system-ui, sans-serif;
  font-weight: 600;
  font-size: 1.125rem;
  line-height: 1.45;
  overflow-x: clip;
}

img {
  display: block;
}

h1,
h2 {
  margin: 0;
  font-weight: 800;
  line-height: 1.02;
  letter-spacing: -0.01em;
  text-wrap: balance;
}

header {
  position: absolute;
  inset: 0 0 auto;
  z-index: 9;
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: var(--stage);
  margin: 0 auto;
  padding: calc(var(--stage) * 0.046) calc(var(--stage) * 0.051);
}

.logo {
  height: calc(var(--stage) * 0.113);
  width: auto;
}

.soon {
  padding: calc(var(--stage) * 0.015) calc(var(--stage) * 0.038);
  border-radius: 999px;
  background: #fff;
  box-shadow: 0 3px 0 rgba(217, 64, 47, 0.25);
  color: var(--coral-dark);
  font-weight: 800;
  font-size: calc(var(--stage) * 0.0375);
  text-decoration: none;
}

/* One moment of the evening. Its scene is laid out on a stage with a phone's
   proportions, so each layer keeps its place whatever the screen. */
.beat {
  position: relative;
  overflow: clip;
}

.stage {
  position: relative;
  width: var(--stage);
  /* A screen tall, but neither so tall nor so short for its width that the
     layers, which are sized by its width and placed by its height, come apart
     or run into each other. */
  height: min(max(100svh, 740px, calc(var(--stage) * 2.05)), calc(var(--stage) * 2.3));
  margin: 0 auto;
  /* Lengths inside are hundredths of the stage's width (cqw), so the scene is
     the same picture at any size. */
  container-type: inline-size;
}

.stage > img,
.stage > svg,
.stage > span,
.stage picture img {
  position: absolute;
}

/* A terrace and whoever sits on it. On a tall screen they are placed on the
   stage like everything else; on a wide one they are placed together. */
.set {
  display: contents;
}

.set > img,
.set > span {
  position: absolute;
}

.words {
  position: absolute;
  inset: 22.5cqw 5.6cqw auto;
  z-index: 4;
  text-align: center;
}

.words h1 {
  font-size: 12.4cqw;
}

.words h2 {
  font-size: 11cqw;
}

.words p {
  margin: 2.6cqw auto 0;
  max-width: 24ch;
  color: var(--dusk-rose);
  font-size: 5cqw;
  line-height: 1.25;
  text-wrap: balance;
}

/* The sky is as wide as the screen, whatever the stage's width. */
.stars {
  inset: 0 auto 0 50%;
  width: 100vw;
  height: 100%;
  margin-left: -50vw;
  fill: var(--cream);
}

.stars circle {
  transform-box: fill-box;
  transform-origin: center;
  animation: twinkle 4.2s ease-in-out infinite;
  animation-delay: var(--d);
}

@keyframes twinkle {
  50% {
    transform: scale(0.35);
  }
}

.hills,
.cloud {
  will-change: transform;
}

/* What melts one moment into the next: the foot of each scene sinks into the dark below it. */
.beat::after {
  content: "";
  position: absolute;
  inset: auto 0 0;
  z-index: 6;
  height: 14%;
  pointer-events: none;
}

/* Dusk: pink above, warming to cream at the horizon, and night coming up from below. */
.dusk {
  background: linear-gradient(#e9a9c4 0%, #f7bfc0 22%, #ffd3b6 46%, #ffe7d0 64%, #fff1e2 100%);
  color: var(--brown);
}

.dusk::after {
  height: 9%;
  background: linear-gradient(rgba(44, 7, 48, 0), var(--night));
}

.dusk .words {
  top: 21cqw;
}

.dusk .words p {
  color: #7c3a2e;
  font-size: 4.6cqw;
}

.dusk .badges {
  margin-top: 3.6cqw;
}

.dusk .stars {
  opacity: 0.5;
}

.dusk .cloud.a {
  width: 62%;
  height: auto;
  left: -16%;
  top: 39%;
}

.dusk .cloud.b {
  width: 40%;
  height: auto;
  right: -8%;
  top: 33%;
}

.dusk .cloud.c {
  width: 26%;
  height: auto;
  left: 34%;
  top: 45.5%;
  opacity: 0.8;
}

/* Hills, lights and floor are centred on the stage and at least as wide as the
   screen, so on a screen wider than the stage the scenery has no edge. */
.dusk .hills {
  --w: max(150cqw, 104vw);
  width: var(--w);
  height: auto;
  left: calc(50% - var(--w) / 2);
  bottom: 33%;
  opacity: 0.9;
}

.terrace {
  width: 112%;
  height: auto;
  left: -6%;
  bottom: -1%;
}

.lights {
  --w: max(118cqw, 104vw);
  width: var(--w);
  height: auto;
  left: calc(50% - var(--w) / 2);
  top: 46%;
  z-index: 2;
  filter: drop-shadow(0 0 10px rgba(255, 214, 140, 0.9));
}

.dusk .bia {
  width: 64%;
  height: auto;
  left: 18%;
  bottom: 4.5%;
  z-index: 3;
  filter: drop-shadow(0 14px 14px rgba(92, 31, 20, 0.22));
}

.hint {
  position: absolute;
  inset: auto 0 3.6cqw;
  z-index: 7;
  margin: 0;
  text-align: center;
  color: #fff;
  font-size: 4.4cqw;
  font-weight: 800;
  letter-spacing: 0.04em;
  animation: nudge 1.8s ease-in-out infinite;
}

@keyframes nudge {
  50% {
    transform: translateY(7px);
  }
}

/* Night: the icon's plum above, easing to a dusky rose at the horizon. */
.night {
  background: linear-gradient(var(--night) 0%, var(--plum) 30%, #7a2358 62%, #b3476f 86%, #d9727f 100%);
}

.night::after {
  height: 9%;
  background: linear-gradient(rgba(58, 10, 56, 0), #3a0a38);
}

.night .words {
  top: 54%;
}

.ecliptic {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

.ecliptic path {
  fill: none;
  stroke: var(--cream);
  stroke-width: 1;
  stroke-dasharray: 1 7;
  stroke-linecap: round;
  opacity: 0.35;
  vector-effect: non-scaling-stroke;
}

/* The five signs: one set, one treatment, in one arc. */
.signs {
  position: absolute;
  inset: 0;
}

.sign {
  position: absolute;
  width: calc(var(--w) * 0.2564cqw);
  height: auto;
  transform: translate(-50%, -50%);
  fill: var(--cream);
  stroke: var(--cream);
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
  opacity: 0.92;
  filter: drop-shadow(0 0 6px rgba(255, 220, 190, 0.55));
  overflow: visible;
}

.sign path {
  fill: none;
}

.sign circle {
  stroke: none;
  transform-box: fill-box;
  transform-origin: center;
}

.sign.libra {
  stroke: var(--gold);
  fill: var(--gold);
  stroke-width: 1.7;
  opacity: 1;
  filter: drop-shadow(0 0 10px rgba(255, 214, 140, 0.9));
}

.night .cloud.a {
  width: 70%;
  height: auto;
  left: -22%;
  top: 71%;
  filter: hue-rotate(-18deg) saturate(0.85) brightness(0.82);
  opacity: 0.42;
}

.night .cloud.c {
  width: 44%;
  height: auto;
  right: -10%;
  top: 66%;
  filter: hue-rotate(-18deg) saturate(0.85) brightness(0.8);
  opacity: 0.36;
}

.night .hills {
  --w: max(170cqw, 104vw);
  width: var(--w);
  height: auto;
  left: calc(50% - var(--w) / 2);
  bottom: -3%;
  filter: brightness(0.8);
}

/* She writes. The same terrace, after dark: the string lights and her phone are what light it. */
.write {
  background: linear-gradient(#3a0a38, var(--night));
}

.write::after {
  background: linear-gradient(rgba(44, 7, 48, 0), var(--night));
}

.write .terrace {
  filter: brightness(0.5) saturate(0.85) hue-rotate(-14deg);
}

.write .lights {
  top: 50%;
  filter: drop-shadow(0 0 16px rgba(255, 214, 140, 1));
}

.write .bia {
  width: 60%;
  height: auto;
  left: 20%;
  bottom: 4%;
  z-index: 3;
  filter: brightness(0.9);
}

.glow {
  left: 20%;
  bottom: 10%;
  z-index: 2;
  width: 60%;
  aspect-ratio: 1;
  border-radius: 50%;
  background: radial-gradient(rgba(255, 226, 190, 0.5), rgba(255, 226, 190, 0) 68%);
}

/* Her options, as the app's editor shows them. */
.options {
  position: absolute;
  inset: 68cqw 0 auto;
  z-index: 4;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 2.3cqw;
  width: 86%;
  margin: 0 auto;
  padding: 0;
  list-style: none;
  color: var(--brown);
}

.options li {
  padding: 2cqw 4.1cqw;
  border-radius: 999px;
  font-weight: 800;
  font-size: 4.4cqw;
}

.options li:nth-child(3n + 1) {
  background: #ffe0c4;
}

.options li:nth-child(3n + 2) {
  background: #ffd1d7;
}

.options li:nth-child(3n) {
  background: #ffd4c4;
}

/* She throws, and it is decided. The card is the app's own screen, in small. */
.decide {
  background: linear-gradient(var(--night), var(--plum));
}

.card {
  position: absolute;
  left: 50%;
  top: 29%;
  z-index: 3;
  width: 66%;
  aspect-ratio: 0.86;
  transform: translateX(-50%);
  border-radius: 8.7cqw;
  background: var(--cream);
  box-shadow:
    0 0 0 6px rgba(255, 245, 234, 0.14),
    0 24px 60px rgba(0, 0, 0, 0.45);
  color: var(--brown);
  text-align: center;
}

.verdict {
  margin: 8% 0 0;
}

.verdict small {
  display: block;
  font-weight: 800;
  font-size: 4.7cqw;
}

.winner {
  display: block;
  color: var(--coral);
  font-weight: 800;
  font-size: 11cqw;
  line-height: 1;
}

.card .die {
  width: 62%;
  height: auto;
  margin: 2% auto 0;
}

.card canvas {
  position: absolute;
  inset: -60% -70%;
  width: 240%;
  height: 220%;
  pointer-events: none;
}

.again {
  position: absolute;
  right: 7%;
  bottom: 15%;
  z-index: 4;
  padding: 3.1cqw 6.7cqw;
  border: 0;
  border-radius: 999px;
  background: var(--coral);
  box-shadow: 0 5px 0 var(--coral-dark);
  color: #fff;
  font: inherit;
  font-weight: 800;
  font-size: 4.6cqw;
  cursor: pointer;
}

.again:active {
  transform: translateY(3px);
  box-shadow: 0 2px 0 var(--coral-dark);
}

.decide .bia {
  width: 40%;
  height: auto;
  left: 3%;
  bottom: 2%;
  z-index: 4;
}

/* The collection: jewellery on velvet. */
.treasure {
  background: linear-gradient(var(--plum), var(--night));
}

/* The dice and, right under them, the gift they came out of. */
.hoard {
  position: absolute;
  inset: 78.5cqw 0 auto;
  z-index: 3;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.dice {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 1.5cqw 0.5cqw;
  width: 94%;
  margin: 0;
  padding: 0;
  list-style: none;
  text-align: center;
}

.dice img {
  width: 100%;
  height: auto;
  animation: bob 5s ease-in-out infinite;
  animation-delay: calc(var(--i) * -0.7s);
  filter: drop-shadow(0 10px 14px rgba(0, 0, 0, 0.35));
}

@keyframes bob {
  50% {
    transform: translateY(-7px) rotate(2deg);
  }
}

.dice span {
  display: block;
  margin-top: -1cqw;
  color: var(--dusk-rose);
  font-weight: 800;
  font-size: 3.1cqw;
  line-height: 1.1;
}

.gift {
  width: 46%;
  height: auto;
  margin-top: 1cqw;
  filter: drop-shadow(0 0 40px rgba(255, 214, 140, 0.45));
}

/* Her turn. */
.yours {
  background: linear-gradient(var(--night) 0%, var(--plum) 38%, #7a2358 70%, #b3476f 100%);
}

.yours::after {
  display: none;
}

.stores {
  position: absolute;
  inset: 67cqw 0 auto;
  z-index: 4;
  text-align: center;
}

.stores p {
  margin: 2.6cqw 0 0;
  color: var(--dusk-rose);
  font-size: 4.2cqw;
}

/* The stores' own buttons, as the stores publish them. */
.badges {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 2.6cqw;
  margin: 4.6cqw 0 0;
  padding: 0;
  list-style: none;
}

.stores .badges {
  margin-top: 0;
}

.badge img {
  width: auto;
  height: 11.4cqw;
}

.yours .hills {
  --w: max(170cqw, 104vw);
  width: var(--w);
  height: auto;
  left: calc(50% - var(--w) / 2);
  bottom: -3%;
  filter: brightness(0.85);
}

.yours .bia {
  width: 56%;
  height: auto;
  left: 22%;
  bottom: 7%;
  z-index: 3;
}

/* How things arrive. Everything is in place and visible from the start, so
   the page is whole without the script or before it runs; the script only
   plays an entrance as each thing is about to come into view. */
.reveal.play {
  animation: arrive 0.7s var(--pop) backwards;
  animation-delay: calc(var(--i, 0) * 80ms);
}

@keyframes arrive {
  from {
    opacity: 0;
    transform: translateY(24px) scale(0.96);
  }
}

/* The signs draw themselves, the outer ones last, then their stars come out. */
.signs path {
  stroke-dasharray: 1;
}

.signs.reveal.play {
  animation: none;
}

.signs.play path {
  animation: draw 1.3s ease backwards;
}

.signs.play .virgo path,
.signs.play .sagittarius path {
  animation-delay: 0.25s;
}

.signs.play .gemini path,
.signs.play .pisces path {
  animation-delay: 0.5s;
}

.signs.play circle {
  animation: star 0.5s var(--pop) backwards;
  animation-delay: calc(0.9s + var(--n) * 90ms);
}

@keyframes draw {
  from {
    stroke-dashoffset: 1;
  }
}

@keyframes star {
  from {
    transform: scale(0);
  }
}

/* The throw: the die drops, and the answer waits for it to land. */
.card.thrown .die {
  animation: drop 0.8s cubic-bezier(0.3, 0.9, 0.4, 1);
}

@keyframes drop {
  0% {
    opacity: 0;
    transform: translateY(-190%) rotate(-50deg) scale(0.7);
  }
  20% {
    opacity: 1;
  }
  58% {
    transform: translateY(0) rotate(4deg) scale(1.04, 0.94);
  }
  76% {
    transform: translateY(-13%) rotate(-2deg);
  }
  100% {
    transform: none;
  }
}

.card .verdict {
  transition:
    opacity 0.25s ease,
    transform 0.5s var(--pop);
}

.card.thrown:not(.decided) .verdict {
  opacity: 0;
  transform: scale(0.7);
  transition: none;
}

@media (prefers-reduced-motion: reduce) {
  .hint,
  .stars circle,
  .dice img,
  .reveal.play,
  .signs.play path,
  .signs.play circle,
  .card.thrown .die {
    animation: none;
  }
}

/* A screen wider than the stage, still upright: the wide painting of the
   terrace takes over (see the picture element), scaled so its rug is the size
   of the tall one's and centred under Bia. 0.63 is where the rug sits across it. */
@media (min-width: 520px) {
  .terrace {
    --w: max(210cqw, 136vw);
    width: var(--w);
    left: calc(50% - var(--w) * 0.63);
    bottom: -1cqw;
  }
}

/* A wide screen. The same evening, laid out sideways: the scene runs from edge
   to edge and each moment's words sit beside its picture. The stage is never
   flatter than a laptop screen, so the layers keep their places; lengths are
   in hundredths of its width (cqw). The same test is WIDE in tools/make-site.py. */
@media (min-width: 760px) and (min-aspect-ratio: 4/5) {
  header {
    width: 100%;
    padding: 1.5vw 7vw;
  }

  .logo {
    height: clamp(30px, 3.4vw, 70px);
  }

  .soon {
    padding: 0.5vw 1.4vw;
    font-size: clamp(0.72rem, 1.15vw, 1.4rem);
  }

  /* As wide as the screen, unless the screen is so wide for its height that a
     moment would be far taller than it; then the stage stops growing and the
     scenery carries on past it. Its height is a screen, held between the
     proportions of a laptop and of a tablet on its side. */
  .stage {
    --wide: min(100vw, 210svh);
    width: var(--wide);
    height: clamp(var(--wide) * 0.62, 100svh, var(--wide) * 0.78);
  }

  .words {
    inset: 8cqw auto auto 7cqw;
    width: 47cqw;
    text-align: left;
  }

  .words h1 {
    font-size: 4.9cqw;
  }

  .words h2 {
    font-size: 4.4cqw;
  }

  .words p {
    max-width: 36ch;
    margin: 0.8cqw 0 0;
    font-size: max(0.9rem, 1.7cqw);
  }

  /* In front of the string lights, which hang between the hills and the terrace. */
  .set {
    display: block;
    position: absolute;
    inset: auto 0 -1cqw;
    z-index: 3;
    aspect-ratio: 2.78;
  }

  .set .terrace {
    inset: 0;
    width: 100%;
    left: 0;
  }

  .lights {
    --w: max(100cqw, 104vw);
    top: auto;
    bottom: 23.5cqw;
  }

  .hint {
    inset: auto 0 1.2cqw;
    font-size: max(0.9rem, 1.2cqw);
  }

  .dusk .hills {
    --w: max(104cqw, 104vw);
    bottom: 19cqw;
  }

  .dusk .cloud.a {
    width: 28%;
    left: 56%;
    top: 5cqw;
  }

  .dusk .cloud.b {
    width: 16%;
    right: 3%;
    top: 13cqw;
  }

  .dusk .cloud.c {
    width: 9%;
    left: 47%;
    top: 16cqw;
  }

  .dusk .set .bia {
    width: 25.8%;
    left: 50%;
    bottom: 12%;
  }

  .night .words {
    inset: 34.5cqw 0 auto;
    width: auto;
    text-align: center;
  }

  .night .words p,
  .treasure .words p {
    margin-inline: auto;
  }

  /* Placed by the stage's width, like the words under them, since its height varies. */
  .signs {
    inset: 0 17% auto;
    height: 62cqw;
  }

  .sign {
    width: calc(var(--w) * 0.125cqw);
  }

  .night .cloud.a {
    width: 32%;
    left: -5%;
    top: 40cqw;
  }

  .night .cloud.c {
    width: 19%;
    right: -3%;
    top: 37cqw;
  }

  .night .hills,
  .yours .hills {
    --w: max(104cqw, 104vw);
  }

  /* On a screen wider than the stage the terrace, which is as wide as the
     stage, fades out at its ends instead of stopping. */
  @media (min-aspect-ratio: 21/10) {
    .set {
      -webkit-mask-image: linear-gradient(to right, transparent, #000 7%, #000 93%, transparent);
      mask-image: linear-gradient(to right, transparent, #000 7%, #000 93%, transparent);
    }
  }

  /* Room for the longer Spanish line to stay on one row, above the options. */
  .write .words {
    width: 62cqw;
  }

  .write .words h2 {
    text-wrap: wrap;
  }

  .write .lights {
    top: auto;
    bottom: 21cqw;
  }

  .write .set .bia {
    width: 24%;
    left: 51%;
    bottom: 10%;
  }

  .glow {
    left: 53%;
    bottom: 28%;
    width: 20%;
  }

  .options {
    inset: 18.5cqw auto auto 7cqw;
    grid-template-columns: repeat(3, 1fr);
    width: 40cqw;
    margin: 0;
    gap: 0.9cqw;
  }

  .options li {
    padding: 0.7cqw 1.5cqw;
    font-size: max(0.85rem, 1.5cqw);
  }

  .card {
    left: 72%;
    top: 10cqw;
    width: 24cqw;
    border-radius: 2.6cqw;
  }

  .verdict small {
    font-size: 1.5cqw;
  }

  .winner {
    font-size: 3.5cqw;
  }

  .again {
    right: auto;
    bottom: auto;
    left: 7cqw;
    top: 22cqw;
    padding: 0.9cqw 2.2cqw;
    font-size: max(0.9rem, 1.5cqw);
  }

  .decide .bia {
    width: 19cqw;
    left: 42%;
    bottom: 2%;
  }

  .treasure .words {
    inset: 7cqw 0 auto;
    width: auto;
    text-align: center;
  }

  .hoard {
    inset: 21cqw 0 auto;
  }

  .dice {
    grid-template-columns: repeat(6, 1fr);
    gap: 1cqw 0.6cqw;
    width: 58cqw;
  }

  .dice span {
    margin-top: -0.3cqw;
    font-size: max(0.68rem, 1.05cqw);
  }

  .gift {
    width: 15cqw;
    margin-top: 0.6cqw;
  }

  .dusk .words {
    top: 8cqw;
  }

  .dusk .words p {
    font-size: max(0.9rem, 1.7cqw);
  }

  .dusk .badges {
    margin-top: 1.7cqw;
  }

  .stores {
    inset: 21.5cqw auto auto 7cqw;
    text-align: left;
  }

  .stores p {
    margin-top: 0.8cqw;
    font-size: max(0.85rem, 1.3cqw);
  }

  .badges {
    justify-content: flex-start;
    gap: 0.9cqw;
    margin-top: 1.7cqw;
  }

  .badge img {
    height: 3.5cqw;
  }

  .yours .bia {
    width: 26cqw;
    left: 61%;
    bottom: 6cqw;
  }
}

footer {
  padding: 26px 20px 38px;
  background: #b3476f;
  text-align: center;
  font-weight: 600;
  font-size: 1rem;
}

footer nav {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 6px 22px;
}

footer a {
  color: var(--cream);
}

footer p {
  margin: 12px 0 0;
  color: var(--dusk-rose);
  font-size: 0.9rem;
}

/* Terms and privacy: plain pages on the app's cream. */
.plain {
  background: var(--cream);
  color: var(--brown);
  font-weight: 500;
}

.plain header {
  position: static;
}

.plain a {
  color: var(--coral-dark);
}

.plain footer {
  background: none;
  border-top: 2px solid var(--coral-soft);
}

.plain footer p {
  color: var(--brown-soft);
}

.legal {
  max-width: 720px;
  margin: 0 auto;
  padding: 16px 22px 64px;
}

.legal h1 {
  font-size: clamp(2rem, 6vw, 3rem);
}

.legal h2 {
  margin: 1.8em 0 0.3em;
  font-size: 1.4rem;
  line-height: 1.2;
  letter-spacing: 0;
}

.legal p,
.legal li {
  font-size: 1.05rem;
}

.legal .updated {
  color: var(--brown-soft);
  font-weight: 600;
}
