/* The 1.0.0 look, from the App Store set (v41, lane-store-creative): each section is one of the frames' colour
   fields under an ink dot grid, the headlines are cream with the accent in gold, the app sits in our own graphite
   device tilted 3 degrees, and one reward track runs across every band, as it runs across the nine frames.
   Loads after site.css and motion.css and only restyles them: the structure, the motion and the copy contract stay. */

html:has(> body.site) {
  overflow-x: clip;
}
/* The root's clip only hides the spill (a viewport turns clip into hidden): the page is still wider, and an iPad can
   zoom out to it. The body clips it for real; the root's own overflow keeps the body's from moving to the viewport.
   A tilted device leans 1 to 7 px past the edge between 790 and 1130 px, and the bands' colour bleeds past main and
   the wrapper, so the cut is at the body, the screen's edge at every width. */
body.site {
  overflow-x: clip;
}
/* Safari 26 on iPhone drops theme-color and tints the bars above and below the page from the body's background colour
   (the iOS 26.5 simulator; the root's is not read). While the first screen is in view (site.js) the body's colour is
   the top band's blue, with its navy canvas painted over it as an image, so the page looks the same and the bar over
   the blue header is blue (Shahrum, 2026-10-22: "fill this upper part in the same blue the top part of the page uses").
   Further down it is the navy again, so the bar under the navy footer stays navy. */
html.at-top body.site {
  background: linear-gradient(var(--canvas), var(--canvas)) #2456c3;
}
.site {
  --b-blue: #2456c3;
  --b-violet: #5a35b5;
  --b-green: #16643c;
  --b-teal: #116572;
  --b-rust: #964412;
  --b-berry: #a03167;
  --body-80: #ece6d6;
  --drop: 0 18px 0 rgb(25 17 33 / 0.38);
  --pill-ink: 0 4px 0 var(--ink);
}
.site .disp {
  letter-spacing: 0.02em;
  line-height: 1.06;
}
.site .disp em {
  color: var(--gold);
}

/* ---------- Bands ---------- */
.site .band {
  position: relative;
  --mute: var(--body-80);
}
.site .band::after {
  content: "";
  position: absolute;
  z-index: -1;
  inset: 0 calc(50% - 50vw);
  pointer-events: none;
  /* v41's grid, softened so it never fights the text (Shahrum, 2026-10-15): the same ink squares at about two thirds
     of their old strength (2026-10-15: a tenth read as flat colour). Fixed, so it never scrolls (ADR-0089). */
  background:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='18' height='18'%3E%3Crect x='7' y='0' width='3' height='3' fill='%23191121' fill-opacity='.13'/%3E%3C/svg%3E")
    50% 0 / 18px 18px fixed,
    var(--band);
}
@media (prefers-contrast: more), (prefers-reduced-transparency: reduce) {
  .site .band::after {
    background: var(--band);
  }
}
.site .b-blue {
  --band: var(--b-blue);
}
.site .b-violet {
  --band: var(--b-violet);
}
.site .b-green {
  --band: var(--b-green);
}
.site .b-teal {
  --band: var(--b-teal);
}
.site .b-rust {
  --band: var(--b-rust);
}
.site .b-berry {
  --band: var(--b-berry);
}
/* The header and the hero are one field: the hero's colour reaches up over the season's top padding. */
.site .top.band {
  z-index: 2;
}
.site .hero.band::after {
  top: -160px;
}
.site .top .mark {
  text-shadow: 2px 3px 0 var(--ink);
}

/* ---------- Pills: a reward, as the frames show one ---------- */
.site .pill {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 8px 16px 8px 10px;
  border: 2px solid var(--ink);
  border-radius: 6px;
  background: #29314c;
  box-shadow: var(--pill-ink);
  color: var(--cream);
  font:
    700 16px / 1.15 -apple-system,
    BlinkMacSystemFont,
    "SF Pro Rounded",
    "Segoe UI",
    Roboto,
    sans-serif;
  white-space: nowrap;
}
.site .pill img {
  width: 26px;
  height: 26px;
  flex: none;
}

/* ---------- The device: our own graphite body, no island, no buttons (Apple's rule for drawn devices) ---------- */
.site .gdev {
  --w: 240px;
  position: relative;
  display: block;
  width: var(--w);
  padding: calc(var(--w) * 0.034);
  border-radius: calc(var(--w) * 0.155);
  background: #2b2e36;
  box-shadow:
    inset 0 0 0 1.5px #a3a7b3,
    inset 0 0 0 calc(var(--w) * 0.014) #40444e,
    var(--drop);
}
.site .dev-screen {
  position: relative;
  display: block;
  overflow: hidden;
  border-radius: calc(var(--w) * 0.125);
  background: #060607;
  box-shadow: 0 0 0 calc(var(--w) * 0.006) #060607;
}
.site .dev-screen img {
  display: block;
  width: 100%;
  height: auto;
}
.site .gdev.pad {
  padding: calc(var(--w) * 0.028);
  border-radius: calc(var(--w) * 0.06);
}
.site .gdev.pad .dev-screen {
  border-radius: calc(var(--w) * 0.035);
}
/* The captures' status bar is cleared (prep.py); 9:41 is drawn back, as the frames do. */
.site .sb {
  position: absolute;
  top: 2.1%;
  left: 9%;
  color: #fff;
  font:
    600 calc(var(--w) * 0.058) / 1 -apple-system,
    BlinkMacSystemFont,
    "SF Pro Text",
    sans-serif;
  letter-spacing: -0.01em;
}
.site .sb::after {
  content: "";
  position: absolute;
  top: 0.08em;
  left: calc(var(--w) * 0.66);
  width: 1.9em;
  height: 0.86em;
  box-sizing: border-box;
  border: 0.09em solid rgb(255 255 255 / 0.55);
  border-radius: 0.26em;
  background: linear-gradient(90deg, #fff 0 70%, transparent 70%) content-box;
  padding: 0.1em;
}
.site .pad .sb {
  top: 1.2%;
  left: 3.5%;
  font-size: calc(var(--w) * 0.026);
}
.site .pad .sb::after {
  left: calc(var(--w) * 0.83);
}
/* Whose device it is: the frames' tag, kid blue or grown-up orange. */
.site .dev-tag {
  display: inline-block;
  justify-self: start;
  width: max-content;
  padding: 5px 9px 4px;
  border: 2px solid var(--ink);
  border-radius: 4px;
  box-shadow: 0 3px 0 var(--ink);
  font: 400 13px / 1 var(--display);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink);
  background: var(--orange);
}
.site .dev-tag.kid {
  background: #6aa3ff;
}

/* ---------- Hero: frame 1, two devices and the approval loop ---------- */
.site .hero h1 {
  font-size: clamp(34px, 8.2cqi, 62px);
}
.site .hero .lede {
  color: var(--body-80);
  font-size: 18px;
  max-width: 34ch;
}
.site .hero {
  padding-top: 24px;
}
.site .cz.duo {
  --canvas: transparent;
  grid-column: 2;
  display: grid;
  margin: 8px 0 0;
  background: none;
  border: 0;
  box-shadow: none;
  padding: 0;
  font-size: 15px;
}
.site .duo-stage {
  position: relative;
  container-type: inline-size;
  width: 100%;
  aspect-ratio: 1 / 1;
  /* The band's bottom edge crops the devices' feet, as the frame's does; the tilted corners stay whole. */
  clip-path: inset(-80px -80px 0 -80px);
  margin-bottom: 0;
}
.site .duo-pad,
.site .duo-phone {
  position: absolute;
  display: grid;
  gap: 8px;
  justify-items: start;
}
.site .duo-pad {
  right: 0;
  top: 21cqw;
  rotate: -3deg;
}
.site .duo-pad .gdev {
  --w: 72cqw;
}
.site .duo-pad .dev-tag {
  justify-self: end;
  margin-right: 4cqw;
}
.site .duo-phone {
  left: 0;
  top: 17cqw;
  rotate: 3deg;
  z-index: 1;
}
.site .duo-phone .gdev {
  --w: 34cqw;
}
.site .duo .pill {
  position: absolute;
  z-index: 2;
  font-size: clamp(13px, 3.4cqw, 17px);
}
.site .duo .pill img {
  width: clamp(20px, 5cqw, 26px);
  height: auto;
}
.site .duo .p1 {
  left: 1cqw;
  top: 1.5cqw;
}
.site .duo .p2 {
  right: 3cqw;
  top: 9cqw;
  rotate: 2deg;
}
.site .duo .foot {
  position: absolute;
  inset: auto 0 0 auto;
  z-index: 3;
  padding: 0;
}
.site .duo figcaption {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
.site .cz.duo {
  position: relative;
}
/* The loop, from the app's own screens (8 s): the kid checks off Unload the dishwasher on the iPad; on your phone you tap
   Approve on Feed the dog and the Undo bar shows; the approved row glows and the battle pass above them fills. The screens
   are the app's own frames, with nothing drawn over them but the taps and the glow (Gate P comment, 2026-10-15). Plays only
   on screen and in a visible tab, with no pause button (Shahrum, Gate P 2026-10-15) (motion.js, cz0); otherwise, and with
   reduced motion, it holds the moment after. */
.site .duo .sb {
  z-index: 1;
}
.site .duo .nx {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}
.site .tap-ring {
  position: absolute;
  z-index: 2;
  left: 72.9%;
  top: 81.7%;
  width: 26%;
  aspect-ratio: 1.9;
  translate: -50% -50%;
  border: 3px solid var(--cream);
  border-radius: 8px;
  box-shadow: 0 0 0 2px var(--ink);
  opacity: 0;
}
.site .tap-ring.kid {
  left: 12%;
  top: 46.6%;
  width: 6.5%;
  aspect-ratio: 1;
}
.site .lift {
  position: absolute;
  left: 8.4%;
  right: 8.4%;
  top: 44.3%;
  height: 10%;
  border: 3px solid var(--gold);
  border-radius: 8px;
  box-shadow:
    0 0 0 2px var(--ink),
    0 0 24px rgb(255 210 74 / 0.55);
}
@media (prefers-reduced-motion: no-preference) {
  .site .duo.run:not(.paused) .pill {
    animation: duo-bob 3.2s ease-in-out infinite alternate;
  }
  .site .duo.run:not(.paused) .p2 {
    animation-delay: -1.6s;
  }
  @keyframes duo-bob {
    from {
      translate: 0 0;
    }
    to {
      translate: 0 -6px;
    }
  }
}

/* ---------- The ladder: each step on its device, tilted like the frames ---------- */
.site .devlink {
  display: grid;
  gap: 10px;
  justify-items: start;
  max-width: none;
  padding-bottom: 22px;
  text-decoration: none;
}
.site .ladder .devlink .gdev {
  --w: min(200px, 60cqi);
}
.site .ladder .step:nth-child(odd) .gdev {
  rotate: 2deg;
}
.site .ladder .step:nth-child(even) .gdev {
  rotate: -2deg;
}
.site .ladder .step h2 {
  font-size: 22px;
}

/* ---------- Feature bands ---------- */
.site .feature.band,
.site .safety.band {
  padding-block: 112px 0;
  margin-top: 0;
}
.site .feature h2 {
  font-size: clamp(28px, 6.4cqi, 50px);
}
.site .feature p {
  font-size: 17px;
  color: var(--body-80);
}
.site .feature + .feature {
  margin-top: 0;
}
/* The motion pieces become cards on the field, with the devices' drop. */
.site .band .cz:not(.duo, .pops) .stage,
.site .band .mr {
  box-shadow: var(--drop);
}
/* "In the app": the device sinks into the band's bottom edge, its foot cropped, as in the frames. */
.site .appshot {
  align-self: end;
  justify-items: start;
  width: 100%;
  gap: 10px;
}
.site .appshot .sink {
  width: calc(100% + 24px);
  clip-path: inset(-40px -40px 0 -40px);
  padding: 6px 12px 0;
  margin: 0 -12px;
  aspect-ratio: 240 / 450;
}
.site .appshot .devlink {
  padding: 0;
}
.site .appshot .gdev {
  --w: 250px;
  rotate: 3deg;
  transform-origin: top left;
}
.site .appshot .gdev {
  box-shadow:
    inset 0 0 0 1.5px #a3a7b3,
    inset 0 0 0 4px #40444e;
}
.site .feature:nth-of-type(even) .appshot .gdev {
  rotate: -3deg;
  transform-origin: top right;
}
@container (max-width: 899px) {
  .site .appshot {
    width: min(70cqi, 280px);
    justify-self: center;
  }
  .site .appshot .gdev {
    --w: min(70cqi, 280px);
  }
}

/* ---------- The reward track: one bar across every band, as across the nine frames ---------- */
.site .tr {
  position: absolute;
  z-index: 2;
  top: -12px;
  left: calc(50% - 50vw);
  width: 100vw;
  height: 24px;
  background: var(--ink);
  pointer-events: none;
}
.site .tr::before {
  /* the ticks still ahead */
  content: "";
  position: absolute;
  inset: 8px 0;
  background: repeating-linear-gradient(90deg, transparent 0 46px, #63677c 46px 50px);
}
.site .tr-fill {
  position: absolute;
  left: 0;
  top: 5px;
  bottom: 5px;
  width: var(--at);
  background: linear-gradient(180deg, rgb(255 255 255 / 0.3) 0 3px, transparent 3px), var(--kid);
  transform-origin: left;
}
.site .tr-gift {
  position: absolute;
  left: var(--at);
  top: 50%;
  width: 36px;
  height: 36px;
  margin: -18px 0 0 -18px;
  border: 2px solid var(--ink);
  border-radius: 4px;
  box-shadow: 0 3px 0 var(--ink);
  background:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M3.5 8.5l3 3 6-7' fill='none' stroke='%23191121' stroke-width='2.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E")
    center / 22px no-repeat,
    var(--cream);
}
.site .tr .pill {
  position: absolute;
  top: 34px;
}
.site .tr.gold .tr-gift {
  width: 44px;
  height: 44px;
  margin: -22px 0 0 -22px;
  background:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M8 1.5l1.9 4 4.4.5-3.3 3 .9 4.4L8 11.2l-3.9 2.2.9-4.4-3.3-3 4.4-.5z' fill='%23191121'/%3E%3C/svg%3E")
    center / 24px no-repeat,
    var(--gold);
}
.site .tr.gold .pill {
  border-color: var(--ink);
  background: #3a3424;
  box-shadow:
    0 0 0 2px var(--gold),
    var(--pill-ink);
}
@media (max-width: 599px) {
  .site .tr .pill {
    font-size: 14px;
  }
}
/* It fills as it rises onto the screen (motion.js adds .on), and when the fill lands (.lit) the gift ticks, the
   present lights and pops, and the reward label rises in. Scrolling back up, it rewinds.
   .still is a reload mid-page: the state as it is, with no motion. Without the script, or with reduced motion, it
   shows full. */
/* The scripts' line sentinels (motion.js, site.js): 1 px, unseen, hung below a bar or a step so the observer's screen
   edge works as a line part way down: the fill line 86% (tracks) or 85% (season steps) down, the rewind line (.up)
   56% or 55% down. Between the two, the scroll's direction decides. */
.site .tr-sense,
.site .line-sense {
  position: absolute;
  left: 0;
  width: 1px;
  height: 1px;
  visibility: hidden;
  pointer-events: none;
}
.site .tr-sense {
  top: 14vh;
}
.site .tr-sense.up {
  top: 44vh;
}
.site .line-sense {
  top: 15vh;
}
.site .line-sense.up {
  top: 45vh;
}
@media (prefers-reduced-motion: no-preference) {
  .tr-js .site .tr-fill {
    transform: scaleX(0);
    transition: transform 0.7s cubic-bezier(0.45, 0, 0.55, 1);
  }
  .tr-js .site .tr.on .tr-fill {
    transform: scaleX(1);
    transition: transform 0.8s cubic-bezier(0.3, 0.6, 0.3, 1);
  }
  .tr-js .site .tr.still,
  .tr-js .site .tr.still *,
  .tr-js .site .tr.still *::after {
    transition: none !important;
    animation: none !important;
  }
  .tr-js .site .tr-gift {
    background-color: #63677c;
    background-size:
      0 0,
      auto;
    transition:
      background-color 0.15s linear,
      background-size 0.3s cubic-bezier(0.2, 0.9, 0.3, 1.5),
      scale 0.3s cubic-bezier(0.2, 0.9, 0.3, 1.5);
  }
  .tr-js .site .tr .pill {
    opacity: 0;
  }
  .tr-js .site .tr.lit .tr-gift {
    background-color: var(--cream);
    background-size: 22px, auto;
    scale: 1.12;
  }
  .tr-js .site .tr.gold.lit .tr-gift {
    background-color: var(--gold);
    background-size: 24px, auto;
  }
  .tr-js .site .tr.lit .pill {
    opacity: 1;
  }
}

/* ---------- Safety on berry: frame 4's field ---------- */
.site .safety.band {
  padding-bottom: 72px;
}
.site .safety .points svg {
  color: var(--gold);
}
.site .safety .points p {
  color: var(--body-80);
}

/* ---------- Plans: the track's last stop, the gold prize ---------- */
.site .plans {
  position: relative;
  padding-top: 120px;
}
.site .plans > h2 {
  font-size: clamp(28px, 6.4cqi, 50px);
}
.site .plans-lede {
  margin: 10px 0 22px;
  font-size: 18px;
  color: var(--body);
}
.site .plans-lede b {
  color: var(--gold);
}

/* ---------- Wide screens ---------- */
@container (min-width: 900px) {
  .site .hero {
    grid-template-columns: var(--col) minmax(0, 0.9fr) minmax(0, 1.1fr);
    padding-top: 40px;
  }
  .site .hero > div {
    padding-right: 24px;
    padding-bottom: 72px;
  }
  .site .cz.duo {
    grid-column: 3;
    grid-row: 1;
    align-self: end;
    margin: 0;
  }
  .site .feature > div:has(> .viz.pair) {
    grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.2fr);
  }
  .site .feature > div > h2,
  .site .feature > div > p {
    align-self: start;
  }
  .site .feature > div {
    align-items: end;
  }
  .site .viz.pair {
    grid-template-columns: minmax(0, 1fr) 250px;
    gap: 36px;
    align-items: end;
  }
  .site .viz.pair > .cz,
  .site .viz.pair > .mr {
    margin-bottom: 72px;
  }
  .site .safety.band {
    padding-block: 120px 96px;
  }
}
@container (min-width: 1000px) {
  .site .hero {
    grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr);
  }
  .site .cz.duo {
    grid-column: 2;
  }
  .site .ladder .step h2 {
    font-size: 24px;
  }
  .site .ladder .devlink .gdev {
    --w: min(190px, 16cqi);
  }
}
@container (max-width: 899px) {
  .site .viz.pair > .cz,
  .site .viz.pair > .mr {
    margin-bottom: 16px;
  }
  .site .feature > div > p {
    margin-bottom: 8px;
  }
}

/* On a phone the two devices take the full width, the rung column included, and keep one pill. */
@container (max-width: 899px) {
  .site .cz.duo {
    grid-column: 1 / -1;
    margin-top: 12px;
  }
}
@media (max-width: 599px) {
  .site .duo .p2 {
    display: none;
  }
}
/* On a phone the season's first rung sits on the blue field: the kid's lighter blue, so it reads. */
.site .hero .rung.zero {
  background: #6aa3ff;
}
/* On a phone the two devices and the +5 XP should reach the first screen: tighter hero spacing. */
@container (max-width: 899px) {
  .site .hero {
    padding-top: 8px;
  }
  .site .hero > div {
    gap: 10px;
  }
  .site .hero .lede {
    font-size: 17px;
  }
}
/* The season's top prize: the gold pill on the last rung, as frame 9's track ends. */
.site .prize .pill.top {
  justify-self: start;
  max-width: 100%;
  font-size: 15px;
  text-align: left;
  background: #3a3424;
  box-shadow:
    0 0 0 2px var(--gold),
    var(--pill-ink);
  white-space: normal;
  rotate: -2deg;
}
/* Captions under a motion piece sit on the band, not on the card: the band's lighter body colour. */
.site .band .cz .foot figcaption {
  color: var(--body-80);
}

/* Design critic, Gate P pass (2026-10-14). */
/* On a phone the season's spine starts at the first step: the hero has no rung of its own. */
@container (max-width: 999px) {
  .site .hero .rung.zero {
    display: none;
  }
  .site .hero {
    grid-template-columns: minmax(0, 1fr);
  }
  .site .cz.duo {
    grid-column: 1;
  }
}
@container (min-width: 900px) and (max-width: 999px) {
  .site .hero {
    grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr);
  }
  .site .cz.duo {
    grid-column: 2;
  }
}
/* Bigger devices on a phone, the iPad running off the edge as in frame 1. */
@media (max-width: 599px) {
  .site .duo-phone .gdev {
    --w: 39cqw;
  }
  .site .duo-pad .gdev {
    --w: 63cqw;
  }
  .site .duo-pad {
    right: 1cqw;
    top: 20cqw;
  }
}
@media (max-width: 359px) {
  .site .duo-pad {
    top: 24cqw;
  }
  .site .duo .p1 {
    font-size: 12px;
  }
}
/* Captions clear the card's hard drop. */
.site .band .cz:not(.pops) .foot {
  margin-top: 28px;
}
/* The ladder's last line clears the seam below it. */
.site .ladder {
  padding-bottom: 64px;
}
/* Plans take the hero's blue, bookending the page; the questions and footer stay on ink. */
.site .plans.band {
  padding-bottom: 72px;
}
.site .plans .fine {
  color: var(--body-80);
}

/* Gate P round 2: the yearly plan's saving, on Plus's price (his comment, 2026-10-15). */
.site .compare .save {
  display: inline-block;
  margin: 4px 0 0 2px;
  padding: 2px 7px 3px;
  border: 2px solid var(--ink);
  border-radius: 5px;
  background: #1f6b3a;
  color: #fff;
  font: 400 12px / 1.1 var(--display);
  letter-spacing: 0.03em;
  box-shadow: 0 2px 0 var(--ink);
  rotate: -2deg;
  white-space: nowrap;
}
.site .compare .per {
  display: block;
  margin-top: 6px;
  font-size: 12px;
  font-weight: 600;
  color: var(--ink);
}

/* Gate P round 3: each ladder screen plays its moment once as it comes into view; a tap replays it (motion.js adds
   .ls-on to the root, then .play per step). The static image is the moment's end; the earlier frames sit above it and
   fade out in turn. Without the script, or with reduced motion, the end frame shows and nothing moves. */
.site .ls .pre {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: 0;
}
.site .ls .sb {
  z-index: 1;
}
.site .ls-ring,
.site .ls-glow,
.site .ls-sweep {
  position: absolute;
  z-index: 2;
  opacity: 0;
  pointer-events: none;
}
.site .ls-ring {
  translate: -50% -50%;
  border: 3px solid var(--cream);
  border-radius: 8px;
  box-shadow: 0 0 0 2px var(--ink);
}
.site .ls-glow {
  border: 3px solid var(--gold);
  border-radius: 7px;
  box-shadow:
    0 0 0 2px var(--ink),
    0 0 18px rgb(255 210 74 / 0.55);
}
/* the battle pass bar on the kid's Today (its blue ends at 29.3%, the bar at 92%) */
.site .ls-sweep {
  left: 29.3%;
  top: 23.3%;
  width: 62.7%;
  height: 1.9%;
  background: linear-gradient(180deg, #669cf7 0 35%, #397def 35%);
  transform-origin: left;
}
.ls-on .site .ls .pre {
  opacity: 1;
}
.ls-on .site .ls.play .pre {
  animation: ls-out var(--o, 0.4s) ease-in-out var(--d) both;
}
.ls-on .site .ls.play .ls-ring {
  animation: ls-ring 0.75s ease-out var(--d) both;
}
.ls-on .site .ls.play .ls-glow {
  animation: ls-glow var(--g, 1.8s) ease-out var(--d) both;
}
.ls-on .site .ls .ls-sweep {
  opacity: 1;
  scale: 0 1;
}
.ls-on .site .ls.play .ls-sweep {
  animation:
    ls-sweep 0.9s cubic-bezier(0.3, 0.7, 0.2, 1) var(--d) both,
    ls-out 0.4s ease-in-out var(--d2) both;
}
@keyframes ls-out {
  from {
    opacity: 1;
  }
  to {
    opacity: 0;
  }
}
@keyframes ls-ring {
  0% {
    opacity: 0;
    scale: 0.6;
  }
  30% {
    opacity: 1;
    scale: 1;
  }
  100% {
    opacity: 0;
    scale: 1.3;
  }
}
@keyframes ls-glow {
  0% {
    opacity: 0;
  }
  18%,
  70% {
    opacity: 1;
  }
  100% {
    opacity: 0;
  }
}
@keyframes ls-sweep {
  from {
    scale: 0 1;
  }
  to {
    scale: 1 1;
  }
}

/* Gate P round 4: the season bar fills by step as each step comes into view (site.js sets --reach), the way the
   reward tracks fill; the tiers check as the fill reaches them. Reduced motion: the bar shows full, as before. */
html.fill-js .site .season::after {
  animation: none;
  transform: scaleY(var(--reach, 0.04));
  transition: transform 0.9s cubic-bezier(0.3, 0.3, 0.4, 1);
}
@container (min-width: 1000px) {
  html.fill-js .site .ladder::after {
    animation: none;
    transform: scaleX(var(--reach, 0.04));
    transition: transform 0.9s cubic-bezier(0.3, 0.3, 0.4, 1);
  }
}
html.fill-js .site .step .rung,
html.fill-js .site .step .rung.gold::before,
html.fill-js .site .step .rung.gold::after {
  animation: none;
}
/* A reward track's gift throws pixel confetti as its tick lands (motion.js). */
.site .tr-confetti {
  position: absolute;
  left: var(--at);
  top: 50%;
  width: 0;
  height: 0;
  pointer-events: none;
}
.site .tr-confetti i {
  position: absolute;
  left: -4px;
  top: -4px;
  width: 8px;
  height: 8px;
  box-shadow: 0 0 0 1px rgb(25 17 33 / 0.6);
}

/* Gate P round 5 (his comments, 2026-10-15). */
/* The hero's battle pass: the kid's track across the top of the stage, Movie night reached and Ice cream run 5 XP
   away. In the loop the approval fills it, and Ice cream run unlocks with a pop and confetti; held still (paused, off
   screen, reduced motion) it shows the moment after. */
.site .bp {
  position: absolute;
  z-index: 2;
  top: 0;
  left: 3cqw;
  right: 3cqw;
  height: 16cqw;
}
.site .bp-track {
  position: absolute;
  left: 0;
  right: 0;
  top: 10.6cqw;
  height: max(12px, 3.2cqw);
  border-radius: 3px;
  background:
    repeating-linear-gradient(90deg, transparent 0 calc(7% - 3px), #63677c calc(7% - 3px) 7%) 0 50%
    / 100% 40% no-repeat,
    var(--ink);
  box-shadow: 0 3px 0 rgb(0 0 0 / 0.35);
}
.site .bp-fill {
  position: absolute;
  left: 3px;
  top: 3px;
  bottom: 3px;
  width: calc(22% - 3px);
  border-radius: 2px;
  background: linear-gradient(180deg, rgb(255 255 255 / 0.3) 0 30%, transparent 30%), var(--kid);
  transform-origin: left;
}
.site .bp-node {
  position: absolute;
  top: calc(10.6cqw + max(12px, 3.2cqw) / 2);
  width: 0;
  height: 0;
}
.site .bp-node.a {
  left: 22%;
}
.site .bp-node.b {
  left: 82%;
}
.site .bp-gift,
.site .bp-lock {
  position: absolute;
  width: max(24px, 6.4cqw);
  aspect-ratio: 1;
  translate: -50% -50%;
  border: 2px solid var(--ink);
  border-radius: 4px;
}
.site .bp-gift {
  left: 0;
  top: 0;
  box-shadow: 0 3px 0 var(--ink);
  background:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M3.5 8.5l3 3 6-7' fill='none' stroke='%23191121' stroke-width='2.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E")
    center / 64% no-repeat,
    var(--cream);
}
.site .bp-lock {
  left: 50%;
  top: 50%;
  display: grid;
  place-items: center;
  border: 0;
  width: 100%;
  background: #8a8fa8;
  opacity: 0;
}
.site .bp-lock svg {
  width: 56%;
  height: 56%;
}
.site .duo .bp .pill {
  position: absolute;
  bottom: calc(max(24px, 6.4cqw) / 2 + 1.6cqw);
  font-size: clamp(12px, 3.1cqw, 16px);
  white-space: nowrap;
  rotate: 0deg;
}
.site .bp-node.a .pill {
  left: -4cqw;
  rotate: -2deg;
}
.site .bp-node.b .pill {
  right: -4cqw;
  rotate: 2deg;
}
.site .bp-tag {
  position: absolute;
  top: -11px;
  right: -8px;
  display: grid;
  font: 400 12px / 1 var(--display);
  letter-spacing: 0.03em;
  white-space: nowrap;
}
.site .bp-tag > span {
  grid-area: 1 / 1;
  justify-self: end;
  padding: 3px 6px 4px;
  border: 2px solid var(--ink);
  border-radius: 5px;
  box-shadow: 0 2px 0 var(--ink);
}
.site .bp-to {
  background: #2b2e36;
  color: var(--cream);
  opacity: 0;
}
.site .bp-yay {
  background: #1f6b3a;
  color: #fff;
}
.site .bp-bits i {
  position: absolute;
  left: -4px;
  top: -4px;
  width: 8px;
  height: 8px;
  box-shadow: 0 0 0 1px rgb(25 17 33 / 0.6);
  opacity: 0;
}
@media (prefers-reduced-motion: no-preference) {
  .site .duo.run:not(.paused) .bp .pill {
    animation: none;
  }
}

/* Plus perks: smaller loop boxes, so the column reads calmer (their insides scale with the box). */
.site .perks-track .box {
  width: 100%;
  max-width: 316px;
}
@media (min-width: 700px) {
  .site .perks-track .box {
    max-width: 340px;
  }
}

/* Footer: who made it sits level with the Sidequest mark, top right. */
@container (min-width: 700px) {
  .site .foot-made {
    align-content: start;
    padding-top: 2px;
  }
}

/* On a phone the two reward pills sit at the strip's two ends, so they never overlap. */
@media (max-width: 599px) {
  .site .bp-node.a .pill {
    left: -20.7cqw;
  }
  .site .bp-node.b .pill {
    right: -16.9cqw;
  }
  .site .duo .bp .pill {
    font-size: 12px;
  }
}
/* The smallest phones: smaller pills, and the devices drop a little to clear the strip's gifts. */
@media (max-width: 359px) {
  .site .duo .bp .pill {
    font-size: 12px;
    gap: 4px;
    padding-inline: 6px 8px;
  }
  .site .duo .bp .pill img {
    width: 16px;
  }
  .site .duo-phone {
    top: 21cqw;
  }
  .site .duo-pad {
    top: 27cqw;
  }
}

/* Gate P round 6: the frames' tilted pixel present beside each checkpoint, grey while ahead and gold with its purple
   ribbon once the fill reaches it (on every band track and the hero's battle pass). */
.site .tr-present,
.site .bp-present {
  position: absolute;
  aspect-ratio: 14 / 13;
  background:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 13' shape-rendering='crispEdges'%3E%3Cpath fill='%23191121' d='M2 0h4v2h2V0h4v3h2v4h-1v6H1V7H0V3h2z'/%3E%3Cpath fill='%2380859c' d='M1 4h12v2H1z'/%3E%3Cpath fill='%2363677c' d='M2 7h10v5H2z'/%3E%3Cpath fill='%2351556a' d='M2 11h10v1H2z'/%3E%3Cpath fill='%238f94ab' d='M6 4h2v2H6zM6 7h2v5H6z'/%3E%3Cpath fill='%23a3a8bd' d='M3 1h2v1H3zM9 1h2v1H9z'/%3E%3C/svg%3E")
    center / 100% 100% no-repeat;
  rotate: -14deg;
}
.site .tr-present::after,
.site .bp-present::after {
  content: "";
  position: absolute;
  inset: 0;
  background:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14 13' shape-rendering='crispEdges'%3E%3Cpath fill='%23191121' d='M2 0h4v2h2V0h4v3h2v4h-1v6H1V7H0V3h2z'/%3E%3Cpath fill='%23ffe48a' d='M1 4h12v2H1z'/%3E%3Cpath fill='%23ffd24a' d='M2 7h10v5H2z'/%3E%3Cpath fill='%23e0a62a' d='M2 11h10v1H2z'/%3E%3Cpath fill='%237b6cf6' d='M6 4h2v2H6zM6 7h2v5H6z'/%3E%3Cpath fill='%23b3a8ff' d='M3 1h2v1H3zM9 1h2v1H9z'/%3E%3C/svg%3E")
    center / 100% 100% no-repeat;
}
.site .tr-present {
  left: var(--at);
  top: 50%;
  width: 30px;
  margin: -24px 0 0 -38px;
}
.site .tr.gold .tr-present {
  width: 34px;
  margin: -28px 0 0 -45px;
}
.site .bp-present {
  left: calc(max(24px, 6.4cqw) * -0.62);
  top: calc(max(24px, 6.4cqw) * -0.2);
  width: calc(max(24px, 6.4cqw) * 0.84);
  translate: -50% -50%;
}
/* The label sits centred under its checkpoint, slid along only as far as it must to stay 16px inside the screen
   (the track is 100vw wide, so --a in vw is the checkpoint's x). */
.site .tr .pill,
.site .tr.r .pill {
  left: 0;
  right: auto;
  translate: clamp(16px, calc(var(--a) * 1vw - 50%), calc(100vw - 16px - 100%)) 0;
}
@media (prefers-reduced-motion: no-preference) {
  .tr-js .site .tr .pill {
    translate: clamp(16px, calc(var(--a) * 1vw - 50%), calc(100vw - 16px - 100%)) 0;
    transform: translateY(8px);
    transition:
      opacity 0.3s ease-out,
      transform 0.3s ease-out;
  }
  .tr-js .site .tr.lit .pill {
    translate: clamp(16px, calc(var(--a) * 1vw - 50%), calc(100vw - 16px - 100%)) 0;
    transform: none;
  }
  .tr-js .site .tr-present::after {
    opacity: 0;
    transition: opacity 0.15s linear;
  }
  .tr-js .site .tr.lit .tr-present::after {
    opacity: 1;
  }
  .tr-js .site .tr.lit .tr-present {
    animation: tr-present 0.5s cubic-bezier(0.2, 0.9, 0.3, 1.4);
  }
  @keyframes tr-present {
    0% {
      scale: 1;
      rotate: -14deg;
    }
    45% {
      scale: 1.35;
      rotate: -26deg;
    }
    100% {
      scale: 1;
      rotate: -14deg;
    }
  }
}

/* Gate P round 7 (his comments, 2026-10-15). */
/* The dark ground's dot grid takes the bands' 18 px pitch and 3 px square, so the dots run on straight through every
   band edge (both layers are fixed and centred on the screen, ADR-0089). A softer ink keeps the dark ground as quiet
   as the old 2 px dot. */
.site::before {
  background:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='18' height='18'%3E%3Crect x='7' y='0' width='3' height='3' fill='%23262c46'/%3E%3C/svg%3E")
    50% 0 / 18px 18px;
}
/* The plan terms sit in the table's empty footer cell, beside the Plus price. */
.site .compare tfoot .gap {
  vertical-align: top;
  text-align: left;
  padding: 14px 20px 0 0;
}
.site .compare tfoot .gap .fine {
  margin: 0;
  max-width: 46ch;
}
@media (max-width: 520px) {
  .site .compare tfoot .gap {
    padding: 10px 12px 0 0;
  }
}
@media (min-width: 1200px) {
  .site .plans-grid > .perks {
    grid-row: 1 / span 2;
  }
  .site .plans-grid > .levelup {
    grid-row: 2;
  }
}
/* Footer: who made it sits level with "Need help?" (the mark's 44 px row, the 4 px gap, then the
   link's 11 px tap padding). */
@container (min-width: 700px) {
  .site .foot-made {
    padding-top: calc(44px + 4px + 11px);
  }
}
/* Achievements: the app's "Achievement unlocked" pop-ups, one after another, the way Steam or Xbox shows them
   (Shahrum, 2026-10-15: not medals on a shelf). Held still (paused, off screen, reduced motion) the first one shows. */
.site .cz.pops .stage {
  /* no box: the pop-ups sit on the band, over a faded wall of the app's other achievements (round 8) */
  height: auto;
  overflow: visible;
  background: none;
  border: 0;
  border-radius: 0;
  box-shadow: none;
  display: grid;
  align-items: center;
  padding-block: 6px;
}
.site .cz.pops .wall {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 8px;
  opacity: 0.4;
}
.site .cz.pops .mini {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
  padding: 6px 10px 6px 6px;
  background: #29314c;
  border: 2px solid var(--ink);
  border-radius: 6px;
  color: var(--cream);
  font:
    700 13px / 1.2 -apple-system,
    BlinkMacSystemFont,
    "SF Pro Rounded",
    "Segoe UI",
    Roboto,
    sans-serif;
}
.site .cz.pops .mini b {
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
.site .cz.pops .pop {
  position: absolute;
  z-index: 1;
  left: 50%;
  top: 50%;
  width: min(80%, 330px);
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 18px 12px 12px;
  background: #29314c;
  border: 3px solid var(--gold);
  border-radius: 6px;
  outline: 2px dashed rgb(255 210 74 / 0.45);
  outline-offset: -8px;
  box-shadow:
    0 0 0 2px var(--ink),
    0 5px 0 2px var(--ink);
  translate: -50% -50%;
}
.site .cz.pops .pop::after {
  /* the gold sheen that crosses a pop-up as it lands */
  content: "";
  position: absolute;
  inset: 0;
  background:
    linear-gradient(100deg, transparent 42%, rgb(255 255 255 / 0.22) 50%, transparent 58%) 100% 0 /
    300% 100%;
  pointer-events: none;
}
.site .cz.pops .pop:not(.p1) {
  opacity: 0;
}
.site .cz.pops .coin {
  /* the app's coin: gold, ink-ringed, the achievement's own icon inside */
  display: grid;
  place-items: center;
  width: 46px;
  height: 46px;
  flex: none;
  border-radius: 50%;
  border: 2px solid var(--ink);
  background: radial-gradient(circle at 50% 42%, #ffe48a, var(--gold) 55%, #e0a62a);
  box-shadow: inset 0 0 0 3px rgb(224 166 42 / 0.9);
}
.site .cz.pops .coin img {
  width: 26px;
  height: 26px;
}
.site .cz.pops .coin.sm {
  width: 30px;
  height: 30px;
  box-shadow: inset 0 0 0 2px rgb(224 166 42 / 0.9);
}
.site .cz.pops .coin.sm img {
  width: 18px;
  height: 18px;
}
.site .cz.pops .tx {
  display: grid;
  gap: 2px;
  min-width: 0;
  text-align: left;
  font-family: -apple-system, BlinkMacSystemFont, "SF Pro Rounded", "Segoe UI", Roboto, sans-serif;
}
.site .cz.pops .t1 {
  font-size: 12px;
  line-height: 1.2;
  letter-spacing: 0.08em;
  color: var(--gold);
}
.site .cz.pops .t2 {
  font-size: 17px;
  line-height: 1.2;
  color: var(--cream);
}
.site .cz.pops .t3 {
  font-size: 13px;
  line-height: 1.3;
  color: #b6bbd0;
}
/* Beside the phone on a wide screen it sits mid-height with a fourth row of the wall; a phone shows three rows. */
@container (min-width: 900px) {
  .site .viz.pair > .cz.pops {
    align-self: center;
    margin-bottom: 0;
  }
}
@media (max-width: 899px) {
  .site .cz.pops .mini:nth-child(n + 7) {
    display: none;
  }
}
.site .cz.pops .spk {
  position: absolute;
  width: 12px;
  height: 12px;
  background:
    linear-gradient(#fff, #fff) center / 4px 100% no-repeat,
    linear-gradient(#fff, #fff) center / 100% 4px no-repeat;
}
.site .cz.pops .spk.a {
  left: -8px;
  top: -9px;
}
.site .cz.pops .spk.b {
  right: 14px;
  bottom: 10px;
  width: 8px;
  height: 8px;
  background-size:
    2px 100%,
    100% 2px;
}
.site .cz.pops.run:not(.paused) .pop {
  animation: pop-in 9s infinite both;
}
.site .cz.pops.run:not(.paused) .pop::after {
  animation: pop-shine 9s infinite both;
}
.site .cz.pops.run:not(.paused) .coin {
  animation: pop-coin 9s infinite both;
}
.site .cz.pops.run:not(.paused) .spk {
  animation: pop-spk 9s infinite both;
}
.site .cz.pops.run:not(.paused) .p2,
.site .cz.pops.run:not(.paused) .p2::after,
.site .cz.pops.run:not(.paused) .p2 .coin,
.site .cz.pops.run:not(.paused) .p2 .spk {
  animation-delay: 3s;
}
.site .cz.pops.run:not(.paused) .p3,
.site .cz.pops.run:not(.paused) .p3::after,
.site .cz.pops.run:not(.paused) .p3 .coin,
.site .cz.pops.run:not(.paused) .p3 .spk {
  animation-delay: 6s;
}
@keyframes pop-in {
  0% {
    opacity: 0;
    transform: translateY(48px) scale(0.9);
  }
  4% {
    opacity: 1;
    transform: translateY(-6px) scale(1.04);
  }
  7%,
  29% {
    opacity: 1;
    transform: none;
  }
  33.3%,
  100% {
    opacity: 0;
    transform: translateY(-36px) scale(0.96);
  }
}
@keyframes pop-shine {
  0%,
  6% {
    background-position: 100% 0;
  }
  14%,
  100% {
    background-position: 0 0;
  }
}
@keyframes pop-coin {
  0%,
  3% {
    transform: scale(0) rotate(-90deg);
  }
  7% {
    transform: scale(1.25) rotate(10deg);
  }
  10%,
  100% {
    transform: none;
  }
}
@keyframes pop-spk {
  0%,
  5% {
    opacity: 0;
    transform: scale(0.2);
  }
  8% {
    opacity: 1;
    transform: scale(1.3);
  }
  12% {
    opacity: 1;
    transform: none;
  }
  18%,
  100% {
    opacity: 0;
    transform: scale(0.4);
  }
}

/* Plans: Free's ticks take its cream, so Plus's orange is the one that draws the eye (Shahrum, 2026-10-15). */
.site .compare tbody td:nth-child(2) .yes rect {
  fill: var(--cream);
}
/* Wide: the level-up sits centred under the table. */
@media (min-width: 1200px) {
  .site .plans-grid > .levelup {
    justify-self: center;
  }
}

/* ---------- Front-page review, 2026-10-15 (T-site-review-1015) ---------- */
/* The hero says what it is before the headline: the category, who it is for and the devices. */
.site .hero .eyebrow {
  margin: 0;
  color: var(--gold);
  font:
    700 16px / 1.3 -apple-system,
    BlinkMacSystemFont,
    "SF Pro Rounded",
    "Segoe UI",
    Roboto,
    sans-serif;
  letter-spacing: 0.01em;
  max-width: none;
}
@media (max-width: 599px) {
  .site .hero .lede {
    font-size: 16px;
  }
  .site .hero .eyebrow {
    font-size: 14px;
  }
}
/* The iPad fades into the band before its edge, so the crop never lands mid-row. */
.site .duo-pad .gdev {
  mask-image: linear-gradient(180deg, #000 0 60%, transparent 71%);
}
@media (max-width: 599px) {
  .site .duo-pad .gdev {
    mask-image: linear-gradient(180deg, #000 0 70%, transparent 81%);
  }
}
/* On a phone the devices reach the first screen: less air above the headline. */
@container (max-width: 899px) {
  .site .hero {
    padding-top: 0;
  }
  .site .hero > div {
    gap: 8px;
  }
  .site .hero h1 {
    margin-block: 0;
    font-size: clamp(31px, 8.2cqi, 62px);
  }
  .site .cz.duo {
    margin-top: 0;
  }
  .site .season {
    padding-top: 4px;
  }
}
/* Wide screens: a text column wide enough for a three-line headline, and section heads that stay in proportion. */
@container (min-width: 1000px) {
  .site .hero {
    grid-template-columns: minmax(0, 540px) minmax(0, 1fr);
  }
  .site .hero h1 {
    font-size: 56px;
    max-width: none;
    text-wrap: balance;
  }
}
@container (min-width: 900px) and (max-width: 999px) {
  .site .hero h1 {
    font-size: 42px;
    text-wrap: balance;
  }
}
/* Wide screens: no dead blue strip in the hero. The text runs the column's width, the devices' top meets the eyebrow,
   (Gate P comment, 2026-10-15). */
@container (min-width: 900px) {
  /* The hero starts close under the header (review 2026-10-18: "a small bit of extra blank space" between them on
     desktop): 28px of the season's top padding, none of the hero's, where it was 36 and 24. Not less: the header
     paints over the hero (its band reaches up under the header), and at 16px it sliced the top off the "XP to go"
     tags (2026-10-19); 28 keeps them about 8px clear, and clear through the unlock pop's 1.1 scale. */
  .site .season {
    padding-top: 28px;
  }
  .site .hero {
    padding-top: 0;
  }
  /* The header is the mark alone, so it is as slim as on a phone, and the words start level with the devices'
     top (Gate P comment, 2026-10-22: "tighten up some of this blank space"). */
  .site .top {
    padding-block: 12px;
  }
  .site .hero > div {
    align-self: start;
    padding-bottom: 32px;
  }
  .site .hero .lede {
    max-width: 470px;
  }
  /* Three chunks, not one block: the headline, the lede, then the next step. */
  .site .hero .get {
    margin-top: 16px;
  }
}
.site .feature h2,
.site .plans > h2 {
  font-size: clamp(28px, 6.4cqi, 44px);
}
/* The page ends on the next step, where the FAQ was (Gate P comments, 2026-10-15): a heading, the free line and the
   launch list, one column, so a visitor this far down can join without scrolling back up (site.js drives both
   boxes). No App Store line: the sign-up is the step (Gate P comment, 2026-10-21). */
.site .closing {
  padding-block: 36px 8px;
}
.site .closing > h2 {
  font-size: 22px;
  margin-bottom: 8px;
}
.site .closing > p {
  font-size: 16px;
  color: var(--mute);
}
.site .notify-end {
  margin-top: 20px;
  max-width: 460px;
}
/* On the dark page the ink edge vanishes (1.2:1); --dot gives the control a 3.4:1 edge (WCAG 1.4.11, design-critic), and
   its shadow goes darker than the band so it still shows. */
.site .notify-end .waitlist-row {
  border-color: var(--dot);
  box-shadow: 0 3px 0 #0a0c16;
}
/* The error line on the hero's blue: the dark band's coral is 3.43:1 there, this paler one 4.7:1 (design-critic). */
.site .hero .notify .waitlist-msg[data-kind="bad"] {
  color: #ffd0c4;
}
@container (min-width: 700px) {
  .site .closing {
    padding-block: 72px 8px;
  }
  .site .closing > h2 {
    font-size: 30px;
  }
}
/* A reward reads as a label, not a button: the pills lose their hard drop. */
.site .pill {
  box-shadow: none;
}
.site .tr.gold .pill,
.site .prize .pill.top {
  box-shadow: 0 0 0 2px var(--gold);
}
/* The track's confetti flies behind the screenshot sinking into the band above, never over its screen, while the
   track's checkpoint (the present, the gift and its label) stays in front of the phone (Gate P comment, 2026-10-15).
   The track is no stacking context of its own, so its parts layer against the phone one by one: the bar and the
   confetti under the phone, the checkpoint over it. */
.site .appshot .sink {
  position: relative;
  z-index: 3;
}
.site .tr {
  z-index: auto;
}
.site .tr-confetti {
  z-index: 2;
}
.site .tr-present,
.site .tr-gift,
.site .tr .pill {
  z-index: 4;
}
/* The phones end at the bar's top edge, so they sink behind the bar on the seam instead of covering its top half
   (the bar straddles the seam by 12 px; Gate P comment, 2026-10-15). */
.site .appshot .sink {
  clip-path: inset(-40px -40px 12px -40px);
}
/* How it works: bigger phones. */
.site .ladder .devlink .gdev {
  --w: min(240px, 66cqi);
}
/* Every phone that opens full size wears one expand badge with no words, pinned to its frame's top-right corner so it
   never sits on the app's own screen; it rides inside the frame, so it tilts with it. Drawn at 28 px (Gate P comment,
   2026-10-15: the 44 px badge was too big), its tap area stays 44 px through an invisible ring around it: on the ladder
   a tap on the screen replays its moment (motion.js, .ls), so the badge is the way to full size (Gate P comments,
   2026-10-15: a text label made the ladder busy; a badge on the status bar looked misplaced). Where the screen itself
   does something on a tap (the hero, pairing, the loot box), the badge is its own link (Shahrum, 2026-10-22: every
   device screenshot opens full size). */
.site .gdev > .zoom-hint {
  z-index: 2;
  top: -12px;
  right: -12px;
  left: auto;
  width: 28px;
  height: 28px;
  box-shadow: 0 2px 0 rgb(0 0 0 / 0.4);
  cursor: zoom-in;
}
.site .gdev > .zoom-hint::before {
  content: "";
  position: absolute;
  inset: -10px;
}
.site .gdev > .zoom-hint svg {
  width: 14px;
  height: 14px;
}
@media (hover: hover) {
  .site .devlink:hover .gdev > .zoom-hint,
  .site .gdev > a.zoom-hint:hover {
    color: var(--gold);
  }
}
@container (min-width: 700px) and (max-width: 999px) {
  .site .step:not(.hero):not(.prize) > div {
    grid-template-columns: 1fr 280px;
    column-gap: 40px;
  }
  .site .step:not(.hero):not(.prize) > div .zoom {
    grid-column: 2;
    grid-row: 1 / span 3;
  }
  .site .ladder .devlink .gdev {
    --w: 260px;
  }
}
@container (min-width: 1000px) {
  .site .ladder .devlink .gdev {
    --w: min(200px, 17.8cqi);
  }
}
/* The 404 page (public/404.html): one blue band, the headline and the way home. */
.site .nf {
  display: grid;
  gap: 16px;
  justify-items: start;
  padding-block: 48px 96px;
}
/* The plain-words name of the error, small and quiet above the headline, the way the home page's eyebrow sits. */
.site .nf .nf-code {
  margin: 0 0 -6px;
  color: var(--body-80);
  font:
    700 15px / 1.3 -apple-system,
    BlinkMacSystemFont,
    "SF Pro Rounded",
    "Segoe UI",
    Roboto,
    sans-serif;
  letter-spacing: 0.01em;
}
.site .nf h1 {
  margin: 0;
  font-size: clamp(34px, 8.2cqi, 56px);
}
.site .nf p {
  margin: 0;
  max-width: 40ch;
  color: var(--body-80);
  font-size: 18px;
}
.site .nf-home {
  display: inline-flex;
  align-items: center;
  min-height: 48px;
  margin-top: 8px;
  padding: 0 18px;
  border: var(--outline);
  border-radius: var(--r);
  background: var(--orange);
  color: var(--ink);
  box-shadow: var(--edge);
  font: 700 16px / 1 var(--text);
  text-decoration: none;
}
.site .nf-home:focus-visible {
  outline: 3px solid var(--gold);
  outline-offset: 2px;
}
/* No loop text under 12 px: the Plus perk loops' small labels keep a floor when their box is narrow. */
.site .rr-nm,
.site .rr-lab,
.site .ach-lbl,
.site .ach-t2 {
  font-size: max(12px, 2.9cqw);
}

/* Gate P round 9: the reward section shows the app's own loot box (the kid's screen, captured: loot.webp, an animated image that plays once) on a phone
   that sinks into the band like the screenshot beside it, tilted the other way. It plays once as it comes into view and
   holds on the reward (motion.js). Without the script, or with reduced motion, the reward shows, still. */
/* Not a container of its own (as .cz is): the phone sizes against the page, like every other screenshot. */
.site .viz.pair > .cz.loot {
  container-type: normal;
  margin-bottom: 0;
}
@container (min-width: 900px) {
  .site .viz.pair > .cz.loot {
    justify-self: end;
    width: 250px;
  }
}
.site .cz.loot .gdev {
  rotate: -3deg;
  transform-origin: top right;
}
.site .cz.loot figcaption {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
/* The two states, named the way the hero names its devices (Gate P comment): opening one reward, then the whole list. */
.site #unlock .appshot .dev-tag {
  position: relative;
  z-index: 4;
  margin-left: 14px;
  rotate: 3deg;
}
.site #unlock .cz.loot .dev-tag {
  justify-self: end;
  margin: 0 14px 0 0;
  rotate: -3deg;
}
/* Two phones side by side from a tablet up; a phone shows the loot box alone, as the Mission report shows once. */
@container (min-width: 560px) and (max-width: 899px) {
  .site #unlock .viz.pair {
    grid-template-columns: 1fr 1fr;
    align-items: end;
  }
  /* Each phone fits its half, tilt and expand badge included, so neither runs off a narrow tablet's edge. */
  .site #unlock .appshot {
    width: min(calc(50cqi - 44px), 280px);
  }
  .site #unlock .appshot .gdev {
    --w: min(calc(50cqi - 44px), 280px);
  }
}
@media (max-width: 599px) {
  .site #unlock .appshot:not(.loot) {
    display: none;
  }
}

/* The replay mark: once a moment has played, a play sign rests on its screen like a watermark: no button shape,
   translucent white with a shadow, its edges stepped on a fine pixel grid for a faint arcade nod. It tilts with its
   device, so it reads as laid over that screen, not as part of the app. A tap on the screen replays the moment
   (motion.js): the ladder's screens and the loot box. The hero loops for good and has none (Gate P, 2026-10-15). */
.site .ls-mark {
  position: absolute;
  z-index: 3;
  left: 50%;
  top: 50%;
  translate: -50% -50%;
  opacity: 0;
  pointer-events: none;
}
.site :is(.ls-mark, .replay) svg {
  display: block;
  width: 40px;
  height: 40px;
  filter: drop-shadow(0 2px 0 rgb(0 0 0 / 0.45)) drop-shadow(0 0 5px rgb(0 0 0 / 0.4));
}
/* The tap-to-replay cover. The mark sits at the screen's centre on every phone, the loot box's too (Gate P comment,
   2026-10-15: low on its rays it was hard to see). */
.site :is(.cz.loot, .mr-shot, .clip-shot) .replay {
  position: absolute;
  inset: 0;
  z-index: 3;
  display: grid;
  place-items: center;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.site :is(.cz.loot, .mr-shot, .clip-shot) .replay[hidden] {
  display: none;
}
.site :is(.cz.loot, .mr-shot, .clip-shot) .replay:focus-visible {
  outline: none;
}
.site :is(.cz.loot, .mr-shot, .clip-shot) .replay:focus-visible svg {
  outline: 3px solid var(--gold);
  outline-offset: 2px;
}
/* jump-none: a delayed animation can end at progress 0.99999, and steps(n, end) would then hold at (n-1)/n. */
.ls-on .site .ls.play .ls-mark {
  animation: sq-mark 0.3s steps(3, jump-none) var(--e) both;
}
.site :is(.cz.loot, .mr-shot, .clip-shot) .replay:not([hidden]) svg {
  animation: sq-mark 0.3s steps(3, jump-none) both;
}
@keyframes sq-mark {
  from {
    opacity: 0;
  }
  to {
    opacity: 0.7;
  }
}

/* The Mission report, live in the phone (Gate P comment, 2026-10-15): the drawn report is the phone's screen, laid
   out as the app's (a 320 pt column scaled to the screen, so every size follows the phone), and the screenshot it
   repeated is gone. It plays once when in view; the replay mark then rests on it (motion.js). */
.site .viz.solo {
  display: grid;
  justify-items: center;
}
.site .mr-shot {
  width: 300px;
}
.site .mr-shot .gdev {
  --w: 300px;
}
@container (max-width: 899px) {
  .site .mr-shot .gdev {
    --w: min(72cqi, 300px);
  }
  .site .mr-shot {
    width: min(72cqi, 300px);
  }
}
.site .mr-screen {
  container-type: inline-size;
  aspect-ratio: 600 / 1298;
  background: #1e2237;
}
.site .mr-screen .mr {
  --u: calc(100cqw / var(--cols, 320));
  --fs: calc(var(--u) * 13);
  --g: calc(var(--u) * 11);
  container-type: normal;
  min-height: 100%;
  padding: calc(var(--u) * 48) calc(var(--u) * 14) calc(var(--u) * 14);
  border: 0;
  border-radius: 0;
  box-shadow: none;
}
/* The app's backdrop under the report, as every real screen has it (Gate P comment, 2026-10-15): SQ.bg with the
   quest-map dot grid of AppBackground.swift (ADR-0089), a 2 pt #29314c dot every 16 pt, centred with a dot on the
   centre line and rows from the screen's top, in the report's own point unit. Flat with more contrast or less
   transparency, as in the app. */
.site .mr-screen .mr {
  background:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Crect width='2' height='2' fill='%2329314c'/%3E%3C/svg%3E")
    calc(50cqw - var(--u)) 0 / calc(var(--u) * 16) calc(var(--u) * 16),
    #1e2237;
}
@media (prefers-contrast: more), (prefers-reduced-transparency: reduce) {
  .site .mr-screen .mr {
    background-image: none;
  }
}
.site .mr-screen .mr-top {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: calc(var(--u) * 10);
}
.site .mr-screen .mr-btn {
  display: grid;
  place-items: center;
  width: calc(var(--u) * 30);
  height: calc(var(--u) * 30);
  background: var(--surface);
  border: var(--outline);
  border-radius: var(--r);
  box-shadow: 0 2px 0 var(--ink);
  color: var(--cream);
}
.site .mr-screen .mr-btn svg {
  width: 55%;
  height: 55%;
}
.site .mr-screen .mr :is(.t, .sub) {
  padding-right: 0;
}
.site .mr-screen .mr .t {
  font-size: calc(var(--u) * 18);
}
.site .mr-screen .mr .sub {
  margin-top: calc(var(--u) * 2);
  font-size: calc(var(--u) * 11);
}
.site .mr-screen .mr .head {
  gap: calc(var(--u) * 4);
  padding: calc(var(--u) * 11);
}
.site .mr-screen .mr .big {
  font-size: calc(var(--u) * 15);
}
.site .mr-screen .mr .big img {
  display: inline-block;
  width: 1.15em;
  height: 1.15em;
  border: 0;
  border-radius: 0;
  box-shadow: none;
  background: none;
  margin-right: 0.3em;
  vertical-align: -0.2em;
}
.site .mr-screen .mr :is(.l, .l u, .chip small) {
  font-size: calc(var(--u) * 10);
}
.site .mr-screen .mr .l u {
  margin-right: calc(var(--u) * 4);
}
.site .mr-screen .mr .bar {
  gap: calc(var(--u) * 4);
}
.site .mr-screen .mr .track {
  height: calc(var(--u) * 9);
}
.site .mr-screen .mr :is(.track.tall, .climb .track) {
  height: calc(var(--u) * 12);
}
.site .mr-screen .mr .num {
  font-size: calc(var(--u) * 28);
}
.site .mr-screen .mr .climb {
  display: flex;
  gap: calc(var(--u) * 7);
}
.site .mr-screen .mr .chip {
  gap: calc(var(--u) * 8);
  padding: calc(var(--u) * 7) calc(var(--u) * 8);
}
.site .mr-screen .mr .chip svg {
  width: calc(var(--u) * 22);
  height: calc(var(--u) * 22);
}
.site :is(.cz.loot, .mr-shot, .clip-shot) .replay svg {
  position: absolute;
  left: 50%;
  top: var(--mark-y, 50%);
  translate: -50% -50%;
}

/* The kid's loot box rises out of an open treasure chest (Gate P comments, 2026-10-15, and 2026-10-21: it held the
   grown-up's Rewards until the reward setup took that phone): the lid and the light pouring out sit behind the phone, the chest's body over its foot. The figure
   makes no stacking context, so the two layers stack against the phone's sink (z 3) one by one. */
.site .appshot.chested {
  position: relative;
}
.site .chest {
  position: absolute;
  left: -14%;
  bottom: 12px;
  width: 140%;
  aspect-ratio: 1;
  pointer-events: none;
}
.site .chest svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}
.site .chest .chest-back {
  z-index: 2;
}
.site .chest .chest-front {
  z-index: 4;
}
/* Room for the chest beside the loot box. */
@container (min-width: 900px) {
  .site #unlock .viz.pair {
    column-gap: 72px;
  }
}
/* Below 900 the chest is centred on the phone's foot, which its lean from the top right swings about 11% of its width
   to the right; held to the left, the foot's right corner poked out past the chest (Shahrum, 2026-10-22: "the phone
   randomly slices thru it on the right side"). Below 700 the chest is barely wider than the phone, so the open lid
   behind it could only show as a sliver down one side; there the chest's body alone holds the phone. */
@container (max-width: 899px) {
  .site .chest {
    left: -1%;
    width: 124%;
  }
}
@container (max-width: 699px) {
  .site .chest {
    left: 7%;
    width: 108%;
  }
  .site .chest .chest-back {
    display: none;
  }
}
/* On a phone the loot box stands alone, so the chest widens to hold it: the open lid and its gold show down both sides,
   the phone sitting inside (Shahrum, 2026-10-22: "so it looks like a phone is actually sitting inside of an open
   chest"). Its centre sits a little left of the foot's, where the lean puts the phone at the lid's height, so the lid
   shows on both sides; the foot is still covered on both. */
@media (max-width: 599px) {
  .site .chest {
    left: -8%;
    width: 132%;
  }
  .site .chest .chest-back {
    display: block;
  }
}

/* Every App Store line (the hero's tag) wears a pixel tablet and phone, so each
   says iPhone and iPad the same way (Gate P comments, 2026-10-15):
   dark bodies, lit screens with an app grid, the phone's earpiece and home button, the tablet's even bezels, so they
   read as devices, not batteries. Not Apple's logo: Apple allows no variation of it. Apple's own badge replaces the
   lines at 1.0. One css px per pixel. */
.site .soon::before {
  flex: none;
  width: 37px;
  height: 28px;
  border: 0;
  border-radius: 0;
  background:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 37 28' shape-rendering='crispEdges'%3E%3Cpath fill='%23191121' d='M2 0h18v1H2zM1 1h9v1H1zM12 1h9v1H12zM0 2h2v1H0zM20 2h2v1H20zM0 3h2v1H0zM20 3h2v1H20zM0 4h2v1H0zM20 4h2v1H20zM0 5h2v1H0zM20 5h2v1H20zM0 6h2v1H0zM20 6h2v1H20zM27 6h8v1H27zM0 7h2v1H0zM20 7h2v1H20zM26 7h3v1H26zM33 7h3v1H33zM0 8h2v1H0zM20 8h2v1H20zM25 8h12v1H25zM0 9h2v1H0zM20 9h2v1H20zM25 9h1v1H25zM36 9h1v1H36zM0 10h2v1H0zM20 10h2v1H20zM25 10h1v1H25zM36 10h1v1H36zM0 11h2v1H0zM20 11h2v1H20zM25 11h1v1H25zM36 11h1v1H36zM0 12h2v1H0zM20 12h2v1H20zM25 12h1v1H25zM36 12h1v1H36zM0 13h2v1H0zM20 13h2v1H20zM25 13h1v1H25zM36 13h1v1H36zM0 14h2v1H0zM20 14h2v1H20zM25 14h1v1H25zM36 14h1v1H36zM0 15h2v1H0zM20 15h2v1H20zM25 15h1v1H25zM36 15h1v1H36zM0 16h2v1H0zM20 16h2v1H20zM25 16h1v1H25zM36 16h1v1H36zM0 17h2v1H0zM20 17h2v1H20zM25 17h1v1H25zM36 17h1v1H36zM0 18h2v1H0zM20 18h2v1H20zM25 18h1v1H25zM36 18h1v1H36zM0 19h2v1H0zM20 19h2v1H20zM25 19h1v1H25zM36 19h1v1H36zM0 20h2v1H0zM20 20h2v1H20zM25 20h1v1H25zM36 20h1v1H36zM0 21h2v1H0zM20 21h2v1H20zM25 21h1v1H25zM36 21h1v1H36zM0 22h2v1H0zM20 22h2v1H20zM25 22h1v1H25zM36 22h1v1H36zM0 23h2v1H0zM20 23h2v1H20zM25 23h1v1H25zM36 23h1v1H36zM0 24h2v1H0zM20 24h2v1H20zM25 24h12v1H25zM0 25h2v1H0zM20 25h2v1H20zM25 25h5v1H25zM32 25h5v1H32zM1 26h20v1H1zM26 26h4v1H26zM32 26h4v1H32zM2 27h18v1H2zM27 27h8v1H27z'/%3E%3Cpath fill='%235a5470' d='M10 1h2v1H10zM29 7h4v1H29zM30 25h2v1H30zM30 26h2v1H30z'/%3E%3Cpath fill='%232f3a66' d='M2 2h18v1H2zM2 3h18v1H2zM2 4h18v1H2zM2 5h2v1H2zM6 5h2v1H6zM10 5h2v1H10zM14 5h2v1H14zM18 5h2v1H18zM2 6h2v1H2zM6 6h2v1H6zM10 6h2v1H10zM14 6h2v1H14zM18 6h2v1H18zM2 7h18v1H2zM2 8h18v1H2zM2 9h2v1H2zM6 9h2v1H6zM10 9h2v1H10zM14 9h2v1H14zM18 9h2v1H18zM26 9h10v1H26zM2 10h2v1H2zM6 10h2v1H6zM10 10h2v1H10zM14 10h2v1H14zM18 10h2v1H18zM26 10h10v1H26zM2 11h18v1H2zM26 11h1v1H26zM29 11h1v1H29zM32 11h1v1H32zM35 11h1v1H35zM2 12h18v1H2zM26 12h1v1H26zM29 12h1v1H29zM32 12h1v1H32zM35 12h1v1H35zM2 13h2v1H2zM6 13h2v1H6zM10 13h2v1H10zM14 13h2v1H14zM18 13h2v1H18zM26 13h10v1H26zM2 14h2v1H2zM6 14h2v1H6zM10 14h2v1H10zM14 14h2v1H14zM18 14h2v1H18zM26 14h1v1H26zM29 14h1v1H29zM32 14h1v1H32zM35 14h1v1H35zM2 15h18v1H2zM26 15h1v1H26zM29 15h1v1H29zM32 15h1v1H32zM35 15h1v1H35zM2 16h18v1H2zM26 16h10v1H26zM2 17h2v1H2zM6 17h2v1H6zM10 17h2v1H10zM14 17h2v1H14zM18 17h2v1H18zM26 17h1v1H26zM29 17h1v1H29zM32 17h1v1H32zM35 17h1v1H35zM2 18h2v1H2zM6 18h2v1H6zM10 18h2v1H10zM14 18h2v1H14zM18 18h2v1H18zM26 18h1v1H26zM29 18h1v1H29zM32 18h1v1H32zM35 18h1v1H35zM2 19h18v1H2zM26 19h10v1H26zM2 20h18v1H2zM26 20h1v1H26zM29 20h1v1H29zM32 20h1v1H32zM35 20h1v1H35zM2 21h2v1H2zM6 21h2v1H6zM10 21h2v1H10zM14 21h2v1H14zM18 21h2v1H18zM26 21h1v1H26zM29 21h1v1H29zM32 21h1v1H32zM35 21h1v1H35zM2 22h2v1H2zM6 22h2v1H6zM10 22h2v1H10zM14 22h2v1H14zM18 22h2v1H18zM26 22h10v1H26zM2 23h18v1H2zM26 23h10v1H26zM2 24h18v1H2zM2 25h18v1H2z'/%3E%3Cpath fill='%23f69c4e' d='M4 5h2v1H4zM4 6h2v1H4zM12 9h2v1H12zM12 10h2v1H12zM27 11h2v1H27zM27 12h2v1H27zM4 17h2v1H4zM27 17h2v1H27zM4 18h2v1H4zM27 18h2v1H27zM12 21h2v1H12zM12 22h2v1H12z'/%3E%3Cpath fill='%23ffd24a' d='M8 5h2v1H8zM8 6h2v1H8zM16 9h2v1H16zM16 10h2v1H16zM30 11h2v1H30zM30 12h2v1H30zM8 17h2v1H8zM30 17h2v1H30zM8 18h2v1H8zM30 18h2v1H30zM16 21h2v1H16zM16 22h2v1H16z'/%3E%3Cpath fill='%232bb3a3' d='M12 5h2v1H12zM12 6h2v1H12zM33 11h2v1H33zM33 12h2v1H33zM4 13h2v1H4zM4 14h2v1H4zM12 17h2v1H12zM33 17h2v1H33zM12 18h2v1H12zM33 18h2v1H33z'/%3E%3Cpath fill='%23e86a92' d='M16 5h2v1H16zM16 6h2v1H16zM8 13h2v1H8zM8 14h2v1H8zM27 14h2v1H27zM27 15h2v1H27zM16 17h2v1H16zM16 18h2v1H16zM27 20h2v1H27zM27 21h2v1H27z'/%3E%3Cpath fill='%235b8cff' d='M4 9h2v1H4zM4 10h2v1H4zM12 13h2v1H12zM12 14h2v1H12zM30 14h2v1H30zM30 15h2v1H30zM30 20h2v1H30zM4 21h2v1H4zM30 21h2v1H30zM4 22h2v1H4z'/%3E%3Cpath fill='%23f8efa8' d='M8 9h2v1H8zM8 10h2v1H8zM16 13h2v1H16zM16 14h2v1H16zM33 14h2v1H33zM33 15h2v1H33zM33 20h2v1H33zM8 21h2v1H8zM33 21h2v1H33zM8 22h2v1H8z'/%3E%3C/svg%3E")
    0 0 / 37px 28px no-repeat;
}
/* What "Notify me" is for, as a tag over the hero's form (Gate P comments, 2026-10-22: the header's "Coming soon" was
   easy to miss, then repeated it, so it went): the form's surface and ink edge, so the two read as one, and the pixel
   phone and tablet every App Store line wears. */
.site .soon.launch-tag {
  min-height: 0;
  margin: 0 0 14px;
  padding: 6px 12px 6px 8px;
  border: var(--outline);
  border-radius: var(--r);
  background: var(--surface);
  box-shadow: var(--edge);
  font: 700 15px / 1.2 var(--text);
}

/* The headline's turning word (kid's, tween's, teen's) keeps a line of its own, as "family's" did at every width, so a
   shorter or longer word never reflows the headline. The mosaic that swaps it draws on a canvas over it (motion.js). */
.site .hero .swap {
  display: block;
  position: relative;
}
.site .hero .swap canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

/* The #unlock pair mirrors: the loot box leans left, the reward setup leans right, as its tag already does, so
   the two phones never share one angle (Gate P comment, 2026-10-15). */
.site #unlock .appshot.rw .gdev {
  rotate: 3deg;
  transform-origin: top left;
}

/* From a tablet up the Mission report shows on the kid's iPad (Gate P comment, 2026-10-15: not always a kid's phone).
   The same live report, laid out as the app's iPad screen (full width), in an iPad's frame and status bar; a phone keeps
   the phone, where the iPad's type would shrink past reading. Only the frame changes, so there is one report and one
   animation. The type is set a little larger than the iPad's true scale, as the phone's is, so it reads on the page.
   Inside the screen a container query would ask the screen itself, so the frame hands its numbers down as properties. */
/* The status bar is set in the screen's own units (the screen is a size container, and --w carries its cqi down
   unresolved): the time 6.23% of the screen wide, as on every other phone, and the battery's right edge 8.4% from the
   screen's, the ::after placed from the time's left edge (Gate P comment, 2026-10-15: the iPad's battery sat 26% in). */
.site .mr-shot .sb {
  top: var(--sb-top, 2.1%);
  left: calc(var(--sb-l, 0.09) * 100%);
  font-size: calc(var(--sb-f, 0.0623) * 100cqi);
}
.site .mr-shot .sb::after {
  left: calc((1 - var(--sb-l, 0.09) - var(--sb-r, 0.084)) * 100cqi - 1.9em);
}
@container (min-width: 700px) {
  .site .mr-shot,
  .site .mr-shot .gdev {
    --w: min(80cqi, 560px);
    width: var(--w);
  }
  .site .mr-shot .gdev {
    --cols: 600;
    --sb-top: 1.2%;
    --sb-l: 0.035;
    --sb-f: 0.0275;
    --sb-r: 0.034;
    padding: calc(var(--w) * 0.028);
    border-radius: calc(var(--w) * 0.06);
  }
  .site .mr-shot .dev-screen {
    border-radius: calc(var(--w) * 0.035);
  }
  /* Cut just under the report's last line, so the iPad sinks behind the next track like the phones do, instead of
     trailing its empty lower screen far past the copy (Gate P comment, 2026-10-15). */
  .site .mr-shot .sink {
    aspect-ratio: auto;
    height: calc(var(--w) * 1.16);
    min-height: 0;
  }
  /* Its replay mark centres on the part of the screen left in view, not the whole screen, whose foot sinks out of
     sight (Gate P comment, 2026-10-15): 628 of the screen's 794 px show, so the middle of what shows is 39.5% down.
     Set on the frame, since a query inside the screen asks the screen. */
  .site .mr-shot .gdev {
    --mark-y: 39.5%;
  }
  .site .mr-screen {
    aspect-ratio: 1668 / 2420;
  }
}

/* A quiet Sidequest Plus nod under the unlock and achievements copy (Gate P comments, 2026-10-15): the table's gold Plus mark and
   one line; a tap glides down to the plans heading, the table under it. */
.site .plus-nod {
  display: flex;
  width: fit-content;
  margin-top: 10px;
  align-items: center;
  gap: 10px;
  min-height: 44px;
  font-size: 15px;
  color: var(--cream);
  text-decoration: none;
}
.site .plus-nod .bonus-mark {
  flex: none;
  width: 36px;
  height: 16px;
  background: var(--gold);
  -webkit-mask: url("/site/plus-mark.svg") center / contain no-repeat;
  mask: url("/site/plus-mark.svg") center / contain no-repeat;
}
.site .plus-nod u {
  text-decoration: underline 2px var(--gold);
  text-underline-offset: 4px;
}
.site .plus-nod:hover u {
  text-decoration-thickness: 3px;
}
.site .plus-nod:focus-visible {
  outline: 3px solid var(--gold);
  outline-offset: 4px;
  border-radius: 4px;
}
.site #plans-h {
  scroll-margin-top: 24px;
}
@media (prefers-reduced-motion: no-preference) {
  html:has(> body.site) {
    scroll-behavior: smooth;
  }
}

/* Instagram and TikTok in the footer (Shahrum, 2026-10-16): each glyph is the platform's own mark, unaltered, in one
   near-black colour (ink), which both brands' rules allow; the site's look comes from the chip around it, the same
   orange tag with an ink edge and drop as the device tags. Like the Apple lines, the marks themselves are not redrawn
   as pixel art: neither brand allows a modified logo. The chip shows at 34 px ("a tiny bit tinier", Gate P comment)
   inside a 44 px link, so the touch target stays at the floor; the -5 px edges line the chips up with the text. They head
   the right column, above the maker line (Gate P comment). */
.site .foot-made .social {
  display: flex;
  gap: 4px;
  margin: 0 -5px 2px;
  padding: 0;
  list-style: none;
}
.site .foot-made .social a {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  color: var(--ink);
  border-radius: 8px;
}
.site .foot-made .social .sq-chip {
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  border: 2px solid var(--ink);
  border-radius: 5px;
  box-shadow: 0 3px 0 var(--ink);
  background: var(--orange);
}
.site .foot-made .social a:focus-visible {
  outline: 2px solid var(--cream);
  outline-offset: 0;
}
/* The lift and press are motion, so they are opt-in like the rest of this file's motion. */
@media (prefers-reduced-motion: no-preference) {
  .site .foot-made .social .sq-chip {
    transition:
      transform 0.12s ease,
      box-shadow 0.12s ease;
  }
  .site .foot-made .social a:hover .sq-chip {
    transform: translateY(-2px);
    box-shadow: 0 5px 0 var(--ink);
  }
  .site .foot-made .social a:active .sq-chip {
    transform: translateY(2px);
    box-shadow: 0 1px 0 var(--ink);
  }
}

/* ---------- Review 2026-10-18 ---------- */
/* Whose screen it is: one badge per screen, naming the person, not the device: orange Grown-up, blue Kid (review
   2026-10-18; pixel icons tried and dropped as too vague at this size). */
.site .dev-tag {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.site .ladder .devlink .dev-tag {
  position: relative;
  z-index: 3;
  rotate: -2deg;
}
.site :is(#example, #achievements, #report) .appshot > .dev-tag {
  position: relative;
  z-index: 4;
  margin-left: 14px;
  rotate: 3deg;
}
.site #report .appshot.mr-shot {
  display: grid;
  gap: 10px;
}
/* The loot box: the whole screen is its tap-to-open button. */
.site .tap-open {
  cursor: pointer;
}
.site .tap-open:focus-visible {
  outline: 3px solid var(--gold);
  outline-offset: 3px;
}
/* Plans: the table alone, one line per feature; a feature with a story opens a row under it. */
.site .plans .compare {
  max-width: 920px;
}
/* The table sits centred and wide (review 2026-10-18), its fine print and the level-up centred under it. */
.site .plans-grid {
  justify-items: center;
}
/* One column at every width now the perk cards are gone: the table, its fine print, then the level-up. */
@media (min-width: 1200px) {
  .site .plans-grid {
    grid-template-columns: minmax(0, 1fr);
  }
  .site .plans-grid > :is(.compare, .fine, .levelup) {
    grid-column: 1;
    grid-row: auto;
  }
}
.site .plans-grid > .fine {
  max-width: 920px;
  margin: 0;
  text-align: center;
}
.site .compare tbody th {
  padding-left: 14px;
  white-space: nowrap;
}
.site .compare tbody tr:not(.detail) > * {
  height: 52px;
  padding-block: 6px;
}
.site .compare .row-x {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  width: calc(100% + 22px);
  min-height: 44px;
  margin: -6px -8px -6px -14px;
  padding: 0 8px 0 14px;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.site .compare .row-x .chev {
  flex: none;
  color: var(--gold);
  transition: rotate 0.15s;
}
.site .compare tr.open .row-x .chev {
  rotate: 180deg;
}
.site .compare .row-x:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: -3px;
}
@media (hover: hover) {
  .site .compare .row-x:hover span {
    text-decoration: underline;
    text-underline-offset: 3px;
  }
}
.site .compare tr.detail > td {
  padding: 12px 14px 16px;
  text-align: left;
  font-weight: 400;
  color: var(--body);
  background-image: none;
  border-left: 2px solid var(--ink);
  border-right: 2px solid var(--ink);
}
.site .compare .detail-in {
  display: grid;
  gap: 12px;
  justify-items: start;
}
.site .compare .detail-in p {
  margin: 0;
  max-width: 52ch;
  font-size: 14px;
  line-height: 1.4;
}
.site .compare .detail-in .box {
  width: 100%;
  max-width: 340px;
  container-type: inline-size;
  position: relative;
}
/* The frame's bottom edge sits on the last row you can see, open or not. */
.site .compare tbody tr:has(+ tr.detail[hidden]:last-child) > * {
  border-bottom: 2px solid var(--ink);
  box-shadow: 0 3px 0 var(--ink);
}
.site .compare tbody tr.bonus:has(+ tr.detail[hidden]:last-child) [scope] {
  border-bottom-left-radius: var(--r);
  box-shadow:
    inset 4px 0 0 var(--gold),
    0 3px 0 var(--ink);
}
.site .compare tbody tr:not(:last-child):has(+ tr.detail:not([hidden])) > * {
  box-shadow: none;
}
/* The level-up is the section's one ambient motion, smaller and centred under the price. */
.site .plans-grid > .levelup {
  width: min(100%, 420px);
  justify-self: center;
}
@container (max-width: 420px) {
  .site .compare {
    font-size: 14px;
  }
  .site .compare thead td {
    width: 50%;
  }
  .site .compare thead th {
    width: 25%;
  }
  .site .compare tbody th {
    white-space: normal;
  }
}
/* Every animation's Pause/Play is one control that looks the same everywhere (review 2026-10-18: the bare glyphs were
   hard to find on busy screens): a cream chip with the page's ink edge and drop, the glyph and the word, so it reads
   as the site's button on any screen behind it. It stays where each animation put it; a 44px ring keeps the target. */
.site .loop-pause {
  width: auto;
  height: 30px;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 0 10px 0 9px;
  border: 2px solid var(--ink);
  border-radius: 6px;
  background: var(--cream);
  color: var(--ink);
  box-shadow: 0 3px 0 var(--ink);
  opacity: 1;
  font: 400 11px / 1 var(--display);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.site .loop-pause::before {
  content: "";
  position: absolute;
  inset: -7px -2px;
}
.site .loop-pause::after {
  content: "Pause";
}
.site .loop-pause[aria-pressed="true"]::after {
  content: "Play";
}
.site .loop-pause svg {
  width: 10px;
  height: 10px;
}
@media (hover: hover) {
  .site .loop-pause:hover {
    background: var(--gold);
  }
}
.site .loop-pause:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 2px;
}
/* The hero's devices carry no badges (review 2026-10-18: too many badges clustered at the top, and no key up there
   either); How it works, right under it, is where Grown-up and Kid first appear, each beside the step it names. */
/* Their badges' room (a 26px tag and the 8px gap) stays, so the iPad's fade still meets the band's bottom edge. */
.site :is(.duo-pad, .duo-phone) {
  padding-top: 34px;
}
/* The loot box's tap hint: a cream ring pulses out from the closed box, the app's own card, and rests while it opens. */
.site .tap-hint {
  position: absolute;
  z-index: 2;
  left: 50%;
  top: 50.4%;
  width: 46%;
  aspect-ratio: 1;
  translate: -50% -50%;
  border: 3px solid var(--cream);
  border-radius: 8px;
  box-shadow: 0 0 0 2px var(--ink);
  opacity: 0;
  pointer-events: none;
}
.site .tap-open:not(.opening) .tap-hint {
  animation: tap-hint 2.2s ease-out infinite;
}
@keyframes tap-hint {
  0% {
    opacity: 0;
    scale: 0.94;
  }
  18% {
    opacity: 0.95;
  }
  70%,
  100% {
    opacity: 0;
    scale: 1.2;
  }
}
/* On a phone the Plus mark in a row is a size smaller, so a wrapped label stays two lines. */
@container (max-width: 420px) {
  .site .compare .bonus-mark {
    width: 28px;
    height: 12px;
    margin-left: 5px;
  }
}
/* A quieter status bar (review 2026-10-18: the clock and battery sat too large on every screen): the time at a real
   iPhone's share of the width (~4.5%, was 5.8%), the iPad's and the report's in step, and a slimmer battery whose right
   edge stays where it was. */
.site .sb {
  font-size: calc(var(--w) * 0.045);
  top: 2.4%;
}
.site .sb::after {
  left: calc(var(--w) * 0.69);
  width: 1.7em;
  height: 0.8em;
  top: 0.1em;
  border-width: 0.08em;
}
.site .pad .sb {
  top: 1.3%;
  font-size: calc(var(--w) * 0.021);
}
.site .pad .sb::after {
  left: calc(var(--w) * 0.84);
}
.site .mr-shot .sb {
  font-size: calc(var(--sb-f, 0.0623) * 0.77 * 100cqi);
}
.site .mr-shot .sb::after {
  left: calc((1 - var(--sb-l, 0.09) - var(--sb-r, 0.084)) * 100cqi - 1.7em);
}
/* How it works keeps one paragraph a step; a step's screenshot, tapped, opens beside the list of what it can do
   (review 2026-10-18: the lists under each step were too much to read). */
.site .lightbox[open]:has(.notes:not([hidden])) {
  display: flex;
  align-items: stretch;
}
.site .lightbox .notes {
  width: min(340px, 40vw);
  padding: 28px 28px 28px 24px;
  overflow-y: auto;
  color: var(--body-80);
  font-size: 16px;
  line-height: 1.4;
}
.site .lightbox .notes .notes-h {
  margin: 0 0 14px;
  color: var(--cream);
  font: 400 20px / 1.1 var(--display);
  text-transform: uppercase;
  text-wrap: balance;
}
.site .lightbox .notes ul {
  display: grid;
  gap: 10px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.site .lightbox .notes li {
  position: relative;
  padding-left: 18px;
}
.site .lightbox .notes li::before {
  content: "";
  position: absolute;
  left: 2px;
  top: 0.5em;
  width: 7px;
  height: 7px;
  background: var(--gold);
}
/* A flow's screenshot steps through its major screens under the image (site.js, data-steps; Shahrum, 2026-10-22).
   The frame keeps the widest step's shape (--ar), so the arrows hold still; on a phone the bar stays in view while the
   list above it scrolls. */
/* The bar takes the image's width, never under 340px, so a caption wraps in two lines instead of widening the box. */
.site .lightbox.stepped .shot {
  width: min-content;
  min-width: min(92vw, 340px);
}
.site .lightbox.stepped img {
  margin: 0 auto;
  max-height: calc(100vh - 196px);
  height: min(calc(100vh - 196px), calc(92vw / var(--ar)));
  aspect-ratio: var(--ar);
  object-fit: contain;
  touch-action: pan-y;
  user-select: none;
  -webkit-user-select: none;
}
.site .lightbox .steps {
  position: sticky;
  bottom: 0;
  display: grid;
  min-height: 69px; /* a two-line caption's height, so the bar holds still from step to step */
  grid-template-columns: 44px 1fr 44px;
  align-items: center;
  gap: 8px;
  padding: 8px;
  background: var(--ink);
}
.site .lightbox .steps[hidden] {
  display: none;
}
.site .lightbox .steps-go {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  padding: 0;
  border: var(--outline);
  border-radius: 8px;
  background: var(--surface);
  box-shadow: var(--edge);
  color: var(--cream);
  cursor: pointer;
}
.site .lightbox .steps-go[aria-disabled="true"] {
  opacity: 0.35;
  cursor: default;
}
.site .lightbox .steps-go:active:not([aria-disabled="true"]) {
  translate: 0 2px;
  box-shadow: 0 1px 0 var(--ink);
}
.site .lightbox .steps-go:focus-visible {
  outline: 3px solid var(--gold);
  outline-offset: 2px;
}
.site .lightbox .steps-say {
  display: grid;
  gap: 3px;
  margin: 0;
  text-align: center;
}
.site .lightbox .steps-n {
  color: var(--gold);
  font: 400 12px / 1 var(--display);
  text-transform: uppercase;
}
.site .lightbox .steps-t {
  color: var(--cream);
  font-size: 15px;
  line-height: 1.25;
  text-wrap: balance;
}
@media (max-width: 699px) {
  .site .lightbox[open]:has(.notes:not([hidden])) {
    flex-direction: column;
    overflow-y: auto;
  }
  .site .lightbox:has(.notes:not([hidden])) img {
    flex: none;
    max-height: 54vh;
    margin: 0 auto;
  }
  .site .lightbox .notes {
    flex: none;
    order: -1;
    width: auto;
    padding: 18px 64px 14px 20px;
  }
  .site .lightbox:has(.notes:not([hidden])) .shot {
    flex: none;
  }
  /* Stepping, the screen leads and the list follows under it, its heading in view. */
  .site .lightbox.stepped:has(.notes:not([hidden])) .shot {
    width: auto;
  }
  .site .lightbox.stepped .notes {
    order: 1;
  }
}
/* The hero's two reward pills sit a little further apart, so they never touch (review 2026-10-18). */
@media (min-width: 600px) {
  .site .bp-node.a .pill {
    left: -7cqw;
  }
  .site .bp-node.b .pill {
    right: -7cqw;
  }
}
/* The hero ties the bar to the chores (review 2026-10-18): the approved chore's +5 XP lifts off its row on the kid's
   iPad and flies into the bar, landing as it fills to Movie night. motion.js sets its two ends (--x0/--y0: the row's
   +5; --x1/--y1: the reward's mark), in the stage's own pixels. */
.site .xp-fly {
  position: absolute;
  z-index: 4;
  left: 0;
  top: 0;
  margin: -12px 0 0 -28px;
  padding: 4px 7px 5px;
  border: 2px solid var(--ink);
  border-radius: 5px;
  box-shadow: 0 2px 0 var(--ink);
  background: var(--gold);
  color: var(--ink);
  font: 400 13px / 1 var(--display);
  letter-spacing: 0.03em;
  white-space: nowrap;
  pointer-events: none;
  opacity: 0;
  translate: var(--x0, 0) var(--y0, 0);
}
/* The hero reads left to right as the day does (review 2026-10-18): the kid's iPad on the left, where the loop starts with
   their check-off, and your phone on the right, in front, where the approvals happen. */
.site .duo-pad {
  right: auto;
  left: 0;
  rotate: 3deg;
}
.site .duo-phone {
  left: auto;
  right: 0;
  rotate: -3deg;
}
@media (max-width: 599px) {
  .site .duo-pad {
    right: auto;
    left: 1cqw;
  }
}
/* The core loop (review 2026-10-18, two rounds), on the app's own hero captures (#1788, #1789), 26.1 s.
   Each step's line shows in the strip under the bar, blue while Sam acts and orange while you do, and the device
   being used comes to the front, lit in the same colour. Generated from one clock (scripts/site-hero/hero-timeline.py):
         0 s  kid    Sam checks off Unload the dishwasher
       3.6 s  grown  It pops up on your phone to approve
       7.7 s  kid    Approved! Sam earns +5 XP
      10.1 s  kid    Movie night unlocked!
      12.2 s  kid    Next, Sam checks off Clean your room
      15.8 s  grown  You approve that one too
      19.7 s  kid    Approved! Sam earns +10 XP
      22.1 s  kid    Ice cream run unlocked!
   then everything settles back to the start (24.6 s). Check-offs carry the app's own celebration
   (ChoreDoneMotion: the mark pops in held steps, eight sparks, and "+N XP" rises off the row), drawn larger and
   slower than the app so it reads at this size (Shahrum, 2026-10-18: "it's okay if you're faking it if it looks
   better"). The play bar under the devices (motion.js) pauses, scrubs and shows the loop's progress. */
.site .arrive {
  position: absolute;
  z-index: 2;
  left: 3.5%;
  right: 4%;
  top: 16.6%;
  height: 17.8%;
  border: 3px solid var(--cream);
  border-radius: 8px;
  box-shadow:
    0 0 0 2px var(--ink),
    0 0 18px rgb(255 244 214 / 0.5);
  opacity: 0;
  pointer-events: none;
}
.site .tap-ring.kid {
  left: 12%;
  top: 56.6%;
}
.site .tap-ring.kid.k2 {
  top: 49.5%;
}
.site .duo-phone .tap-ring {
  left: 72.7%;
  top: 30.9%;
  width: 38%;
  aspect-ratio: 3.4;
}
.site .lift {
  top: 54.2%;
  height: 5.6%;
  opacity: 0;
}
.site .lift.l2 {
  top: 54.8%;
  height: 5%;
}
/* The bar runs from 5 XP short of Movie night to Ice cream run, 10 XP past it; at rest it holds Movie night reached. */
.site .bp {
  z-index: 3;
}
.site .bp-node.b {
  left: 82%;
}
.site .bp-fill {
  width: calc(82% - 3px);
  scale: 0.268 1;
}
.site .bp-node.b .bp-lock {
  opacity: 1;
}
/* A reward not yet reached is dimmed: grey text and a black-and-white icon. */
.site .bp-node.b .pill {
  color: #8b90a8;
}
.site .bp-node.b .pill img {
  filter: grayscale(1) brightness(0.8);
}
.site .bp-node.b .bp-present::after,
.site .bp-node.b .bp-yay {
  opacity: 0;
}
/* The kid's check-off, drawn over the capture's checked mark: the pop, the sparks and the rising "+N XP". */
.site .duo-pad {
  --rise: 40px;
  --k: 1px;
}
.site .kpop,
.site .kspk,
.site .xp-rise {
  position: absolute;
  z-index: 3;
  pointer-events: none;
}
.site .kpop {
  left: 12.1%;
  top: 59.1%;
  width: 4.6%;
  aspect-ratio: 1;
  translate: -50% -50%;
  border: 3px solid var(--gold);
  border-radius: 5px;
  box-shadow:
    0 0 0 2px var(--ink),
    0 0 14px rgb(255 210 74 / 0.7);
  opacity: 0;
}
.site .kpop.k2,
.site .kspk.k2 {
  top: 59.7%;
}
.site .kspk {
  left: 12.1%;
  top: 59.1%;
}
.site .kspk i {
  position: absolute;
  width: 6px;
  height: 6px;
  margin: -3px 0 0 -3px;
  box-shadow: 0 0 0 1px var(--ink);
  opacity: 0;
}
.site .xp-rise {
  left: 50%;
  top: 58.6%;
  display: flex;
  align-items: center;
  gap: 5px;
  padding: 4px 8px 4px 5px;
  translate: -50% -50%;
  border: 2px solid var(--ink);
  border-radius: 6px;
  box-shadow:
    0 2px 0 var(--ink),
    inset 0 0 0 1px rgb(70 209 96 / 0.5);
  background: #2b3150;
  color: #46d160;
  font: 400 13px / 1 var(--display);
  letter-spacing: 0.03em;
  text-shadow: 0 2px 0 var(--ink);
  white-space: nowrap;
  opacity: 0;
}
.site .xp-rise.k2 {
  top: 59.3%;
}
.site .xp-rise i {
  width: 15px;
  height: 15px;
  border-radius: 50%;
  background:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M4 8.5l2.6 2.6L12 5.5' fill='none' stroke='%23191121' stroke-width='2.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E")
    center / 80% no-repeat,
    #46d160;
}
/* Whoever is acting is lit in their colour: a ring round the device, edged in ink so the kid's blue still reads on the
   blue band. The stage is a little taller and the devices sit a little lower, to make room for the strip above them
   and the play bar below the chores. */
.site .duo-stage {
  aspect-ratio: 1 / 1.16;
}
.site .duo-pad,
.site .duo-phone {
  translate: 0 7cqw;
}
.site .duo-pad {
  --lit: #6aa3ff;
}
.site .duo-phone .gdev {
  --lit: var(--orange);
}
/* The iPad's ring sits on its wrapper's grid cell (the iPad's own box, inside the wrapper's padding), since the iPad
   itself is masked by its fade into the band; the ring fades with it. */
.site .duo-pad::after,
.site .duo-phone .gdev::after {
  content: "";
  position: absolute;
  inset: -8px;
  border: 4px solid var(--lit);
  border-radius: calc(34cqw * 0.155 + 8px);
  box-shadow:
    0 0 0 2px var(--ink),
    inset 0 0 0 2px var(--ink),
    0 0 22px var(--lit);
  opacity: 0;
  pointer-events: none;
}
.site .duo-pad::after {
  grid-area: 1 / 1;
  border-radius: calc(4.3cqw + 8px);
  mask-image: linear-gradient(180deg, #000 0 60%, transparent 71%);
}
@media (max-width: 599px) {
  .site .duo-pad::after {
    mask-image: linear-gradient(180deg, #000 0 70%, transparent 81%);
  }
}
/* The strip under the bar says what is happening, blue while Sam acts and orange while you do (the frames' tags),
   as large as the reward pills above it. */
.site .say {
  position: absolute;
  z-index: 3;
  left: 0;
  right: 0;
  top: 17.5cqw;
  pointer-events: none;
}
.site .say span {
  position: absolute;
  left: 50%;
  top: 0;
  width: max-content;
  max-width: 92cqw;
  padding: 6px 12px 5px;
  translate: -50% 0;
  border: 2px solid var(--ink);
  border-radius: 5px;
  box-shadow: 0 3px 0 var(--ink);
  background: #6aa3ff;
  color: var(--ink);
  font: 400 clamp(13px, 3.4cqw, 17px) / 1.15 var(--display);
  letter-spacing: 0.03em;
  text-align: center;
  text-wrap: balance;
  opacity: 0;
}
.site .say .grown {
  background: var(--orange);
}
/* The play bar: the loop plays on its own; pause it, or drag along it to scrub back and forth (motion.js). Each
   stretch of the track is coloured by who is acting then. */
.site .scrub {
  position: absolute;
  z-index: 5;
  left: 50%;
  bottom: 14px;
  display: flex;
  align-items: center;
  gap: 10px;
  width: min(88%, 440px);
  padding: 4px 14px 4px 4px;
  translate: -50% 0;
  border: 2px solid var(--ink);
  border-radius: 10px;
  background: rgb(25 17 33 / 0.9);
  box-shadow: 0 3px 0 rgb(0 0 0 / 0.35);
}
.site .scrub[hidden] {
  display: none;
}
.site .scrub-play {
  flex: none;
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  padding: 0;
  border: 2px solid var(--ink);
  border-radius: 7px;
  box-shadow: 0 2px 0 var(--ink);
  background: var(--cream);
  color: var(--ink);
  cursor: pointer;
}
.site .scrub-track {
  position: relative;
  flex: 1;
  height: 40px;
}
.site .scrub-bg,
.site .scrub-fill {
  position: absolute;
  left: 0;
  right: 0;
  top: 15px;
  height: 10px;
  border-radius: 3px;
  pointer-events: none;
}
.site .scrub-bg {
  opacity: 0.32;
  box-shadow: inset 0 0 0 1px rgb(255 255 255 / 0.15);
}
.site .scrub-fill {
  clip-path: inset(0 calc((1 - var(--p, 0)) * 100%) 0 0);
}
.site .scrub input {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  background: none;
  cursor: pointer;
  appearance: none;
}
.site .scrub input::-webkit-slider-runnable-track {
  height: 40px;
  background: none;
}
.site .scrub input::-moz-range-track {
  height: 40px;
  background: none;
}
.site .scrub input::-webkit-slider-thumb {
  width: 14px;
  height: 24px;
  margin-top: 8px;
  border: 2px solid var(--ink);
  border-radius: 3px;
  box-shadow: 0 2px 0 var(--ink);
  background: var(--cream);
  appearance: none;
}
.site .scrub input::-moz-range-thumb {
  width: 10px;
  height: 20px;
  border: 2px solid var(--ink);
  border-radius: 3px;
  box-shadow: 0 2px 0 var(--ink);
  background: var(--cream);
}
.site .scrub :focus-visible {
  outline: 3px solid var(--cream);
  outline-offset: 2px;
}
@media (max-width: 599px) {
  .site .duo-pad {
    --rise: 24px;
    --k: 0.6px;
  }
  .site .xp-rise {
    gap: 3px;
    padding: 2px 5px 2px 3px;
    font-size: 10px;
  }
  .site .xp-rise i {
    width: 11px;
    height: 11px;
  }
  .site .kspk i {
    width: 4px;
    height: 4px;
    margin: -2px 0 0 -2px;
  }
  .site .say span {
    max-width: 96cqw;
    padding: 5px 8px 4px;
    font-size: 12px;
  }
  .site .scrub {
    bottom: 8px;
    gap: 8px;
    width: 92%;
    padding: 3px 10px 3px 3px;
  }
  .site .scrub-play {
    width: 34px;
    height: 34px;
  }
  .site .scrub-track {
    height: 34px;
  }
  .site .scrub-bg,
  .site .scrub-fill {
    top: 12px;
  }
}
.site .scrub-bg,
.site .scrub-fill {
  background: linear-gradient(
    90deg,
    #6aa3ff 0% 13.79%,
    var(--orange) 13.79% 29.5%,
    #6aa3ff 29.5% 60.54%,
    var(--orange) 60.54% 75.48%,
    #6aa3ff 75.48% 100%
  );
}
.site .duo.run .tap-ring.kid {
  animation: hl-tap-kid 26.1s ease-out infinite;
}
.site .duo.run .tap-ring.kid.k2 {
  animation: hl-tap-kid2 26.1s ease-out infinite;
}
.site .duo.run .duo-phone .tap-ring {
  animation: hl-tap-approve 26.1s ease-out infinite;
}
.site .duo.run .duo-phone .tap-ring.t2 {
  animation: hl-tap-approve2 26.1s ease-out infinite;
}
.site .duo.run .kpop {
  animation: hl-pop 26.1s ease-out infinite;
}
.site .duo.run .kpop.k2 {
  animation: hl-pop2 26.1s ease-out infinite;
}
.site .duo.run .kspk i {
  animation: hl-spark 26.1s ease-out infinite;
}
.site .duo.run .kspk.k2 i {
  animation: hl-spark2 26.1s ease-out infinite;
}
.site .duo.run .xp-rise {
  animation: hl-rise 26.1s ease-out infinite;
}
.site .duo.run .xp-rise.k2 {
  animation: hl-rise2 26.1s ease-out infinite;
}
.site .duo.run .duo-pad .nx {
  animation: hl-pad-checked 26.1s ease-out infinite;
}
.site .duo.run .duo-pad .nx.n6 {
  animation: hl-pad-approved 26.1s ease-out infinite;
}
.site .duo.run .duo-pad .nx.n7 {
  animation: hl-pad-next 26.1s ease-out infinite;
}
.site .duo.run .duo-pad .nx.n11 {
  animation: hl-pad-approved2 26.1s ease-out infinite;
}
.site .duo.run .duo-phone .nx.n4 {
  animation: hl-phone-arrived 26.1s ease-out infinite;
}
.site .duo.run .duo-phone .nx.n5 {
  animation: hl-phone-approved 26.1s ease-out infinite;
}
.site .duo.run .duo-phone .nx.n9 {
  animation: hl-phone-arrived2 26.1s ease-out infinite;
}
.site .duo.run .duo-phone .nx.n10 {
  animation: hl-phone-approved2 26.1s ease-out infinite;
}
.site .duo.run .arrive {
  animation: hl-arrive 26.1s ease-out infinite;
}
.site .duo.run .lift {
  animation: hl-lift 26.1s ease-out infinite;
}
.site .duo.run .lift.l2 {
  animation: hl-lift2 26.1s ease-out infinite;
}
.site .duo.run .xp-fly {
  animation: hl-fly 26.1s ease-out infinite;
  animation-timing-function: cubic-bezier(0.4, 0, 0.3, 1);
}
.site .duo.run .xp-fly.f2 {
  animation: hl-fly2 26.1s ease-out infinite;
  animation-timing-function: cubic-bezier(0.4, 0, 0.3, 1);
}
.site .duo.run .bp-fill {
  animation: hl-fill 26.1s ease-out infinite;
  animation-timing-function: cubic-bezier(0.3, 0.7, 0.2, 1);
}
.site .duo.run .duo-pad {
  animation: hl-pad-front 26.1s ease-out infinite;
  animation-timing-function: ease-in-out;
}
.site .duo.run .duo-phone {
  animation: hl-phone-front 26.1s ease-out infinite;
  animation-timing-function: ease-in-out;
}
.site .duo.run .duo-pad .gdev {
  animation: hl-pad-lit 26.1s ease-out infinite;
  animation-timing-function: ease-in-out;
}
.site .duo.run .duo-phone .gdev {
  animation: hl-phone-lit 26.1s ease-out infinite;
  animation-timing-function: ease-in-out;
}
.site .duo.run .duo-pad::after {
  animation: hl-pad-ring 26.1s ease-out infinite;
  animation-timing-function: ease-in-out;
}
.site .duo.run .duo-phone .gdev::after {
  animation: hl-phone-ring 26.1s ease-out infinite;
  animation-timing-function: ease-in-out;
}
.site .duo.run .bp-node.a .bp-lock {
  animation: hl-a-lock 26.1s ease-out infinite;
  animation-timing-function: linear;
}
.site .duo.run .bp-node.a .bp-gift {
  animation: hl-a-gift 26.1s ease-out infinite;
}
.site .duo.run .bp-node.a .pill {
  animation: hl-a-pill 26.1s ease-out infinite;
}
.site .duo.run .bp-node.a .pill img {
  animation: hl-a-icon 26.1s ease-out infinite;
  animation-timing-function: linear;
}
.site .duo.run .bp-node.a .bp-present {
  animation: hl-a-present-pop 26.1s ease-out infinite;
}
.site .duo.run .bp-node.a .bp-present::after {
  animation: hl-a-present 26.1s ease-out infinite;
  animation-timing-function: linear;
}
.site .duo.run .bp-node.a .bp-to {
  animation: hl-a-to 26.1s ease-out infinite;
  animation-timing-function: linear;
}
.site .duo.run .bp-node.a .bp-yay {
  animation: hl-a-yay 26.1s ease-out infinite;
}
.site .duo.run .bp-node.a .bp-bits i {
  animation: hl-a-bit 26.1s ease-out infinite;
}
.site .duo.run .bp-node.b .bp-lock {
  animation: hl-b-lock 26.1s ease-out infinite;
  animation-timing-function: linear;
}
.site .duo.run .bp-node.b .bp-gift {
  animation: hl-b-gift 26.1s ease-out infinite;
}
.site .duo.run .bp-node.b .pill {
  animation: hl-b-pill 26.1s ease-out infinite;
}
.site .duo.run .bp-node.b .pill img {
  animation: hl-b-icon 26.1s ease-out infinite;
  animation-timing-function: linear;
}
.site .duo.run .bp-node.b .bp-present {
  animation: hl-b-present-pop 26.1s ease-out infinite;
}
.site .duo.run .bp-node.b .bp-present::after {
  animation: hl-b-present 26.1s ease-out infinite;
  animation-timing-function: linear;
}
.site .duo.run .bp-node.b .bp-to {
  animation: hl-b-to 26.1s ease-out infinite;
  animation-timing-function: linear;
}
.site .duo.run .bp-node.b .bp-yay {
  animation: hl-b-yay 26.1s ease-out infinite;
}
.site .duo.run .bp-node.b .bp-bits i {
  animation: hl-b-bit 26.1s ease-out infinite;
}
.site .duo.run .say .s1 {
  animation: hl-say1 26.1s ease-out infinite;
}
.site .duo.run .say .s2 {
  animation: hl-say2 26.1s ease-out infinite;
}
.site .duo.run .say .s3 {
  animation: hl-say3 26.1s ease-out infinite;
}
.site .duo.run .say .s4 {
  animation: hl-say4 26.1s ease-out infinite;
}
.site .duo.run .say .s5 {
  animation: hl-say5 26.1s ease-out infinite;
}
.site .duo.run .say .s6 {
  animation: hl-say6 26.1s ease-out infinite;
}
.site .duo.run .say .s7 {
  animation: hl-say7 26.1s ease-out infinite;
}
.site .duo.run .say .s8 {
  animation: hl-say8 26.1s ease-out infinite;
}
@keyframes hl-tap-kid {
  0% {
    opacity: 0;
    scale: 0.6;
  }
  5.17% {
    opacity: 0;
    scale: 0.6;
  }
  6.13% {
    opacity: 1;
    scale: 1;
  }
  8.05% {
    opacity: 0;
    scale: 1.35;
  }
  100% {
    opacity: 0;
    scale: 1.35;
  }
}
@keyframes hl-tap-kid2 {
  0% {
    opacity: 0;
    scale: 0.6;
  }
  51.92% {
    opacity: 0;
    scale: 0.6;
  }
  52.87% {
    opacity: 1;
    scale: 1;
  }
  54.79% {
    opacity: 0;
    scale: 1.35;
  }
  100% {
    opacity: 0;
    scale: 1.35;
  }
}
@keyframes hl-tap-approve {
  0% {
    opacity: 0;
    scale: 0.6;
  }
  21.26% {
    opacity: 0;
    scale: 0.6;
  }
  22.22% {
    opacity: 1;
    scale: 1;
  }
  24.14% {
    opacity: 0;
    scale: 1.25;
  }
  100% {
    opacity: 0;
    scale: 1.25;
  }
}
@keyframes hl-tap-approve2 {
  0% {
    opacity: 0;
    scale: 0.6;
  }
  67.24% {
    opacity: 0;
    scale: 0.6;
  }
  68.2% {
    opacity: 1;
    scale: 1;
  }
  70.11% {
    opacity: 0;
    scale: 1.25;
  }
  100% {
    opacity: 0;
    scale: 1.25;
  }
}
@keyframes hl-pop {
  0% {
    opacity: 0;
    scale: 1.4;
    animation-timing-function: step-end;
  }
  6.67% {
    opacity: 0;
    scale: 1.4;
    animation-timing-function: step-end;
  }
  6.7% {
    opacity: 1;
    scale: 1.4;
    animation-timing-function: step-end;
  }
  6.93% {
    scale: 1.25;
    animation-timing-function: step-end;
  }
  7.16% {
    scale: 0.9;
    animation-timing-function: step-end;
  }
  7.39% {
    scale: 1.06;
    animation-timing-function: step-end;
  }
  7.62% {
    opacity: 1;
    scale: 1;
  }
  9.2% {
    opacity: 0;
    scale: 1;
  }
  100% {
    opacity: 0;
    scale: 1;
  }
}
@keyframes hl-pop2 {
  0% {
    opacity: 0;
    scale: 1.4;
    animation-timing-function: step-end;
  }
  53.41% {
    opacity: 0;
    scale: 1.4;
    animation-timing-function: step-end;
  }
  53.45% {
    opacity: 1;
    scale: 1.4;
    animation-timing-function: step-end;
  }
  53.68% {
    scale: 1.25;
    animation-timing-function: step-end;
  }
  53.91% {
    scale: 0.9;
    animation-timing-function: step-end;
  }
  54.14% {
    scale: 1.06;
    animation-timing-function: step-end;
  }
  54.37% {
    opacity: 1;
    scale: 1;
  }
  55.94% {
    opacity: 0;
    scale: 1;
  }
  100% {
    opacity: 0;
    scale: 1;
  }
}
@keyframes hl-spark {
  0% {
    opacity: 0;
    translate: 0 0;
  }
  6.67% {
    opacity: 0;
    translate: 0 0;
  }
  6.7% {
    opacity: 1;
    translate: 0 0;
    animation-timing-function: cubic-bezier(0.2, 0.7, 0.4, 1);
  }
  7.85% {
    opacity: 1;
    translate: calc(var(--dx) * var(--k)) calc(var(--dy) * var(--k));
    animation-timing-function: ease-in;
  }
  9.2% {
    opacity: 0;
    translate: calc(var(--dx) * 1.3 * var(--k)) calc((var(--dy) + 34) * var(--k));
  }
  100% {
    opacity: 0;
    translate: calc(var(--dx) * 1.3 * var(--k)) calc((var(--dy) + 34) * var(--k));
  }
}
@keyframes hl-spark2 {
  0% {
    opacity: 0;
    translate: 0 0;
  }
  53.41% {
    opacity: 0;
    translate: 0 0;
  }
  53.45% {
    opacity: 1;
    translate: 0 0;
    animation-timing-function: cubic-bezier(0.2, 0.7, 0.4, 1);
  }
  54.6% {
    opacity: 1;
    translate: calc(var(--dx) * var(--k)) calc(var(--dy) * var(--k));
    animation-timing-function: ease-in;
  }
  55.94% {
    opacity: 0;
    translate: calc(var(--dx) * 1.3 * var(--k)) calc((var(--dy) + 34) * var(--k));
  }
  100% {
    opacity: 0;
    translate: calc(var(--dx) * 1.3 * var(--k)) calc((var(--dy) + 34) * var(--k));
  }
}
@keyframes hl-rise {
  0% {
    opacity: 0;
    translate: -50% -50%;
  }
  6.67% {
    opacity: 0;
    translate: -50% -50%;
  }
  6.7% {
    opacity: 1;
    translate: -50% -50%;
    animation-timing-function: steps(10, end);
  }
  11.49% {
    opacity: 1;
    translate: -50% calc(-50% - var(--rise));
    animation-timing-function: step-end;
  }
  12.18% {
    opacity: 0.67;
    translate: -50% calc(-50% - var(--rise));
    animation-timing-function: step-end;
  }
  12.84% {
    opacity: 0.34;
    translate: -50% calc(-50% - var(--rise));
    animation-timing-function: step-end;
  }
  13.41% {
    opacity: 0;
    translate: -50% calc(-50% - var(--rise));
  }
  100% {
    opacity: 0;
    translate: -50% calc(-50% - var(--rise));
  }
}
@keyframes hl-rise2 {
  0% {
    opacity: 0;
    translate: -50% -50%;
  }
  53.41% {
    opacity: 0;
    translate: -50% -50%;
  }
  53.45% {
    opacity: 1;
    translate: -50% -50%;
    animation-timing-function: steps(10, end);
  }
  58.24% {
    opacity: 1;
    translate: -50% calc(-50% - var(--rise));
    animation-timing-function: step-end;
  }
  58.93% {
    opacity: 0.67;
    translate: -50% calc(-50% - var(--rise));
    animation-timing-function: step-end;
  }
  59.58% {
    opacity: 0.34;
    translate: -50% calc(-50% - var(--rise));
    animation-timing-function: step-end;
  }
  60.15% {
    opacity: 0;
    translate: -50% calc(-50% - var(--rise));
  }
  100% {
    opacity: 0;
    translate: -50% calc(-50% - var(--rise));
  }
}
@keyframes hl-pad-checked {
  0% {
    opacity: 0;
  }
  6.13% {
    opacity: 0;
  }
  6.7% {
    opacity: 1;
  }
  94.25% {
    opacity: 1;
  }
  96.17% {
    opacity: 0;
  }
  100% {
    opacity: 0;
  }
}
@keyframes hl-pad-approved {
  0% {
    opacity: 0;
  }
  29.31% {
    opacity: 0;
  }
  29.89% {
    opacity: 1;
  }
  94.25% {
    opacity: 1;
  }
  96.17% {
    opacity: 0;
  }
  100% {
    opacity: 0;
  }
}
@keyframes hl-pad-next {
  0% {
    opacity: 0;
  }
  52.87% {
    opacity: 0;
  }
  53.45% {
    opacity: 1;
  }
  94.25% {
    opacity: 1;
  }
  96.17% {
    opacity: 0;
  }
  100% {
    opacity: 0;
  }
}
@keyframes hl-pad-approved2 {
  0% {
    opacity: 0;
  }
  75.29% {
    opacity: 0;
  }
  75.86% {
    opacity: 1;
  }
  94.25% {
    opacity: 1;
  }
  96.17% {
    opacity: 0;
  }
  100% {
    opacity: 0;
  }
}
@keyframes hl-phone-arrived {
  0% {
    opacity: 0;
  }
  13.98% {
    opacity: 0;
  }
  14.56% {
    opacity: 1;
  }
  94.25% {
    opacity: 1;
  }
  96.17% {
    opacity: 0;
  }
  100% {
    opacity: 0;
  }
}
@keyframes hl-phone-approved {
  0% {
    opacity: 0;
  }
  22.99% {
    opacity: 0;
  }
  23.56% {
    opacity: 1;
  }
  94.25% {
    opacity: 1;
  }
  96.17% {
    opacity: 0;
  }
  100% {
    opacity: 0;
  }
}
@keyframes hl-phone-arrived2 {
  0% {
    opacity: 0;
  }
  60.73% {
    opacity: 0;
  }
  61.3% {
    opacity: 1;
  }
  94.25% {
    opacity: 1;
  }
  96.17% {
    opacity: 0;
  }
  100% {
    opacity: 0;
  }
}
@keyframes hl-phone-approved2 {
  0% {
    opacity: 0;
  }
  68.97% {
    opacity: 0;
  }
  69.54% {
    opacity: 1;
  }
  94.25% {
    opacity: 1;
  }
  96.17% {
    opacity: 0;
  }
  100% {
    opacity: 0;
  }
}
@keyframes hl-arrive {
  0% {
    opacity: 0;
    scale: 1.06;
  }
  14.56% {
    opacity: 0;
    scale: 1.06;
  }
  15.33% {
    opacity: 1;
    scale: 1;
  }
  17.05% {
    opacity: 0.45;
    scale: 1;
  }
  18.2% {
    opacity: 1;
    scale: 1;
  }
  22.61% {
    opacity: 0;
    scale: 1;
  }
  61.3% {
    opacity: 0;
    scale: 1.06;
  }
  62.07% {
    opacity: 1;
    scale: 1;
  }
  63.6% {
    opacity: 0.45;
    scale: 1;
  }
  64.56% {
    opacity: 1;
    scale: 1;
  }
  68.58% {
    opacity: 0;
    scale: 1;
  }
  100% {
    opacity: 0;
    scale: 1;
  }
}
@keyframes hl-lift {
  0% {
    opacity: 0;
  }
  30.27% {
    opacity: 0;
  }
  31.03% {
    opacity: 1;
  }
  42.91% {
    opacity: 1;
  }
  44.44% {
    opacity: 0;
  }
  100% {
    opacity: 0;
  }
}
@keyframes hl-lift2 {
  0% {
    opacity: 0;
  }
  76.25% {
    opacity: 0;
  }
  77.01% {
    opacity: 1;
  }
  87.74% {
    opacity: 1;
  }
  89.27% {
    opacity: 0;
  }
  100% {
    opacity: 0;
  }
}
@keyframes hl-fly {
  0% {
    opacity: 0;
    scale: 0.5;
    translate: var(--x0, 0) var(--y0, 0);
  }
  34.1% {
    opacity: 0;
    scale: 0.5;
    translate: var(--x0, 0) var(--y0, 0);
  }
  34.87% {
    opacity: 1;
    scale: 1.1;
    translate: var(--x0, 0) calc(var(--y0, 0px) - 14px);
  }
  38.31% {
    opacity: 1;
    scale: 0.9;
    translate: var(--x1, 0) var(--y1, 0);
  }
  39.08% {
    opacity: 0;
    scale: 0.4;
    translate: var(--x1, 0) var(--y1, 0);
  }
  100% {
    opacity: 0;
    scale: 0.4;
    translate: var(--x1, 0) var(--y1, 0);
  }
}
@keyframes hl-fly2 {
  0% {
    opacity: 0;
    scale: 0.5;
    translate: var(--x0, 0) var(--y0, 0);
  }
  80.08% {
    opacity: 0;
    scale: 0.5;
    translate: var(--x0, 0) var(--y0, 0);
  }
  80.84% {
    opacity: 1;
    scale: 1.1;
    translate: var(--x0, 0) calc(var(--y0, 0px) - 14px);
  }
  84.29% {
    opacity: 1;
    scale: 0.9;
    translate: var(--x1, 0) var(--y1, 0);
  }
  85.06% {
    opacity: 0;
    scale: 0.4;
    translate: var(--x1, 0) var(--y1, 0);
  }
  100% {
    opacity: 0;
    scale: 0.4;
    translate: var(--x1, 0) var(--y1, 0);
  }
}
@keyframes hl-fill {
  0% {
    scale: 0.23 1;
  }
  37.55% {
    scale: 0.23 1;
  }
  39.08% {
    scale: 0.268 1;
  }
  82.76% {
    scale: 0.268 1;
  }
  85.06% {
    scale: 1 1;
  }
  94.25% {
    scale: 1 1;
  }
  96.17% {
    scale: 0.23 1;
  }
  100% {
    scale: 0.23 1;
  }
}
@keyframes hl-a-lock {
  0% {
    opacity: 1;
  }
  39% {
    opacity: 1;
  }
  39.23% {
    opacity: 0;
  }
  94.25% {
    opacity: 0;
  }
  96.17% {
    opacity: 1;
  }
  100% {
    opacity: 1;
  }
}
@keyframes hl-a-gift {
  0% {
    scale: 1;
  }
  39% {
    scale: 1;
  }
  40.23% {
    scale: 1.45;
  }
  41.38% {
    scale: 1;
  }
  100% {
    scale: 1;
  }
}
@keyframes hl-a-pill {
  0% {
    scale: 1;
    color: #8b90a8;
  }
  39% {
    scale: 1;
    color: #8b90a8;
  }
  39.46% {
    scale: 1.04;
    color: var(--cream);
  }
  40.23% {
    scale: 1.1;
  }
  41.38% {
    scale: 1;
    color: var(--cream);
  }
  94.25% {
    scale: 1;
    color: var(--cream);
  }
  96.17% {
    scale: 1;
    color: #8b90a8;
  }
  100% {
    scale: 1;
    color: #8b90a8;
  }
}
@keyframes hl-a-icon {
  0% {
    filter: grayscale(1) brightness(0.8);
  }
  39% {
    filter: grayscale(1) brightness(0.8);
  }
  39.46% {
    filter: grayscale(0) brightness(1);
  }
  94.25% {
    filter: grayscale(0) brightness(1);
  }
  96.17% {
    filter: grayscale(1) brightness(0.8);
  }
  100% {
    filter: grayscale(1) brightness(0.8);
  }
}
@keyframes hl-a-present {
  0% {
    opacity: 0;
  }
  39% {
    opacity: 0;
  }
  39.23% {
    opacity: 1;
  }
  94.25% {
    opacity: 1;
  }
  96.17% {
    opacity: 0;
  }
  100% {
    opacity: 0;
  }
}
@keyframes hl-a-present-pop {
  0% {
    scale: 1;
    rotate: -14deg;
  }
  39% {
    scale: 1;
    rotate: -14deg;
  }
  40.23% {
    scale: 1.35;
    rotate: -26deg;
  }
  41.38% {
    scale: 1;
    rotate: -14deg;
  }
  100% {
    scale: 1;
    rotate: -14deg;
  }
}
@keyframes hl-a-yay {
  0% {
    opacity: 0;
    scale: 0.6;
  }
  39.08% {
    opacity: 0;
    scale: 0.6;
  }
  40.23% {
    opacity: 1;
    scale: 1.15;
  }
  41.19% {
    opacity: 1;
    scale: 1;
  }
  94.25% {
    opacity: 1;
    scale: 1;
  }
  95.79% {
    opacity: 0;
    scale: 1;
  }
  100% {
    opacity: 0;
    scale: 1;
  }
}
@keyframes hl-a-bit {
  0% {
    opacity: 0;
    translate: 0 0;
    rotate: 0deg;
  }
  39.08% {
    opacity: 0;
    translate: 0 0;
    rotate: 0deg;
  }
  39.31% {
    opacity: 1;
    translate: 0 0;
    rotate: 0deg;
  }
  42.53% {
    opacity: 1;
    translate: var(--dx) var(--dy);
    rotate: 200deg;
  }
  45.21% {
    opacity: 0;
    translate: calc(var(--dx) * 1.2) calc(var(--dy) + 9cqw);
    rotate: 320deg;
  }
  100% {
    opacity: 0;
    translate: calc(var(--dx) * 1.2) calc(var(--dy) + 9cqw);
    rotate: 320deg;
  }
}
@keyframes hl-b-lock {
  0% {
    opacity: 1;
  }
  84.98% {
    opacity: 1;
  }
  85.21% {
    opacity: 0;
  }
  94.25% {
    opacity: 0;
  }
  96.17% {
    opacity: 1;
  }
  100% {
    opacity: 1;
  }
}
@keyframes hl-b-gift {
  0% {
    scale: 1;
  }
  84.98% {
    scale: 1;
  }
  86.21% {
    scale: 1.45;
  }
  87.36% {
    scale: 1;
  }
  100% {
    scale: 1;
  }
}
@keyframes hl-b-pill {
  0% {
    scale: 1;
    color: #8b90a8;
  }
  84.98% {
    scale: 1;
    color: #8b90a8;
  }
  85.44% {
    scale: 1.04;
    color: var(--cream);
  }
  86.21% {
    scale: 1.1;
  }
  87.36% {
    scale: 1;
    color: var(--cream);
  }
  94.25% {
    scale: 1;
    color: var(--cream);
  }
  96.17% {
    scale: 1;
    color: #8b90a8;
  }
  100% {
    scale: 1;
    color: #8b90a8;
  }
}
@keyframes hl-b-icon {
  0% {
    filter: grayscale(1) brightness(0.8);
  }
  84.98% {
    filter: grayscale(1) brightness(0.8);
  }
  85.44% {
    filter: grayscale(0) brightness(1);
  }
  94.25% {
    filter: grayscale(0) brightness(1);
  }
  96.17% {
    filter: grayscale(1) brightness(0.8);
  }
  100% {
    filter: grayscale(1) brightness(0.8);
  }
}
@keyframes hl-b-present {
  0% {
    opacity: 0;
  }
  84.98% {
    opacity: 0;
  }
  85.21% {
    opacity: 1;
  }
  94.25% {
    opacity: 1;
  }
  96.17% {
    opacity: 0;
  }
  100% {
    opacity: 0;
  }
}
@keyframes hl-b-present-pop {
  0% {
    scale: 1;
    rotate: -14deg;
  }
  84.98% {
    scale: 1;
    rotate: -14deg;
  }
  86.21% {
    scale: 1.35;
    rotate: -26deg;
  }
  87.36% {
    scale: 1;
    rotate: -14deg;
  }
  100% {
    scale: 1;
    rotate: -14deg;
  }
}
@keyframes hl-b-yay {
  0% {
    opacity: 0;
    scale: 0.6;
  }
  85.06% {
    opacity: 0;
    scale: 0.6;
  }
  86.21% {
    opacity: 1;
    scale: 1.15;
  }
  87.16% {
    opacity: 1;
    scale: 1;
  }
  94.25% {
    opacity: 1;
    scale: 1;
  }
  95.79% {
    opacity: 0;
    scale: 1;
  }
  100% {
    opacity: 0;
    scale: 1;
  }
}
@keyframes hl-b-bit {
  0% {
    opacity: 0;
    translate: 0 0;
    rotate: 0deg;
  }
  85.06% {
    opacity: 0;
    translate: 0 0;
    rotate: 0deg;
  }
  85.29% {
    opacity: 1;
    translate: 0 0;
    rotate: 0deg;
  }
  88.51% {
    opacity: 1;
    translate: var(--dx) var(--dy);
    rotate: 200deg;
  }
  91.19% {
    opacity: 0;
    translate: calc(var(--dx) * 1.2) calc(var(--dy) + 9cqw);
    rotate: 320deg;
  }
  100% {
    opacity: 0;
    translate: calc(var(--dx) * 1.2) calc(var(--dy) + 9cqw);
    rotate: 320deg;
  }
}
@keyframes hl-a-to {
  0% {
    opacity: 1;
  }
  39% {
    opacity: 1;
  }
  39.23% {
    opacity: 0;
  }
  94.25% {
    opacity: 0;
  }
  96.17% {
    opacity: 1;
  }
  100% {
    opacity: 1;
  }
}
@keyframes hl-b-to {
  0% {
    opacity: 0;
  }
  40.23% {
    opacity: 0;
  }
  41.38% {
    opacity: 1;
  }
  84.98% {
    opacity: 1;
  }
  85.21% {
    opacity: 0;
  }
  100% {
    opacity: 0;
  }
}
@keyframes hl-pad-front {
  0% {
    z-index: 2;
    scale: 1.02;
  }
  13.33% {
    z-index: 2;
    scale: 1.02;
  }
  14.25% {
    z-index: 1;
    scale: 0.97;
  }
  29.04% {
    z-index: 1;
    scale: 0.97;
  }
  29.96% {
    z-index: 2;
    scale: 1.02;
  }
  60.08% {
    z-index: 2;
    scale: 1.02;
  }
  61% {
    z-index: 1;
    scale: 0.97;
  }
  75.02% {
    z-index: 1;
    scale: 0.97;
  }
  75.94% {
    z-index: 2;
    scale: 1.02;
  }
  100% {
    z-index: 2;
    scale: 1.02;
  }
}
@keyframes hl-phone-front {
  0% {
    z-index: 1;
    scale: 0.97;
  }
  13.33% {
    z-index: 1;
    scale: 0.97;
  }
  14.25% {
    z-index: 2;
    scale: 1.04;
  }
  29.04% {
    z-index: 2;
    scale: 1.04;
  }
  29.96% {
    z-index: 1;
    scale: 0.97;
  }
  60.08% {
    z-index: 1;
    scale: 0.97;
  }
  61% {
    z-index: 2;
    scale: 1.04;
  }
  75.02% {
    z-index: 2;
    scale: 1.04;
  }
  75.94% {
    z-index: 1;
    scale: 0.97;
  }
  100% {
    z-index: 1;
    scale: 0.97;
  }
}
@keyframes hl-pad-lit {
  0% {
    filter: brightness(1);
  }
  13.33% {
    filter: brightness(1);
  }
  14.25% {
    filter: brightness(0.72);
  }
  29.04% {
    filter: brightness(0.72);
  }
  29.96% {
    filter: brightness(1);
  }
  60.08% {
    filter: brightness(1);
  }
  61% {
    filter: brightness(0.72);
  }
  75.02% {
    filter: brightness(0.72);
  }
  75.94% {
    filter: brightness(1);
  }
  100% {
    filter: brightness(1);
  }
}
@keyframes hl-phone-lit {
  0% {
    filter: brightness(0.72);
  }
  13.33% {
    filter: brightness(0.72);
  }
  14.25% {
    filter: brightness(1);
  }
  29.04% {
    filter: brightness(1);
  }
  29.96% {
    filter: brightness(0.72);
  }
  60.08% {
    filter: brightness(0.72);
  }
  61% {
    filter: brightness(1);
  }
  75.02% {
    filter: brightness(1);
  }
  75.94% {
    filter: brightness(0.72);
  }
  100% {
    filter: brightness(0.72);
  }
}
@keyframes hl-pad-ring {
  0% {
    opacity: 1;
  }
  13.33% {
    opacity: 1;
  }
  14.25% {
    opacity: 0;
  }
  29.04% {
    opacity: 0;
  }
  29.96% {
    opacity: 1;
  }
  60.08% {
    opacity: 1;
  }
  61% {
    opacity: 0;
  }
  75.02% {
    opacity: 0;
  }
  75.94% {
    opacity: 1;
  }
  100% {
    opacity: 1;
  }
}
@keyframes hl-phone-ring {
  0% {
    opacity: 0;
  }
  13.33% {
    opacity: 0;
  }
  14.25% {
    opacity: 1;
  }
  29.04% {
    opacity: 1;
  }
  29.96% {
    opacity: 0;
  }
  60.08% {
    opacity: 0;
  }
  61% {
    opacity: 1;
  }
  75.02% {
    opacity: 1;
  }
  75.94% {
    opacity: 0;
  }
  100% {
    opacity: 0;
  }
}
@keyframes hl-say1 {
  0% {
    opacity: 1;
    translate: -50% 0;
  }
  13.33% {
    opacity: 1;
    translate: -50% 0;
  }
  13.79% {
    opacity: 0;
    translate: -50% 0;
  }
  96.13% {
    opacity: 0;
    translate: -50% 6px;
  }
  96.86% {
    opacity: 1;
    translate: -50% 0;
  }
  100% {
    opacity: 1;
    translate: -50% 0;
  }
}
@keyframes hl-say2 {
  0% {
    opacity: 0;
    translate: -50% 6px;
  }
  13.79% {
    opacity: 0;
    translate: -50% 6px;
  }
  14.48% {
    opacity: 1;
    translate: -50% 0;
  }
  29.04% {
    opacity: 1;
    translate: -50% 0;
  }
  29.5% {
    opacity: 0;
    translate: -50% 0;
  }
  100% {
    opacity: 0;
    translate: -50% 0;
  }
}
@keyframes hl-say3 {
  0% {
    opacity: 0;
    translate: -50% 6px;
  }
  29.5% {
    opacity: 0;
    translate: -50% 6px;
  }
  30.19% {
    opacity: 1;
    translate: -50% 0;
  }
  38.24% {
    opacity: 1;
    translate: -50% 0;
  }
  38.7% {
    opacity: 0;
    translate: -50% 0;
  }
  100% {
    opacity: 0;
    translate: -50% 0;
  }
}
@keyframes hl-say4 {
  0% {
    opacity: 0;
    translate: -50% 6px;
  }
  38.7% {
    opacity: 0;
    translate: -50% 6px;
  }
  39.39% {
    opacity: 1;
    translate: -50% 0;
  }
  46.28% {
    opacity: 1;
    translate: -50% 0;
  }
  46.74% {
    opacity: 0;
    translate: -50% 0;
  }
  100% {
    opacity: 0;
    translate: -50% 0;
  }
}
@keyframes hl-say5 {
  0% {
    opacity: 0;
    translate: -50% 6px;
  }
  46.74% {
    opacity: 0;
    translate: -50% 6px;
  }
  47.43% {
    opacity: 1;
    translate: -50% 0;
  }
  60.08% {
    opacity: 1;
    translate: -50% 0;
  }
  60.54% {
    opacity: 0;
    translate: -50% 0;
  }
  100% {
    opacity: 0;
    translate: -50% 0;
  }
}
@keyframes hl-say6 {
  0% {
    opacity: 0;
    translate: -50% 6px;
  }
  60.54% {
    opacity: 0;
    translate: -50% 6px;
  }
  61.23% {
    opacity: 1;
    translate: -50% 0;
  }
  75.02% {
    opacity: 1;
    translate: -50% 0;
  }
  75.48% {
    opacity: 0;
    translate: -50% 0;
  }
  100% {
    opacity: 0;
    translate: -50% 0;
  }
}
@keyframes hl-say7 {
  0% {
    opacity: 0;
    translate: -50% 6px;
  }
  75.48% {
    opacity: 0;
    translate: -50% 6px;
  }
  76.17% {
    opacity: 1;
    translate: -50% 0;
  }
  84.21% {
    opacity: 1;
    translate: -50% 0;
  }
  84.67% {
    opacity: 0;
    translate: -50% 0;
  }
  100% {
    opacity: 0;
    translate: -50% 0;
  }
}
@keyframes hl-say8 {
  0% {
    opacity: 0;
    translate: -50% 6px;
  }
  84.67% {
    opacity: 0;
    translate: -50% 6px;
  }
  85.36% {
    opacity: 1;
    translate: -50% 0;
  }
  93.79% {
    opacity: 1;
    translate: -50% 0;
  }
  94.25% {
    opacity: 0;
    translate: -50% 0;
  }
  100% {
    opacity: 0;
    translate: -50% 0;
  }
}

/* ---------- T-site-review-1021: more of what the app does (Gate P, 2026-10-21) ---------- */
/* On a phone the launch list keeps the room the trust line under it left before the devices (Shahrum, 2026-10-22,
   took the line out: "No ads. No kid accounts. You approve everything."). */
.site .hero .get {
  margin-bottom: 30px;
}
/* A step's second paragraph: the next thing a parent asks, a size down from the step's own line at every width
   (the desktop ladder drops that line to 16px at 1000). The two sit in one box so the desktop ladder's subgrid keeps
   its four rows (rung, heading, words, screen). */
.site .step .words {
  display: grid;
  gap: 10px;
  align-content: start;
}
/* The aside under a step's words runs a size under them (Gate P comment, 2026-10-22: "a little bit more"). */
.site .step p.more {
  font-size: 14px;
}
@container (min-width: 900px) {
  .site .ladder .step .words p {
    margin-bottom: 0;
  }
  .site .ladder .step .words {
    margin-bottom: 16px;
  }
  .site .step p.more {
    font-size: 16px;
  }
}
@container (min-width: 1000px) {
  .site .ladder .step p.more {
    font-size: 14px;
  }
}
/* Step 3 opens on the grown-up's lock screen: the app's real push ("⭐ Sam · 2 chores ready", one per kid,
   server/routes/verify.ts) arrives, a tap opens Home, then Approve and its Undo bar. Drawn: the lock screen is
   iOS's own, not the app's. With reduced motion or no script it never shows; the end frame does. */
.site .ls-lock {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  padding-top: 15%;
  background: radial-gradient(120% 75% at 50% 0%, #3a4784 0%, #1e2237 58%, #12141f 100%);
  color: #fff;
  font-family: -apple-system, BlinkMacSystemFont, "SF Pro Display", sans-serif;
  opacity: 0;
  pointer-events: none;
}
.site .ls-lock .lk-date {
  font-size: calc(var(--w) * 0.06);
  font-weight: 600;
  opacity: 0.9;
}
.site .ls-lock .lk-time {
  order: 1;
  font-size: calc(var(--w) * 0.29);
  font-weight: 700;
  line-height: 1;
  letter-spacing: -0.02em;
}
.site .ls-lock .lk-note {
  position: absolute;
  top: 30.5%;
  left: 3.5%;
  right: 3.5%;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  gap: calc(var(--w) * 0.02);
  align-items: center;
  padding: calc(var(--w) * 0.035);
  border-radius: calc(var(--w) * 0.07);
  background: rgb(255 255 255 / 0.17);
  text-align: left;
}
.site .ls-lock .lk-note img {
  width: calc(var(--w) * 0.12);
  height: auto;
  border-radius: 23%;
}
.site .ls-lock .lk-tx {
  display: grid;
  font-size: calc(var(--w) * 0.042);
  line-height: 1.25;
}
.site .ls-lock .lk-tx b {
  font-weight: 600;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.site .ls-lock .lk-now {
  align-self: start;
  font-size: calc(var(--w) * 0.043);
  opacity: 0.7;
}
/* The lock screen's own furniture, so its lower half reads as a phone: flashlight, camera, home bar. */
.site .ls-lock .lk-btn {
  position: absolute;
  bottom: 6%;
  width: calc(var(--w) * 0.13);
  aspect-ratio: 1;
  border-radius: 50%;
  background: rgb(255 255 255 / 0.14);
}
.site .ls-lock .lk-btn.l {
  left: 11%;
}
.site .ls-lock .lk-btn.r {
  right: 11%;
}
.site .ls-lock .lk-bar {
  position: absolute;
  bottom: 1.6%;
  left: 35%;
  right: 35%;
  height: calc(var(--w) * 0.014);
  border-radius: 99px;
  background: rgb(255 255 255 / 0.8);
}
/* The tap on the notification follows the card's own rounded corners. */
.site .ls-ring.lk-ring {
  border-radius: calc(var(--w) * 0.075);
}
.ls-on .site .ls .ls-lock {
  opacity: 1;
}
.ls-on .site .ls.play .ls-lock {
  animation: ls-out 0.4s ease-in-out var(--d) both;
}
.ls-on .site .ls.play .lk-note {
  animation: lk-in 0.45s cubic-bezier(0.2, 0.8, 0.2, 1) 0.3s both;
}
@keyframes lk-in {
  from {
    opacity: 0;
    translate: 0 -40%;
    scale: 0.96;
  }
}
/* The setup strip: three numbered steps, upright and whole, under the section's text, the pairing phone and iPad one
   step (Gate P comment, 2026-10-22). Phones stack them in order. */
.site .feature.setup {
  padding-bottom: 64px;
}
.site .viz.setup-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 22px 12px;
  align-items: start;
  margin-top: 10px;
}
.site .viz.setup-row .appshot {
  align-self: start;
  width: 100%;
  justify-items: center;
  gap: 10px;
}
.site .setup-row .appshot > .dev-tag {
  justify-self: center;
}
.site .feature.setup .setup-row .appshot .gdev {
  --w: min(40cqi, 210px);
  rotate: none;
}
/* Clear of the device's ring by 16 px (Gate P comment, 2026-10-22: more room between each screen and its words). */
.site .setup-row figcaption {
  min-height: 2.5em;
  margin-top: 14px;
  color: var(--body-80);
  font-size: 16px;
  text-align: center;
  text-wrap: balance;
}
/* The step's number rides its first line, so it stays by the words when they wrap. */
.site .setup-row .step-n {
  display: inline-grid;
  place-items: center;
  margin-right: 8px;
  vertical-align: 1px;
  width: 26px;
  height: 26px;
  border: 2px solid var(--ink);
  border-radius: 4px;
  box-shadow: 0 3px 0 var(--ink);
  background: var(--cream);
  color: var(--ink);
  font: 400 14px / 1 var(--display);
}
@container (min-width: 700px) {
  .site .viz.setup-row {
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 16px;
  }
  .site .feature.setup .setup-row .appshot .gdev {
    --w: min(21cqi, 210px);
  }
}
@container (min-width: 900px) {
  .site .hero .get {
    margin-bottom: 0;
  }
  .site .setup > div > .viz {
    grid-column: 1 / -1;
    grid-row: auto;
  }
  /* The words run under the heading across both columns, so they wrap later (Gate P comment, 2026-10-22: wrapped
     short, they made the section too tall). */
  .site .setup > div > p {
    grid-column: 1 / -1;
    max-width: 60ch;
  }
}
/* Pairing, as one moment (Gate P comment, 2026-10-21): the grown-up's phone shows the code, the kid's iPad types it
   and opens to their chores, then the phone says Paired!. It plays like a ladder step (.ls; motion.js). The typed
   letters are drawn over the capture's empty boxes, at CodeEntryField's look: 28pt bold monospaced cream on the
   surface colour, the active box ringed in the accent. Phones: the middle row; 700 up: the middle two columns. */
.site .pair-anim {
  display: flex;
  justify-content: center;
  align-items: flex-end;
  gap: 14px;
}
.site .pair-dev {
  display: grid;
  justify-items: center;
  gap: 10px;
}
.site .feature.setup .setup-row .pair .gdev.phone {
  --w: 34cqi;
}
.site .feature.setup .setup-row .pair .gdev.pad {
  --w: 52cqi;
}
.site .pk-entry {
  display: block;
}
.site :is(.pk-c, .pk-f) {
  position: absolute;
  top: 54.05%;
  width: 5.5%;
  aspect-ratio: 88 / 112;
  translate: -50% -50%;
  border-radius: calc(var(--w) * 0.01);
  opacity: 0;
}
.site .pk-c {
  z-index: 1;
  display: grid;
  place-items: center;
  border: 1px solid rgb(246 156 78 / 0.25);
  background: #29314c;
  color: var(--cream);
  font:
    700 calc(var(--w) * 0.0317) / 1 ui-monospace,
    "SF Mono",
    Menlo,
    monospace;
}
.site .pk-f {
  border: max(1.5px, calc(var(--w) * 0.0024)) solid #f69c4e;
}
@container (min-width: 700px) {
  .site .setup-row .appshot.pair {
    grid-column: span 2;
  }
  .site .feature.setup .setup-row .pair .gdev.phone {
    --w: min(17cqi, 180px);
  }
  .site .feature.setup .setup-row .pair .gdev.pad {
    --w: min(27cqi, 290px);
  }
}
.ls-on .site .ls.play :is(.pk-c, .pk-f) {
  animation: pk-in 0.05s step-end var(--t) both;
}
/* A box's focus ring goes as its letter lands (--u): left on, it showed through the letter box's translucent edge
   (his "glitchiness" comment, 2026-10-21). */
.ls-on .site .ls.play .pk-f {
  animation:
    pk-in 0.05s step-end var(--t) both,
    pk-gone 0.05s step-end var(--u) forwards;
}
/* 99.9%: Safari ends a delayed animation at progress 0.99999, and a stepped last move would then hold a step short
   (the pairing code's letters never showed), so each stepped animation's end value starts at 99.9%, as sq-mark's
   jump-none does in its way (T-site-safari-step-end). */
@keyframes pk-gone {
  99.9%,
  to {
    visibility: hidden;
  }
}
@keyframes pk-in {
  from {
    opacity: 0;
  }
  99.9%,
  to {
    opacity: 1;
  }
}
/* Pairing lights whoever is acting in their colour, as the hero does (Gate P comment, 2026-10-21, a try on this row
   first): the grown-up's phone while it shows the code, the kid's iPad while it types it, the phone again at
   Paired!. Without motion both rings show, so the two devices still read as grown-up and kid. */
/* The tag clears the ring (inset 8px out, with its 3px shadow). */
.site .pair-anim .pair-dev {
  gap: 16px;
}
.site .pair-anim .gdev.phone {
  --lit: var(--orange);
}
.site .pair-anim .gdev.pad {
  --lit: #6aa3ff;
}
.site .pair-anim .gdev::after {
  content: "";
  position: absolute;
  inset: -8px;
  border: 4px solid var(--lit);
  border-radius: calc(var(--w) * 0.155 + 8px);
  box-shadow:
    0 0 0 2px var(--ink),
    inset 0 0 0 2px var(--ink),
    0 0 22px var(--lit);
  pointer-events: none;
}
.site .pair-anim .gdev.pad::after {
  border-radius: calc(var(--w) * 0.06 + 8px);
}
.ls-on .site .pair-anim .gdev::after {
  opacity: 0;
}
.ls-on .site .pair-anim.play .gdev.phone::after {
  animation: pair-lit-grown 5s linear both;
}
.ls-on .site .pair-anim.play .gdev.pad::after {
  animation: pair-lit-kid 5s linear both;
}
/* 5 s: the code until 1 s, the iPad types to 3.4 s, Paired! from 3.5 s. */
@keyframes pair-lit-grown {
  0%,
  19% {
    opacity: 1;
  }
  23%,
  68% {
    opacity: 0;
  }
  72%,
  100% {
    opacity: 1;
  }
}
@keyframes pair-lit-kid {
  0%,
  19% {
    opacity: 0;
  }
  23%,
  68% {
    opacity: 1;
  }
  72%,
  100% {
    opacity: 0;
  }
}
/* The reward editor's Repeats switch, drawn over the app's own (Gate P comment, 2026-10-21: slide it, don't ring it). It
   starts as captured, off; the knob slides and the track takes the app's orange; then the editor quickly becomes the
   end frame, where "Unlocks around" has given way to "How often" (a reflow, not a scroll, so no slide). Measured on
   the store world's editor (1170 px): the track is 189 x 80 at (897, 1701), off grey #63687e. */
.site .rw-edit {
  display: block;
}
.site .rw-switch {
  position: absolute;
  left: 76.67%;
  top: 67.18%;
  width: 16.15%;
  height: 3.16%;
  border-radius: 999px;
  background: #63687e;
}
.site .rw-switch b {
  position: absolute;
  top: 5%;
  bottom: 5%;
  left: 3.17%;
  width: 58.73%;
  border-radius: 999px;
  background: #fff;
}
.ls-on .site .ls.play .rw-switch {
  animation: rw-track 0.3s ease-in-out var(--d) both;
}
.ls-on .site .ls.play .rw-switch b {
  animation: rw-knob 0.3s cubic-bezier(0.3, 0.7, 0.2, 1) var(--d) both;
}
/* The editor is a sheet: it slides up over the list (--s), then cuts to the end frame once Repeats is on. */
.ls-on .site .ls.play .rw-edit.pre {
  animation:
    ch-up 0.35s cubic-bezier(0.2, 0.8, 0.2, 1) var(--s) both,
    ls-out 0.08s ease-in-out var(--d) both;
}
@keyframes rw-track {
  to {
    background: var(--orange);
  }
}
@keyframes rw-knob {
  to {
    translate: 59.5% 0;
  }
}
/* The launch list (Shahrum, 2026-10-21): Apple's review is taking longer than a night, so the hero's wait list is open,
   not folded. His Gate P comments made it sharper: the field and "Notify me" as one control, and no store to pick
   until the App Store launch (2026-10-22). Its address still comes to Shahrum in one email and is kept nowhere
   (ADR-0152). */
.site .notify {
  flex: 1 1 100%;
}
.site .waitlist > label {
  font-weight: 700;
  color: var(--cream);
}
/* Small, so the promise never outweighs the form (Gate P comment, 2026-10-21); .waitlist outranks the hero's
   `.step p` size. */
.site .waitlist .waitlist-note {
  margin: 0;
  font-size: 13px;
  color: var(--mute);
}
/* Stacked, the hero stage's reward tags reach 26 px above its box (measured over the loop at 390 px), so a status
   line under the form keeps clear of them. */
.site .hero .notify .waitlist-msg:not(:empty) {
  margin-bottom: 20px;
}

/* You plan your kids' chores (Gate P comment, 2026-10-21: "show the parent ... typing the name of the chore"): the New
   chore sheet slides up over Alex's list, "Unload the dishwasher" types in, Medium and Weekly are tapped, the weekdays
   and Evening light, and Save slides the sheet away onto the list with the chore in Evening. Every frame is the app's
   own (SiteShotTests B, the store world). The sheet is one layer, so its taps and glows ride it down. */
.site .ch-sheet {
  position: absolute;
  inset: 0;
  display: none;
}
.site .ch-name {
  display: block;
}
/* The editor scrolls from Effort down to When: below its fixed header (545 px of 2532) the two frames are one strip,
   368 pt apart (measured: they match row for row there but for the taps). */
.site .ch-scroll {
  position: absolute;
  inset: 0;
  clip-path: inset(21.52% 0 0 0);
}
.site .ch-scroll img {
  position: absolute;
  inset: 0;
}
/* Weekly adds the day row under Frequency, so the first frame stops above Frequency (730 of 844 pt): the tap lights
   Weekly, the day row is there, and the sheet scrolls on. The cut is fixed on a copy of the frame (.ch-cut), and the
   whole frame above it goes at the tap, by a 10 ms linear fade: Safari ends a delayed step-end animation just short
   (progress 0.99999, as sq-mark's jump-none says), so an animated step-end cut and hide never held and a stray
   "Daily" strip sat over the day row (Shahrum's iPhone screenshot, 2026-10-22; reproduced in WebKit, not in
   Chrome). */
.site .ch-scroll .ch-cut {
  clip-path: inset(0 0 13.5% 0);
}
/* The name types in: a cover in the field's own colour lifts one letter at a time (each stop is a measured letter
   edge, so no letter is ever cut), and the caret rides its edge. */
.site :is(.ch-type, .ch-caret) {
  position: absolute;
  top: 27.01%;
  height: 1.97%;
}
.site .ch-type {
  left: 25.64%;
  width: 46.32%;
  background: #29314c;
}
.site .ch-caret {
  left: 25.73%;
  top: 26.7%;
  width: 0.51%;
  height: 2.6%;
  background: var(--orange);
  opacity: 0;
}
.ls-on .site .ch-sheet {
  display: block;
  translate: 0 100%;
}
.ls-on .site .ls.play .ch-sheet {
  animation:
    ch-up 0.35s cubic-bezier(0.2, 0.8, 0.2, 1) var(--s) both,
    ch-down 0.3s ease-in var(--x) forwards;
}
.ls-on .site .ls.play .ch-to {
  animation: ch-to 0.45s ease-in-out var(--d) both;
}
.ls-on .site .ls.play .ch-cut {
  animation:
    ch-from 0.45s ease-in-out var(--d) both,
    ls-out 0.01s linear calc(var(--d) + 0.45s) both;
}
.ls-on .site .ls.play .ch-whole {
  animation: ls-out 0.01s linear var(--t) both;
}
@keyframes ch-to {
  from {
    translate: 0 43.6%;
  }
  to {
    translate: 0 0;
  }
}
@keyframes ch-from {
  to {
    translate: 0 -43.6%;
  }
}
.ls-on .site .ls.play .ch-type {
  animation: ch-type 1.05s step-end var(--d) both;
}
.ls-on .site .ls.play .ch-caret {
  animation: ch-caret 1.05s step-end var(--d) both;
}
@keyframes ch-up {
  from {
    translate: 0 100%;
  }
  to {
    translate: 0 0;
  }
}
@keyframes ch-down {
  from {
    translate: 0 0;
  }
  to {
    translate: 0 100%;
  }
}
@keyframes ch-type {
  0.00% {
    clip-path: inset(0 0 0 6.46%);
  }
  4.76% {
    clip-path: inset(0 0 0 11.81%);
  }
  9.52% {
    clip-path: inset(0 0 0 14.21%);
  }
  14.29% {
    clip-path: inset(0 0 0 19.93%);
  }
  19.05% {
    clip-path: inset(0 0 0 24.91%);
  }
  23.81% {
    clip-path: inset(0 0 0 30.63%);
  }
  28.57% {
    clip-path: inset(0 0 0 32.47%);
  }
  33.33% {
    clip-path: inset(0 0 0 36.35%);
  }
  38.10% {
    clip-path: inset(0 0 0 41.70%);
  }
  42.86% {
    clip-path: inset(0 0 0 47.05%);
  }
  47.62% {
    clip-path: inset(0 0 0 48.89%);
  }
  52.38% {
    clip-path: inset(0 0 0 54.61%);
  }
  57.14% {
    clip-path: inset(0 0 0 57.01%);
  }
  61.90% {
    clip-path: inset(0 0 0 61.99%);
  }
  66.67% {
    clip-path: inset(0 0 0 67.53%);
  }
  71.43% {
    clip-path: inset(0 0 0 74.91%);
  }
  76.19% {
    clip-path: inset(0 0 0 79.89%);
  }
  80.95% {
    clip-path: inset(0 0 0 85.06%);
  }
  85.71% {
    clip-path: inset(0 0 0 90.41%);
  }
  90.48% {
    clip-path: inset(0 0 0 95.76%);
  }
  95.24% {
    clip-path: inset(0 0 0 100.00%);
  }
  99.9%,
  100% {
    clip-path: inset(0 0 0 100%);
  }
}
@keyframes ch-caret {
  0.00% {
    left: 28.72%;
    opacity: 1;
  }
  4.76% {
    left: 31.20%;
    opacity: 1;
  }
  9.52% {
    left: 32.31%;
    opacity: 1;
  }
  14.29% {
    left: 34.96%;
    opacity: 1;
  }
  19.05% {
    left: 37.26%;
    opacity: 1;
  }
  23.81% {
    left: 39.91%;
    opacity: 1;
  }
  28.57% {
    left: 40.77%;
    opacity: 1;
  }
  33.33% {
    left: 42.56%;
    opacity: 1;
  }
  38.10% {
    left: 45.04%;
    opacity: 1;
  }
  42.86% {
    left: 47.52%;
    opacity: 1;
  }
  47.62% {
    left: 48.38%;
    opacity: 1;
  }
  52.38% {
    left: 51.03%;
    opacity: 1;
  }
  57.14% {
    left: 52.14%;
    opacity: 1;
  }
  61.90% {
    left: 54.44%;
    opacity: 1;
  }
  66.67% {
    left: 57.01%;
    opacity: 1;
  }
  71.43% {
    left: 60.43%;
    opacity: 1;
  }
  76.19% {
    left: 62.74%;
    opacity: 1;
  }
  80.95% {
    left: 65.13%;
    opacity: 1;
  }
  85.71% {
    left: 67.61%;
    opacity: 1;
  }
  90.48% {
    left: 70.09%;
    opacity: 1;
  }
  95.24% {
    left: 72.05%;
    opacity: 1;
  }
  99.9%,
  100% {
    left: 72.05%;
    opacity: 1;
  }
}
/* Setup step 1 (Gate P comment, 2026-10-22: "show adding a custom reward too"): after two starter ticks, Add your own
   slides the New reward sheet up (the chore editor's .ch-sheet), "Bake cookies together" types in the way the chore's
   name does (a little slower, 70 ms a letter, and about a second on each of the sheet's screens: Gate P comment,
   2026-10-22, it "moves through that screen extremely fast"), the cookie comes from the icon picker's Rewards, and Add slides the sheet away onto the list with it
   ticked. The field is empty until the first letter, and the app's own caret shows once the last one lands. */
.site :is(.sr-type, .sr-caret) {
  position: absolute;
  top: 19.04%;
  height: 2.88%;
}
.site .sr-type {
  left: 25.56%;
  width: 45.47%;
  background: #29314c;
}
.site .sr-caret {
  top: 19.19%;
  width: 0.43%;
  height: 2.61%;
  background: #0091ff;
  opacity: 0;
}
.ls-on .site .ls.play .sr-type {
  animation: sr-type 1.47s step-end var(--d) both;
}
.ls-on .site .ls.play .sr-caret {
  animation: sr-caret 1.47s step-end var(--d) both;
}
@keyframes sr-type {
  0.00% {
    clip-path: inset(0 0 0 0.00%);
  }
  4.76% {
    clip-path: inset(0 0 0 6.39%);
  }
  9.52% {
    clip-path: inset(0 0 0 11.47%);
  }
  14.29% {
    clip-path: inset(0 0 0 16.54%);
  }
  19.05% {
    clip-path: inset(0 0 0 21.80%);
  }
  23.81% {
    clip-path: inset(0 0 0 24.06%);
  }
  28.57% {
    clip-path: inset(0 0 0 29.14%);
  }
  33.33% {
    clip-path: inset(0 0 0 34.77%);
  }
  38.10% {
    clip-path: inset(0 0 0 40.41%);
  }
  42.86% {
    clip-path: inset(0 0 0 45.49%);
  }
  47.62% {
    clip-path: inset(0 0 0 47.74%);
  }
  52.38% {
    clip-path: inset(0 0 0 53.38%);
  }
  57.14% {
    clip-path: inset(0 0 0 58.27%);
  }
  61.90% {
    clip-path: inset(0 0 0 60.34%);
  }
  66.67% {
    clip-path: inset(0 0 0 63.91%);
  }
  71.43% {
    clip-path: inset(0 0 0 69.36%);
  }
  76.19% {
    clip-path: inset(0 0 0 74.81%);
  }
  80.95% {
    clip-path: inset(0 0 0 80.26%);
  }
  85.71% {
    clip-path: inset(0 0 0 83.83%);
  }
  90.48% {
    clip-path: inset(0 0 0 89.47%);
  }
  95.24% {
    clip-path: inset(0 0 0 94.92%);
  }
  99.9%,
  100% {
    clip-path: inset(0 0 0 100.00%);
  }
}
@keyframes sr-caret {
  0.00% {
    left: 25.73%;
    opacity: 1;
  }
  4.76% {
    left: 28.46%;
    opacity: 1;
  }
  9.52% {
    left: 30.77%;
    opacity: 1;
  }
  14.29% {
    left: 33.08%;
    opacity: 1;
  }
  19.05% {
    left: 35.47%;
    opacity: 1;
  }
  23.81% {
    left: 36.50%;
    opacity: 1;
  }
  28.57% {
    left: 38.80%;
    opacity: 1;
  }
  33.33% {
    left: 41.37%;
    opacity: 1;
  }
  38.10% {
    left: 43.93%;
    opacity: 1;
  }
  42.86% {
    left: 46.24%;
    opacity: 1;
  }
  47.62% {
    left: 47.26%;
    opacity: 1;
  }
  52.38% {
    left: 49.83%;
    opacity: 1;
  }
  57.14% {
    left: 52.05%;
    opacity: 1;
  }
  61.90% {
    left: 52.99%;
    opacity: 1;
  }
  66.67% {
    left: 54.62%;
    opacity: 1;
  }
  71.43% {
    left: 57.09%;
    opacity: 1;
  }
  76.19% {
    left: 59.57%;
    opacity: 1;
  }
  80.95% {
    left: 62.05%;
    opacity: 1;
  }
  85.71% {
    left: 63.68%;
    opacity: 1;
  }
  90.48% {
    left: 66.24%;
    opacity: 1;
  }
  95.24% {
    left: 68.72%;
    opacity: 1;
  }
  99.9%,
  100% {
    left: 70.34%;
    opacity: 0;
  }
}
/* Kids unlock rewards: a finger drags the scrubber from the first reward to Arcade trip, the one that is ready, and
   taps Ask; the app asks "Ask for this?". The frames are crops of the sheet's middle (points 290 to 660 of 844,
   SiteShotTests D) laid back over the phone at their own place, as on the battle pass below. They played as a framed
   close-up over a dimmed phone until its outline bled over the phone (Gate P comment, 2026-10-22: no zoom needed). */
.site .bp-close {
  position: absolute;
  z-index: 1;
  top: 34.36%;
  left: 0;
  right: 0;
}
/* The app's alert dims the whole screen. The frames carry their own dimming, so the rest of the screen dims as the
   last one gives way to it, and stays dim where nothing moves. */
.site .bp-scrim {
  position: absolute;
  inset: 0;
  background: rgb(4 4 10 / 0.6);
}
.ls-on .site .ls .bp-scrim {
  opacity: 0;
}
.ls-on .site .ls.play .bp-scrim {
  animation: bp-dim var(--o) ease-in-out var(--d) both;
}
@keyframes bp-dim {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}
/* A fingertip on the scrubber: on Kids unlock rewards it drags from the first reward's thumb to Arcade trip's (measured
   centres, % of the width); on the battle pass phone script moves it. */
.site .bp-finger {
  position: absolute;
  z-index: 3;
  top: 89.7%;
  left: 22.9%;
  width: 12%;
  aspect-ratio: 1;
  translate: -50% -50%;
  border-radius: 50%;
  background: rgb(255 255 255 / 0.3);
  box-shadow:
    0 0 0 2px var(--ink),
    inset 0 0 0 3px rgb(255 255 255 / 0.85);
  opacity: 0;
  pointer-events: none;
}
.ls-on .site .ls.play .bp-finger {
  animation: bp-drag 1.8s linear var(--d) both;
}
@keyframes bp-drag {
  0% {
    left: 22.9%;
    opacity: 0;
    scale: 0.7;
  }
  10% {
    left: 22.9%;
    opacity: 1;
    scale: 1;
  }
  85% {
    left: 42%;
    opacity: 1;
    scale: 1;
  }
  100% {
    left: 42%;
    opacity: 0;
    scale: 0.85;
  }
}
/* XP progresses their battle pass (Gate P comment, 2026-10-21: the kid's battle pass pop-up, "interactive so it looks
   like it's an actual iPhone screenshot but you can scroll through it yourself"): Sam's sheet in a phone. Each tier's
   frame is a crop of the sheet's middle (points 290 to 660 of 844) laid back over the phone at its own place; the
   scrubber takes a drag, the app's arrows step, and the arrow keys work too (motion.js). */
.site .bp-tier {
  position: absolute;
  left: 0;
  top: 34.36%;
}
.site .bp-tier[hidden] {
  display: none;
}
.site .bp-drag {
  position: absolute;
  z-index: 2;
  left: 16.8%;
  top: 70.4%;
  width: 66.4%;
  height: 6.5%;
  cursor: ew-resize;
  touch-action: pan-y;
}
.site .bp-step {
  position: absolute;
  z-index: 2;
  top: 71.17%;
  width: 10.82%;
  height: 5%;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
}
/* On a phone the app's arrows are drawn about 24 px; an invisible ring takes the tap to about 44 px tall without
   reaching the first or last reward's spot on the bar. */
.site .bp-step::before {
  content: "";
  position: absolute;
  inset: -11px -6px;
}
.site .bp-step.prev {
  left: 5.97%;
}
.site .bp-step.next {
  left: 83.2%;
}
.site :is(.bp-drag, .bp-step):focus-visible {
  outline: 3px solid var(--gold);
  outline-offset: 2px;
  border-radius: 8px;
}
.site .bp-sheet .bp-finger {
  top: 73.7%;
  left: 42%;
  transition: opacity 0.25s;
}
.site .bp-sheet .bp-finger.on {
  opacity: 1;
}
/* The ladder's rows start at the top, so each badge stays on its frame instead of the grid stretching it to the tallest
   step. */
.site .ladder .devlink {
  align-content: start;
}
/* The battle pass phone stands upright, so a drag along its bar goes straight across, and larger on a wide screen. It
   stands whole above the band's edge instead of sinking into it (Gate P comment, 2026-10-22: it bled into the XP bar
   below), and each tier frame is laid flat on its screen, without the screenshot edge every app shot gets (the same
   comment: "an awkward outline box around the battle pass track"). The screenshot under the frames goes without it
   too, as on Kids unlock rewards: with the 2 px edge it drew 4 px narrower than the frame over it, so the sheet's
   outline stepped in below the bar (Shahrum, 2026-10-22). */
.site #example .bp-sheet .gdev {
  rotate: 0deg;
}
.site #example .bp-sheet .sink {
  aspect-ratio: auto;
  clip-path: none;
  padding-bottom: 56px;
}
.site .bp-sheet .dev-screen > img {
  border: 0;
  border-radius: 0;
  background: none;
  box-shadow: none;
}
@container (min-width: 900px) {
  .site #example .bp-sheet {
    width: 320px;
  }
  .site #example .bp-sheet .gdev {
    --w: 300px;
  }
}
/* How to use the battle pass phone: the hint beside the words (Gate P comment, 2026-10-21: the Kid tag sat apart from
   its phone over the hint), and a Replay button that plays the fingertip's tour again ("a replay animation button"),
   on the Kid tag's row over the phone's right corner (Gate P comment, 2026-10-22: by the words it sat too far from the
   phone). It is drawn 32 px; an invisible ring gives a 44 px tap. */
.site .bp-try[hidden],
.site .bp-replay[hidden] {
  display: none;
}
.site .bp-sheet > :is(.dev-tag, .bp-replay) {
  grid-area: 1 / 1;
}
.site .feature .bp-hint {
  margin: 0;
  font-size: 14px;
  color: var(--body-80);
}
.site .bp-replay {
  position: relative;
  z-index: 4;
  justify-self: end;
  align-self: center;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  min-height: 32px;
  padding: 0 12px 0 10px;
  border: var(--outline);
  border-radius: var(--r);
  background: var(--surface);
  color: var(--cream);
  box-shadow: var(--edge);
  font: 700 14px / 1 var(--text);
  cursor: pointer;
}
.site .bp-replay::before {
  content: "";
  position: absolute;
  inset: -6px -2px;
}
.site .bp-replay svg {
  flex: none;
}
.site .bp-replay:focus-visible {
  outline: 3px solid var(--gold);
  outline-offset: 2px;
}
/* The card and the phone stand together to the right of the words (Gate P comment, 2026-10-22: "slide them over more
   to the right of this entire area"), the card on the phone's left. Where the words would get too narrow for that, they
   go above and the pair sits under them, side by side; on a phone the card stacks under the phone. */
@container (min-width: 900px) {
  .site .feature > div:has(> .bp-try) {
    grid-template-columns: minmax(0, 1fr);
  }
  .site .feature > div:has(> .bp-try) > .viz {
    grid-column: 1;
    grid-row: auto;
  }
  .site .feature > div > .bp-try {
    grid-column: 1;
    align-self: start;
  }
}
@container (min-width: 1076px) {
  .site .feature > div:has(> .bp-try) {
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-rows: auto auto auto 1fr;
    column-gap: 40px;
  }
  .site .feature > div:has(> .bp-try) > .viz {
    grid-column: 2;
    grid-row: 1 / span 4;
  }
}
.site .bp-viz {
  position: relative;
  row-gap: 20px;
}
@container (min-width: 720px) {
  .site .bp-viz {
    grid-template-columns: auto auto;
    column-gap: 40px;
    align-items: center;
    justify-content: center;
  }
  .site .bp-side {
    order: -1;
  }
}

/* The reward the phone shows (Gate P comment, 2026-10-22: the section was one phone and nothing else; he picked a card
   that follows the drag, with the three states in it): the app's own icon, its price, and Given, Ready to ask and
   Locked as a legend, the one it is in lit. The app's arrows flank it, smaller than the card, so it reads as the
   phone's card blown up (the same day: "put those arrows alongside the box itself, maybe slightly smaller"). */
.site .bp-side[hidden] {
  display: none;
}
.site .bp-side {
  display: grid;
  grid-template-columns: 30px minmax(0, 1fr) 30px;
  align-items: center;
  gap: 10px;
  width: min(100%, 352px);
}
@container (min-width: 720px) {
  .site .bp-side {
    width: 352px;
  }
}
.site .bp-card {
  display: grid;
  gap: 14px;
  padding: 16px 14px 14px;
  border: var(--outline);
  border-radius: 6px;
  background: var(--surface);
  box-shadow: var(--edge);
  outline: 2px solid var(--cream);
  outline-offset: 3px;
}
.site .feature .bp-card p {
  margin: 0;
}
.site .feature .bp-card-h {
  font: 400 13px / 1 var(--display);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--cream);
}
.site .bp-card-main {
  display: flex;
  align-items: center;
  min-height: 76px;
  gap: 14px;
}
.site .bp-card-icon {
  flex: none;
  width: 48px;
  height: 48px;
}
.site .feature .bp-card-main p {
  display: grid;
  gap: 4px;
}
.site .bp-card-name {
  font-size: 19px;
  line-height: 1.25;
  color: var(--cream);
}
.site .bp-card-pos {
  font-size: 14px;
  color: var(--mute);
}
/* A key, not buttons: each mark and its name, the one the reward is in lit, so the three fit one row in the card. */
.site .bp-states {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 8px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.site .bp-states li {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font: 700 13px / 1.2 var(--text);
  color: var(--mute);
  opacity: 0.45;
}
.site .bp-states li.on {
  color: var(--cream);
  opacity: 1;
}
.site .bp-states li::before {
  content: "";
  flex: none;
  width: 14px;
  height: 14px;
  border: 2px solid var(--ink);
  border-radius: 3px;
  background: var(--ahead);
}
.site .bp-states [data-s="given"]::before {
  background:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 7 6' shape-rendering='crispEdges'%3E%3Cpath fill='%23191121' d='M6 0h1v1H6zM5 1h2v1H5zM0 2h1v1H0zM4 2h2v1H4zM0 3h2v1H0zM3 3h2v1H3zM1 4h3v1H1zM2 5h1v1H2z'/%3E%3C/svg%3E")
    center / 8px 7px no-repeat #5fd38a;
}
.site .bp-states [data-s="ready"]::before {
  background: var(--gold);
  box-shadow: 0 0 8px rgb(255 210 74 / 0.7);
}
.site .feature .bp-card-note {
  min-height: 3em;
  font-size: 15px;
  line-height: 1.5;
  color: var(--body);
}
/* On a phone the phone is the page's width, so the card would only repeat its reward card at the same size: the phone
   stands alone, with its own arrows and drag (Gate P comment, 2026-10-22: "only show the iPhone itself ... the zoomed
   in box was added to the desktop view since the iPhone is smaller"). The slider's value text still names each reward. */
@container (max-width: 719px) {
  .site .bp-side,
  .site .bp-focus {
    display: none;
  }
}
/* The app's arrows as its sheet draws them: an ink-edged square in the card's colour, a cream chevron. Drawn 30 px;
   an invisible ring gives a 44 px tap. */
.site .bp-arrow {
  position: relative;
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  padding: 0;
  border: var(--outline);
  border-radius: 6px;
  background: var(--surface);
  box-shadow: var(--edge);
  color: var(--cream);
  cursor: pointer;
}
.site .bp-arrow::before {
  content: "";
  position: absolute;
  inset: -7px;
}
.site .bp-arrow svg {
  width: 13px;
  height: 13px;
}
.site .bp-arrow:active {
  translate: 0 2px;
  box-shadow: 0 1px 0 var(--ink);
}
.site .bp-arrow:focus-visible {
  outline: 3px solid var(--gold);
  outline-offset: 2px;
}
/* What ties the card to the phone: the same cream outline on the phone's own reward card as on the card, sized to
   each tier's card (motion.js). Lines drawn between them read as awkward (Gate P comment, 2026-10-22). */
.site .bp-focus {
  position: absolute;
  z-index: 1;
  top: 44.6%;
  left: 5.5%;
  right: 5.5%;
  height: 21%;
  border: 2px solid var(--cream);
  border-radius: 6px;
  box-shadow: 0 0 12px rgb(248 239 168 / 0.45);
  pointer-events: none;
}
.site .bp-viz:has(> .bp-side[hidden]) .bp-focus {
  display: none;
}
/* Who holds each device, in their colour, on every device the page shows (Gate P comment, 2026-10-21: "use that
   consistently throughout this page"): the grown-up's orange and the kid's blue, edged in ink, as on the hero and the
   pairing row, which light theirs only while that device acts. */
.site .gdev.who-grown {
  --lit: var(--orange);
}
.site .gdev.who-kid {
  --lit: #6aa3ff;
}
.site .gdev:is(.who-grown, .who-kid)::after {
  content: "";
  position: absolute;
  inset: -8px;
  border: 4px solid var(--lit);
  border-radius: calc(var(--w) * 0.155 + 8px);
  box-shadow:
    0 0 0 2px var(--ink),
    inset 0 0 0 2px var(--ink),
    0 0 22px var(--lit);
  pointer-events: none;
}
/* The tag clears the ring. */
.site .devlink:has(> .gdev:is(.who-grown, .who-kid)) {
  gap: 16px;
}
/* From 700 px the Mission report is on an iPad, whose corners are tighter than a phone's, so its ring follows them;
   its tag sits above the ring as on Achievements, not pulled down onto the frame (Gate P comment, 2026-10-21: the
   outline missed the iPad and the badge sat awkwardly). */
@container (min-width: 700px) {
  .site .mr-shot .gdev.who-kid::after {
    border-radius: calc(var(--w) * 0.06 + 8px);
  }
}
/* Reduced motion still plays the page's clips, the screens and celebrations drawn from the app, as a video would
   (Shahrum, 2026-10-23: a visitor whose computer asks for less motion saw nothing move at all). What it drops in them
   is the confetti, the sparkles, the loot box's shake and its white flash. The reward tracks between sections, the
   plans' season ladder and smooth scrolling still hold still. */
@media (prefers-reduced-motion: reduce) {
  .site .duo .bp-bits,
  .site .kspk,
  .site .cz.pops .spk {
    display: none;
  }
  .lvl.lv-run :is(.lv-conf, .lv-shake, .lv-flash) {
    animation: none;
  }
}
