/* ============================================================================
   Frogi landing. Design system lifted from the app handoff (Nunito, Paper/Ink/
   Green, red reserved for the tongue). The frog is the interactive mascot.
   ========================================================================= */
:root {
  --paper: #fbfaf6;
  --ink: #14231a;
  --ink-press: #0c150f;
  --green: #2cb454;
  --green-light: #35bf5d;
  --green-dark: #23a54b;
  --green-deep: #1e8c42;
  --green-tint: #e6f4ea;
  --green-text: #1e7a3c;
  --red: #ff4a45;
  --card: #ffffff;
  --fill: #f3f3ef;
  --fill-alt: #f1f1ec;
  --hairline: #e9e9e4;
  --border: #c9cbc4;
  --muted: #5f6359;
  --muted-soft: #6e7269;
  --font: "Nunito", ui-rounded, -apple-system, system-ui, sans-serif;
  --mono: ui-monospace, SFMono-Regular, Menlo, monospace;
  --shadow-card: 0 6px 16px rgba(20, 35, 26, 0.06);
  /* raised control, Workbox convention: the hairline is drawn by the shadow
     (border stays 0) so it never doubles up with a CSS border */
  --shadow-control: 0 0 0 1px rgba(20, 35, 26, 0.12),
    inset 0 1px 0 rgba(255, 255, 255, 0.9), 0 2px 5px rgba(20, 35, 26, 0.08);
  --shadow-control-hover: 0 0 0 1px rgba(20, 35, 26, 0.2),
    inset 0 1px 0 rgba(255, 255, 255, 0.9), 0 2px 5px rgba(20, 35, 26, 0.1);
  --shadow-pill: 0 8px 20px rgba(20, 35, 26, 0.18);
  --ease-pop: cubic-bezier(0.2, 1.5, 0.4, 1);
  --ease-swim: cubic-bezier(0.22, 0.86, 0.3, 1);
}
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}
html {
  -webkit-text-size-adjust: 100%;
}
body {
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font);
  font-weight: 700;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  font-variant-numeric: tabular-nums;
  overflow-x: hidden;
}
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
}
b {
  color: var(--ink);
  font-weight: 900;
}
::selection {
  background: var(--green-tint);
}

/* ---------- top bar ---------- */
.top {
  position: sticky;
  top: 0;
  z-index: 20;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 14px 22px;
  background: color-mix(in srgb, var(--paper) 86%, transparent);
  -webkit-backdrop-filter: saturate(1.1) blur(8px);
  backdrop-filter: saturate(1.1) blur(8px);
}
.brand {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  text-decoration: none;
  color: var(--ink);
}
.brand-mark {
  width: 26px;
  height: 26px;
  display: block;
}
.brand-mark svg {
  width: 100%;
  height: 100%;
  display: block;
}
.brand-word {
  display: inline-flex;
  /* baseline, not flex-end: flex-end drops the eye to the bottom of the line
     box, which sits a descender below where the letters actually rest */
  align-items: baseline;
  font-weight: 900;
  font-size: 31px;
  letter-spacing: -0.055em;
  color: var(--ink);
}
.brand-word.small {
  font-size: 18px;
}

/* ---------- Frogi wordmark: the "i" is a frog eye ----------
   Pixel-matched to the design lockup (the i's dot is an eye: white circle,
   4px green ring, ink pupil, on a rounded ink stem). All in em so it scales. */
.fw-i {
  position: relative;
  display: inline-block;
  width: 0.519em;
  height: 1em;
  margin-left: -0.019em;
  flex: none;
}
.fw-i i {
  position: absolute;
  display: block;
}
.fw-i .st {
  left: 0.154em;
  bottom: 0;
  width: 0.212em;
  height: 0.5em;
  border-radius: 0.096em;
  background: var(--ink);
}
.fw-i .ey {
  left: -0.038em;
  top: -0.077em;
  width: 0.615em;
  height: 0.615em;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 0 0 0.077em var(--green);
}
.fw-i .pu {
  left: 0.144em;
  top: 0.125em;
  width: 0.25em;
  height: 0.25em;
  border-radius: 50%;
  background: var(--ink);
}
.on-ink .fw-i .st,
.on-ink .fw-i .pu {
  background: #fff;
}
.on-ink .fw-i .ey {
  background: var(--ink);
}
.counter {
  /* centred on the viewport, not on whatever the brand and the right side
     happen to measure */
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  font: 700 12px/1 var(--mono);
  letter-spacing: 1.2px;
  text-transform: uppercase;
  color: var(--muted-soft);
  white-space: nowrap;
  pointer-events: none;
}
.counter #counter-n {
  color: var(--ink);
  font-weight: 800;
}
/* a raised white control, so it reads as clickable: it now goes to the
   waitlist rather than being a label that only looked like a button */
.coming {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  border: 0;
  font-weight: 800;
  font-size: 14.5px;
  color: var(--ink);
  text-decoration: none;
  /* the same fill as the mute button beside it, so the two header controls
     read as one pair rather than two different kinds of thing */
  background: var(--fill);
  border-radius: 999px;
  padding: 10px 17px;
  white-space: nowrap;
  box-shadow: var(--shadow-control);
  transition: box-shadow 0.16s var(--ease-swim), transform 0.12s ease;
}
.coming:hover {
  box-shadow: var(--shadow-control-hover);
}
.coming:active {
  transform: scale(0.96);
}
.coming:focus-visible {
  outline: 2px solid var(--green);
  outline-offset: 3px;
}
.coming-icon {
  display: inline-flex;
  align-items: center;
  flex: none;
  color: var(--ink);
}
.coming-icon svg {
  width: auto;
  height: 14px;
  display: block;
}
/* slot-text splits this into per-character cells and animates its own width,
   so the box is reserved for the longest label the button ever shows */
.lockable {
  display: inline-flex;
  justify-content: flex-start;
  min-width: 10.2ch;
}
@media (prefers-reduced-motion: reduce) {
  .coming {
    transition: box-shadow 0.16s linear;
  }
  .coming:active {
    transform: none;
  }
}
@media (max-width: 620px) {
  .counter {
    display: none;
  }
}

/* ---------- layout ---------- */
main {
  max-width: 500px;
  margin: 0 auto;
  padding: 0 24px;
}
.hero {
  /* the mascot leads, so give him room to arrive; the bottom pad separates
     the hero from the first band on whitespace alone */
  padding: 118px 0 76px;
  text-align: center;
}
.kicker {
  font: 700 11px/1 var(--mono);
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: var(--muted-soft);
}
.headline {
  display: inline-flex;
  align-items: flex-end;
  margin-top: 22px;
  font-weight: 900;
  font-size: 52px;
  line-height: 1;
  letter-spacing: -0.044em;
  color: var(--ink);
}
.deck {
  margin: 18px auto 0;
  max-width: 17ch;
  font-weight: 700;
  font-size: 22px;
  line-height: 1.3;
  letter-spacing: -0.01em;
}
.deck .dim {
  color: #8c9088;
}
.deck .ink {
  color: var(--ink);
}

/* ---------- the frog stage ---------- */
/* the frog sits full-body directly on the paper (no card around him) */
.frog-card {
  position: relative;
  margin: 0 auto;
  width: 100%;
  max-width: 195px; /* 0.65 of the original 300 */
  padding: 8px 12px 0;
  background: none;
  box-shadow: none;
}
.frog-btn {
  display: block;
  width: 100%;
  border: 0;
  background: none;
  padding: 0;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}
.frog {
  display: block;
  width: 100%;
  height: auto;
  overflow: visible; /* full body already inside the viewBox */
  transform-origin: 50% 88%; /* he squashes onto his feet, not his middle */
  transition: transform 0.09s cubic-bezier(0.23, 1, 0.32, 1);
}
/* on press, not on release: the finger is still down when he gives */
.frog-btn:active .frog {
  transform: scale(0.955);
}

/* frog part transitions (mood + catch are driven by app.js) */
.pupil {
  /* the rAF tracker retargets this every frame, so it has to be short
     enough not to lag behind the fly it is following */
  transition: transform 0.08s linear;
}
.lid {
  transition: transform 0.13s var(--ease-swim);
  transform: translateY(-300px); /* parked above the eye */
}
#frogBody {
  transition: transform 0.2s var(--ease-pop);
  transform-box: fill-box;
  transform-origin: bottom center;
}
/* ---- the mouth ----
   Opening is a jaw drop rather than a cross-fade: the open mouth grows from a
   slit with its top edge pinned, so you never see two mouths at once. The
   selector covers all three by id, because #mouthFlat is a rect and the old
   `#mouth path` rule silently skipped it. */
#mouthSmile,
#mouthFlat,
#mouthOpen {
  transform-box: fill-box;
}
#mouthSmile,
#mouthFlat {
  transform-origin: 50% 50%;
  transition: opacity 0.1s linear, transform 0.26s var(--ease-pop);
}
#mouthOpen {
  transform-origin: 50% 16%;
  transform: scale(0.34, 0.06);
  transition: opacity 0.09s linear,
    transform 0.2s cubic-bezier(0.34, 1.3, 0.5, 1);
}
[data-mouth="open"] #mouthOpen {
  transform: none;
}
/* the closed shapes give way as the jaw drops, then pop back */
[data-mouth="open"] #mouthSmile,
[data-mouth="open"] #mouthFlat {
  transform: scaleY(0.35);
}
@media (prefers-reduced-motion: reduce) {
  #mouthSmile,
  #mouthFlat,
  #mouthOpen {
    transition: opacity 0.1s linear;
    transform: none;
  }
}
/* tongue fires by scaling up from the mouth end */
#tongueScale {
  transform: scaleY(0);
  transform-box: fill-box;
  transform-origin: bottom center;
  transition: transform 0.14s cubic-bezier(0.3, 0, 0.3, 1);
}
#tongue {
  transition: opacity 0.1s linear;
}
#fly {
  transition: transform 0.32s var(--ease-swim), opacity 0.18s linear;
}

.tapme {
  position: absolute;
  left: 50%;
  top: -20px;
  transform: translateX(-50%) rotate(-5deg);
  font-weight: 800;
  font-size: 15px;
  color: var(--muted);
  transition: opacity 0.3s var(--ease-swim);
}
.tapme-arrow {
  display: inline-block;
  transform: translateY(1px);
}
.tapme.gone {
  opacity: 0;
  pointer-events: none;
  visibility: hidden;
}

/* ---------- buttons + waitlist ---------- */
.waitlist {
  display: flex;
  gap: 8px;
  margin: 22px auto 0;
  max-width: 400px;
  position: relative;
  /* the header is sticky, so an #waitlist jump would otherwise land underneath it */
  scroll-margin-top: 96px;
}
/* ---- coach mark ----
   Pressing "Coming soon" rings the form rather than scrolling to it: the ring
   sweeps in a touch wide, settles onto the field, holds, then leaves. */
.waitlist.coach {
  /* above the sticky header (20) for the duration, so the scrim covers the
     whole page and not just what happens to sit under this section */
  z-index: 30;
}
.waitlist.coach::before {
  content: "";
  position: absolute;
  inset: -9px;
  border-radius: 36px;
  /* the second layer is the scrim: one enormous spread darkens everything
     outside this box, so the ring is literally a hole punched in it. The
     form's own children paint after ::before, so they stay lit. */
  box-shadow: 0 0 0 2px var(--green), 0 0 0 100vmax rgba(20, 35, 26, 0.4);
  pointer-events: none;
  opacity: 0;
  animation: coachRing 2.2s var(--ease-swim) forwards;
}
@keyframes coachRing {
  0% {
    opacity: 0;
    transform: scale(1.06);
  }
  18% {
    opacity: 1;
    transform: scale(1);
  }
  70% {
    opacity: 1;
    transform: scale(1);
  }
  100% {
    opacity: 0;
    transform: scale(1.02);
  }
}
@media (prefers-reduced-motion: reduce) {
  .waitlist.coach::before {
    animation: coachHold 2.2s linear forwards;
  }
  @keyframes coachHold {
    0%,
    80% {
      opacity: 1;
      transform: none;
    }
    100% {
      opacity: 0;
      transform: none;
    }
  }
}
/* bait for bots. Off-screen rather than display:none, since some bots skip
   what is not rendered, and out of the tab order for everyone else. */
.wl-trap {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}
/* only present when a send actually failed, so it can never be a false alarm */
.waitlist[data-error]::after {
  content: attr(data-error);
  position: absolute;
  top: calc(100% + 8px);
  left: 22px;
  font-weight: 700;
  font-size: 13px;
  color: var(--red);
}
.wl-input {
  flex: 1 1 auto;
  min-width: 0;
  height: 56px;
  border: 1.5px solid var(--border);
  border-radius: 28px;
  background: var(--card);
  padding: 0 20px;
  font-family: var(--font);
  font-weight: 700;
  font-size: 16px;
  color: var(--ink);
  outline: none;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.wl-input::placeholder {
  color: var(--muted-soft);
  font-weight: 600;
}
.wl-input:focus {
  border-color: var(--green);
  box-shadow: 0 0 0 4px var(--green-tint);
}
.btn {
  font-family: var(--font);
  cursor: pointer;
  border: 0;
}
.btn-primary {
  flex: 0 0 auto;
  height: 56px;
  padding: 0 24px;
  border-radius: 28px;
  background: var(--ink);
  color: #fff;
  font-weight: 900;
  font-size: 17px;
  transition: transform 0.09s ease, background-color 0.09s ease;
}
.btn-primary:active {
  transform: scale(0.975);
  background: var(--ink-press);
}
.trust {
  margin: 12px auto 0;
  font-weight: 700;
  font-size: 13.5px;
  color: var(--muted);
}
.waitlist.done {
  justify-content: center;
  font-weight: 800;
  color: var(--green-text);
}

/* ---------- bands (story sections) ---------- */
.band {
  padding: 112px 0 10px;
  text-align: left;
}
.mono-kicker {
  font: 700 11px/1 var(--mono);
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: var(--muted-soft);
  margin-bottom: 14px;
}
.band-head {
  font-weight: 900;
  font-size: 33px;
  line-height: 1.04;
  letter-spacing: -1.3px;
}
.band-copy {
  margin-top: 14px;
  font-weight: 700;
  font-size: 18px;
  line-height: 1.45;
  color: var(--muted);
  max-width: 34ch;
}
.band-copy.center {
  margin-inline: auto;
  text-align: center;
}
.chips {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 20px;
  list-style: none;
}
.chip {
  background: var(--fill);
  color: var(--ink);
  font-weight: 800;
  font-size: 14px;
  padding: 9px 15px;
  border-radius: 16px;
}

/* poster (the cost) */
.band-poster {
  text-align: center;
  padding-top: 118px;
}
.poster {
  font-weight: 900;
  font-size: clamp(46px, 15vw, 76px);
  line-height: 0.9;
  letter-spacing: -3px;
  color: var(--green);
  white-space: nowrap;
}

/* ---------- closer ---------- */
.closer {
  text-align: center;
  /* the flight lane below already gives the section its air, so the padding
     only has to break away from the FAQ rather than open a second gap */
  padding: 26px 0 30px;
}
.closer-head {
  font-weight: 900;
  font-size: 38px;
  line-height: 1.02;
  letter-spacing: -1.6px;
  margin-bottom: 22px;
}

/* ---------- footer ---------- */
/* two tiers, both using both edges: brand and links on top, the small print
   and the signature underneath. A grid rather than a wrapping flex row, so
   the split is deliberate instead of whatever happens to fit. */
.foot {
  max-width: 500px;
  margin: 40px auto 0;
  padding: 26px 24px 40px;
  border-top: 1px solid var(--hairline);
  display: grid;
  grid-template-columns: auto auto;
  justify-content: space-between;
  align-items: center;
  gap: 14px 20px;
}
.foot-nav,
.foot-copy {
  justify-self: end;
}
@media (max-width: 460px) {
  /* one column, everything left: two columns would crowd at this width */
  .foot {
    grid-template-columns: auto;
    justify-content: start;
    gap: 10px;
  }
  .foot-nav,
  .foot-copy {
    justify-self: start;
  }
}
.foot-sign {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  /* a 23px row is too small to tap: pad the hit area out to ~41px and pull
     the same amount back off the margin so the footer row does not grow */
  padding-block: 9px;
  margin-block: -9px;
  font: 700 11px/1 var(--mono);
  letter-spacing: 1.2px;
  color: var(--muted-soft);
  /* the underline is always there, just transparent, so it fades in on hover
     rather than snapping on and shifting the baseline */
  text-decoration: underline;
  text-decoration-color: transparent;
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
  transition: color 0.15s linear, text-decoration-color 0.2s var(--ease-swim);
}
.foot-sign b {
  /* the global b is ink 900, which would shout next to the copyright */
  font-weight: 700;
  color: var(--muted);
  transition: color 0.15s linear;
}
.foot-sign:hover,
.foot-sign:focus-visible {
  color: var(--muted);
  text-decoration-color: currentColor;
}
.foot-sign:hover b,
.foot-sign:focus-visible b {
  color: var(--ink);
}
/* the frog and the card are not part of the underlined label */
.foot-sign-frog,
.sign-card {
  text-decoration: none;
}
.foot-sign:focus-visible {
  outline: 2px solid var(--green);
  outline-offset: 4px;
  border-radius: 6px;
}
/* ---- the signature's hover preview ----
   The label says "AGC" but the link goes to an X profile, so show what is on
   the other end before the click. It opens upward: the footer is the last
   thing on the page and there is nothing below it to open into. */
.foot-sign {
  position: relative;
}
.sign-card {
  position: absolute;
  left: 0;
  bottom: calc(100% + 10px);
  z-index: 5;
  display: flex;
  flex-direction: column;
  gap: 9px;
  width: 252px;
  padding: 13px 14px 12px;
  border-radius: 16px;
  background: color-mix(in srgb, var(--card) 97%, transparent);
  -webkit-backdrop-filter: saturate(1.1) blur(10px);
  backdrop-filter: saturate(1.1) blur(10px);
  box-shadow: var(--shadow-card), 0 0 0 1px rgba(20, 35, 26, 0.07);
  pointer-events: none;
  opacity: 0;
  transform: translateY(5px) scale(0.97);
  transform-origin: 0 100%;
  transition: opacity 0.14s linear, transform 0.22s var(--ease-swim);
}
.sign-card-top {
  display: flex;
  align-items: center;
  gap: 10px;
}
.sign-card-pic {
  width: 44px;
  height: 44px;
  border-radius: 50%;
  object-fit: cover;
  flex: none;
}
.sign-card-txt {
  display: flex;
  flex-direction: column;
  gap: 3px;
  text-align: left;
  margin-right: auto;
}
.sign-card-bio {
  font-weight: 700;
  font-size: 12.5px;
  line-height: 1.4;
  letter-spacing: -0.005em;
  color: var(--muted);
  text-align: left;
}
.sign-card-stats {
  display: flex;
  gap: 14px;
  font: 700 11px/1 var(--mono);
  letter-spacing: 0.4px;
  color: var(--muted-soft);
}
.sign-card-stats b {
  font-weight: 800;
  color: var(--ink);
}
.sign-card-name {
  font-weight: 800;
  font-size: 13px;
  letter-spacing: -0.01em;
  color: var(--ink);
}
.sign-card-at {
  font: 700 11px/1 var(--mono);
  letter-spacing: 0.6px;
  color: var(--muted-soft);
}
.sign-card-x {
  display: flex;
  margin-left: 2px;
  color: var(--muted-soft);
}
.sign-card-x svg {
  width: 13px;
  height: 13px;
  display: block;
}
/* pointer only: on touch the tap already opens the profile */
@media (hover: hover) and (pointer: fine) {
  .foot-sign:hover .sign-card {
    opacity: 1;
    transform: none;
  }
}
/* keyboard users get it too, without needing a pointer */
.foot-sign:focus-visible .sign-card {
  opacity: 1;
  transform: none;
}
@media (prefers-reduced-motion: reduce) {
  .sign-card {
    transition: opacity 0.12s linear;
    transform: none;
  }
}

/* the maker's mark: sized by ratio so it reserves its box before it loads */
.foot-sign-frog {
  width: 31px;
  aspect-ratio: 2160 / 2056;
  /* he is the signature, not a headline: he sits back until pointed at */
  opacity: 0.82;
  /* optical, not geometric: his box centres fine, but the smoke plume is thin
     ink filling the top while the body is dense and low, which puts his
     visible mass 5.1% under the box centre and reads as sitting below the
     type. Lift him by that much so the body lands on the text's axis. */
  transform: translateY(-5.1%);
}
@media (hover: hover) and (pointer: fine) {
  .foot-sign-frog {
    transition: transform 0.22s var(--ease-pop), opacity 0.15s linear;
  }
  .foot-sign:hover .foot-sign-frog {
    opacity: 1;
    transform: translateY(calc(-5.1% - 2px)) rotate(-5deg);
  }
}
@media (prefers-reduced-motion: reduce) {
  .foot-sign:hover .foot-sign-frog {
    transform: translateY(-5.1%);
  }
}
@media (prefers-reduced-motion: reduce) {
  .foot-sign-frog {
    transition: opacity 0.15s linear;
  }
  .foot-sign:hover .foot-sign-frog {
    transform: none;
  }
}
.foot-copy {
  font: 700 11px/1 var(--mono);
  letter-spacing: 1.2px;
  color: var(--muted-soft);
}

/* ---------- motion ---------- */
.rise {
  opacity: 0;
  transform: translateY(14px);
  animation: rise 0.5s var(--ease-swim) forwards;
  animation-delay: calc(var(--d) * 70ms);
}
@keyframes rise {
  to {
    opacity: 1;
    transform: none;
  }
}
.reveal {
  opacity: 0;
  transform: translateY(18px);
  transition: opacity 0.5s var(--ease-swim), transform 0.5s var(--ease-swim);
}
.reveal.in {
  opacity: 1;
  transform: none;
}

@media (prefers-reduced-motion: reduce) {
  .rise,
  .reveal {
    opacity: 1;
    transform: none;
    animation: none;
    transition: none;
  }
  /* reduced motion means drop movement, not drop crossfades */
  .frog *,
  .frog {
    transition-property: opacity;
  }
}

/* ---------- small screens ---------- */
@media (max-width: 480px) {
  .headline {
    font-size: 44px;
  }
  .deck {
    font-size: 18px;
  }
  .band-head {
    font-size: 29px;
  }
  .closer-head {
    font-size: 32px;
  }
}

/* ---------- top-right: mute toggle (framework pattern) + coming pill ---------- */
.top-right {
  display: inline-flex;
  align-items: center;
  gap: 10px;
}
.mute-btn {
  appearance: none;
  border: 0;
  background: var(--fill);
  color: var(--ink);
  width: 34px;
  height: 34px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: transform 0.09s ease, background-color 0.15s ease;
}
.mute-btn:active {
  transform: scale(0.96);
}
.mute-btn svg {
  width: 20px;
  height: 20px;
}
.mute-btn .ic-off {
  display: none;
}
.mute-btn.muted .ic-on {
  display: none;
}
.mute-btn.muted .ic-off {
  display: block;
}

/* ============================================================================
   Pond -> editor, in the design's 402-wide frame, cropped to 752 tall (scaled to
   fit). The frog leaps with the design's fgPondLeap; chrome cross-fades.
   ========================================================================= */
.pond-device {
  position: relative;
  width: 100%;
  aspect-ratio: 402 / 752;
  margin: 26px auto 0;
  border-radius: 52px;
  overflow: hidden;
  background: var(--paper);
  box-shadow: var(--shadow-card), 0 0 0 1px rgba(20, 35, 26, 0.05);
}
.frame402 {
  position: absolute;
  top: 0;
  left: 0;
  width: 402px;
  height: 752px;
  transform-origin: top left;
  transform: scale(var(--fs, 0.776)); /* JS keeps this exact = width/402 */
}

/* ---- pond chrome: rule rows + hint (fade out on the leap) ---- */
.pchrome {
  position: absolute;
  inset: 0;
  transition: opacity 0.26s var(--ease-swim);
}
.pond-device.is-editor .pchrome {
  opacity: 0;
  pointer-events: none;
}
.pond-head {
  position: absolute;
  left: 0;
  right: 0;
  top: 60px;
  text-align: center;
  font-weight: 900;
  font-size: 20px;
  letter-spacing: -0.4px;
  color: var(--ink);
}
.pond-rows {
  position: absolute;
  left: 26px;
  right: 26px;
  top: 116px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
/* rule row (prototype): alias + "max X a day", usage detail, progress fill, toggle */
.rrow {
  position: relative;
  height: 74px;
  border-radius: 20px;
  overflow: hidden;
  background: var(--green);
}
.rrow.caught {
  background: var(--red);
}
.rrow.paused {
  background: #e4e4de;
}
.rrow-fill {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  background: rgba(20, 35, 26, 0.1);
}
.rrow-body {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 3px;
  padding: 0 82px 0 20px;
}
.rrow-top {
  display: flex;
  align-items: baseline;
  gap: 8px;
}
.rrow-name {
  font-weight: 900;
  font-size: 20px;
  letter-spacing: -0.02em;
  color: var(--ink);
}
.rrow-every {
  font-weight: 800;
  font-size: 13px;
  color: rgba(20, 35, 26, 0.6);
}
.rrow-detail {
  font-weight: 700;
  font-size: 13px;
  color: rgba(20, 35, 26, 0.62);
}
.rrow.paused .rrow-every,
.rrow.paused .rrow-detail {
  color: var(--muted-soft);
}
.rrow-tog {
  position: absolute;
  right: 18px;
  top: 50%;
  margin-top: -15px;
  width: 52px;
  height: 30px;
  border-radius: 15px;
  background: #14231a;
}
.rrow.paused .rrow-tog {
  background: #c9cbc4;
}
.rrow-tog::after {
  content: "";
  position: absolute;
  top: 3px;
  left: 25px;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  background: #fff;
}
.rrow.paused .rrow-tog::after {
  left: 3px;
}
.pc-hint {
  position: absolute;
  left: 0;
  right: 0;
  top: 478px;
  text-align: center;
  font: 700 13px/1 var(--mono);
  letter-spacing: 1.6px;
  color: var(--muted-soft);
}

/* ---- editor chrome: sentence, eye wheels, app pill (fade in on the leap) ---- */
.echrome {
  position: absolute;
  inset: 0;
  z-index: 3; /* the wheels + sentence sit above the frog's white eyes */
  opacity: 0;
  pointer-events: none;
  /* leaving: go promptly, so the editor is not still hovering over the pond
     while he falls. The delay belongs to the entrance only. */
  transition: opacity 0.24s cubic-bezier(0.23, 1, 0.32, 1);
}
.pond-device.is-editor .echrome {
  opacity: 1;
  pointer-events: auto;
  transition-duration: 0.4s;
  transition-delay: 0.2s; /* waits for him to land before reading in */
}
.ec-sentence {
  position: absolute;
  left: 26px;
  right: 26px;
  top: 78px;
  text-align: center;
  font-weight: 900;
  font-size: 16px;
  letter-spacing: -0.3px;
  color: var(--ink);
}
/* the two eyes as scrollable hour/minute wheels (drag to set the time) */
.ec-wheel {
  position: absolute;
  top: 101px;
  width: 262px;
  height: 262px;
  border-radius: 50%;
  overflow: hidden;
}
.wh-h {
  left: -97px;
} /* clip centred on eye centre x34 */
.wh-m {
  left: 237px;
} /* eye centre x368 */
.ec-scroll {
  position: absolute;
  inset: 0;
  overflow-y: scroll;
  scroll-snap-type: y mandatory;
  scrollbar-width: none;
  padding: 99px 0; /* (262 - 64) / 2, so the snapped digit sits at the centre */
  -webkit-overflow-scrolling: touch;
}
.ec-scroll::-webkit-scrollbar {
  display: none;
}
.ec-digit {
  height: 64px;
  display: flex;
  align-items: center;
  justify-content: center;
  scroll-snap-align: center;
  font-weight: 900;
  font-size: 58px;
  letter-spacing: -2px;
  line-height: 1;
  color: #d9d9d3;
  font-variant-numeric: tabular-nums;
  transition: color 0.12s ease;
}
.ec-digit.active {
  color: #14231a;
}
.ec-unit {
  position: absolute;
  top: 210px;
  font-weight: 900;
  font-size: 22px;
  color: #6e7269;
  z-index: 1;
  pointer-events: none;
}
.u-h {
  left: 116px;
}
.u-m {
  left: 300px;
}
/* mouth: the design's exact wide border-bottom smile */
.ec-mouth {
  position: absolute;
  left: 36px;
  top: 468px;
  width: 330px;
  height: 92px;
  border-bottom: 18px solid #14231a;
  border-radius: 0 0 230px 230px;
}
/* tongue: sits behind the mouth (its top tucks under the lip) */
.ec-tongue {
  position: absolute;
  left: 50%;
  margin-left: -13px;
  top: 546px;
  width: 26px;
  height: 58px;
  border-radius: 0 0 13px 13px;
  background: #ff4a45;
}
.ec-pill {
  position: absolute;
  left: 56px;
  top: 588px;
  width: 290px;
  height: 64px;
  border-radius: 22px;
  background: #fff;
  box-shadow: 0 8px 20px rgba(20, 35, 26, 0.18);
  border: 0;
  cursor: pointer;
  font-family: var(--font);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  font-weight: 900;
  font-size: 20px;
  color: #6e7269; /* muted until an app is chosen */
  transition: transform 0.09s ease;
}
.ec-pill.chosen {
  color: var(--ink);
}
.ec-pill:active {
  transform: scale(0.97);
}
.ec-chevron {
  width: 9px;
  height: 9px;
  border-right: 2.5px solid #6e7269;
  border-bottom: 2.5px solid #6e7269;
  transform: rotate(-45deg);
}
/* Save (replaces "back to the pond"): enabled once app + a limit are set */
.ec-save {
  position: absolute;
  left: 56px;
  top: 664px;
  width: 290px;
  height: 62px;
  border-radius: 31px;
  border: 0;
  cursor: pointer;
  font-family: var(--font);
  font-weight: 900;
  font-size: 18px;
  background: #14231a;
  color: #fff;
  z-index: 4;
  /* it only exists once there is something to save: a limit AND an app */
  opacity: 0;
  transform: translateY(10px) scale(0.96);
  pointer-events: none;
  transition: opacity 0.26s ease, transform 0.34s var(--ease-pop),
    background-color 0.15s ease;
}
.ec-save.ready {
  opacity: 1;
  transform: none;
  pointer-events: auto;
  /* the entrance keeps its pop; the press must not inherit a 340ms spring
     or the button feels mushy under the finger */
  transition: transform 0.09s cubic-bezier(0.23, 1, 0.32, 1),
    background-color 0.15s linear;
}
.ec-save.ready:active {
  transform: scale(0.975);
  background: #0c150f;
}
@media (prefers-reduced-motion: reduce) {
  .ec-save {
    transition: opacity 0.15s ease;
    transform: none;
  }
}

/* ---- app picker (screen 21) ---- */
.picker {
  position: absolute;
  inset: 0;
  z-index: 6;
  background: var(--paper);
  padding: 60px 26px 0;
  opacity: 0;
  transform: translateY(26px);
  pointer-events: none;
  transition: opacity 0.26s var(--ease-swim),
    transform 0.3s cubic-bezier(0.32, 0.72, 0, 1);
}
.picker.open {
  opacity: 1;
  transform: none;
  pointer-events: auto;
}
.pk-title {
  text-align: center;
  font-weight: 900;
  font-size: 30px;
  letter-spacing: -1.2px;
  color: var(--ink);
}
.pk-sub {
  margin: 8px auto 0;
  max-width: 300px;
  text-align: center;
  font-weight: 700;
  font-size: 15px;
  line-height: 1.35;
  color: var(--muted);
}
.pk-list {
  margin-top: 26px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.pk-row {
  display: flex;
  align-items: center;
  gap: 16px;
  height: 76px;
  padding: 0 18px;
  border-radius: 24px;
  background: #f3f3ef;
  border: 0;
  cursor: pointer;
  font-family: var(--font);
  width: 100%;
  text-align: left;
}
.pk-row {
  transition: background-color 0.18s linear, transform 0.09s
    cubic-bezier(0.23, 1, 0.32, 1);
}
.pk-row:active {
  transform: scale(0.985);
}
.pk-row.sel {
  background: var(--green);
}
.pk-tile {
  width: 46px;
  height: 46px;
  border-radius: 13px;
  flex: none;
  background: repeating-linear-gradient(135deg, #e4e4de 0 6px, #edede7 6px 12px);
}
.pk-row.sel .pk-tile {
  background: repeating-linear-gradient(
    135deg,
    rgba(255, 255, 255, 0.62) 0 6px,
    rgba(255, 255, 255, 0.34) 6px 12px
  );
}
.pk-name {
  flex: 1 1 auto;
  font-weight: 900;
  font-size: 20px;
  color: var(--ink);
}
.pk-dot {
  width: 26px;
  height: 26px;
  border-radius: 50%;
  border: 2px solid #c9cbc4;
  flex: none;
}
.pk-row.sel .pk-dot {
  border-color: #14231a;
  background: #14231a;
}
.pk-frog {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 230px;
  border: 0;
  background: none;
  padding: 0;
  cursor: pointer;
}
.pk-frog svg {
  position: absolute;
  left: 0;
  bottom: 0;
  width: 100%;
  height: auto;
}

/* ---- the leaping frog: exact fgPondLeap (translateY 660 scale 0.345 ->
   16% dip translateY 690 scale 0.325 -> rest), origin top-centre ---- */
.leap-frog {
  position: absolute;
  left: 0;
  top: 0;
  width: 402px;
  height: 874px;
  border: 0;
  background: none;
  padding: 0;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  z-index: 2;
  transform-origin: 201px 0px;
  transform: translateY(538px) scale(0.345); /* pond */
}
.pond-device.is-editor .leap-frog {
  animation: leapUp 0.56s cubic-bezier(0.32, 0, 0.3, 1.02) both;
  cursor: default;
  pointer-events: none;
}
.pond-device.sinking .leap-frog {
  animation: leapDown 0.56s cubic-bezier(0.3, 0, 0.32, 1) both;
  /* mid-descent he is not catchable: re-entering here would restart leapUp
     from the pond and teleport him down through his own fall */
  pointer-events: none;
}
@keyframes leapUp {
  0% {
    transform: translateY(538px) scale(0.345);
  }
  16% {
    transform: translateY(568px) scale(0.325);
  }
  100% {
    transform: translateY(0) scale(1);
  }
}
@keyframes leapDown {
  0% {
    transform: translateY(0) scale(1);
  }
  12% {
    transform: translateY(-14px) scale(1.02);
  }
  100% {
    transform: translateY(538px) scale(0.345);
  }
}
.pond-frog {
  display: block;
  width: 402px;
  height: 874px;
  overflow: visible;
  /* he sits above the pond surface rather than printed on it. Blur/offset are
     in frame units, so the 0.345 pond scale lands them at ~8px on screen. */
  filter: drop-shadow(0 22px 28px rgba(20, 35, 26, 0.24))
    drop-shadow(0 6px 10px rgba(20, 35, 26, 0.12));
  transition: filter 0.3s var(--ease-swim);
}
/* The breath lives on an inner group, never on the filtered element: scaling
   the drop-shadowed node re-rasterises the whole filter every frame. It also
   only runs while the pond is actually on screen (.breathing, from JS). */
.pond-breathe {
  transform-origin: 201px 874px;
  transform-box: view-box;
}
.pond-device.breathing .pond-breathe {
  animation: frogBreathe 3.4s ease-in-out infinite;
}
/* once he has leapt he IS the editor: no lift, no breath */
.pond-device.is-editor .pond-frog,
.pond-device.sinking .pond-frog {
  filter: none;
}
.pond-device.is-editor .pond-breathe,
.pond-device.sinking .pond-breathe {
  animation: none;
}
@keyframes frogBreathe {
  0%,
  100% {
    transform: scale(1);
  }
  50% {
    transform: scale(1.03);
  }
}
/* the hint breathes with him, on the same clock */
.pc-hint {
  animation: hintPulse 3.4s ease-in-out infinite;
}
@keyframes hintPulse {
  0%,
  100% {
    opacity: 0.5;
  }
  50% {
    opacity: 1;
  }
}
/* eye + plus swap: pupils/plus (pond) fade out; wheels + mouth live in echrome */
.frog-pupil,
.pond-plus {
  transition: opacity 0.2s ease;
}
.pond-device.is-editor .frog-pupil,
.pond-device.is-editor .pond-plus {
  opacity: 0;
}

@media (prefers-reduced-motion: reduce) {
  .frog-pupil,
  .pond-plus {
    transition: none;
  }
  /* these cross-fade: keep the opacity, lose nothing else */
  .pchrome,
  .echrome {
    transition-property: opacity;
    transition-duration: 0.2s;
  }
  .picker {
    transform: none;
    transition-property: opacity;
  }
  .pond-device.is-editor .leap-frog,
  .pond-device.sinking .leap-frog {
    animation: none;
  }
  .pond-device.is-editor .leap-frog {
    transform: translateY(0) scale(1);
  }
  /* the breath and the hint pulse are decorative: the lift stays */
  .pond-frog {
    animation: none;
    transform: none;
  }
  .pc-hint {
    animation: none;
    opacity: 1;
  }
}

/* ============================================================================
   Added: numbered steps, mission tiles, and an FAQ.
   ========================================================================= */
/* ---------- numbered steps inside "how it works" ---------- */
.step-label {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: 44px;
  font-weight: 900;
  font-size: 33px;
  line-height: 1.04;
  letter-spacing: -1.3px;
  color: var(--ink);
}
.step-label:first-of-type {
  margin-top: 8px;
}
/* the step number is drawn, not set: a pen numeral inside a wobbly ring */
.step-n {
  display: block;
  flex: none;
  width: 40px;
  height: 40px;
  color: var(--ink);
}
.step-n svg {
  display: block;
  width: 100%;
  height: 100%;
  overflow: visible;
}
.step-label + .band-copy {
  margin-top: 12px;
}

/* ---------- mission tiles ----------
   Square ink chips, each nudged off true, with a chunky illustration that
   runs past the corner instead of sitting politely inside it. */
.missions {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 13px;
  margin-top: 26px;
}
.mtile {
  position: relative;
  aspect-ratio: 1 / 1;
  border-radius: 25%;
  background: var(--ink);
  overflow: hidden;
  transform: rotate(var(--r, 0deg));
}
.mtile-name {
  position: absolute;
  left: 11%;
  top: 9%;
  z-index: 1;
  font-weight: 900;
  font-size: 15px;
  line-height: 1.15;
  letter-spacing: -0.02em;
  color: #fff;
}
.mtile-art {
  position: absolute;
  right: -5%;
  bottom: -6%;
  width: 68%;
  height: auto;
}
@media (max-width: 470px) {
  .missions {
    grid-template-columns: 1fr 1fr;
    gap: 11px;
  }
  .mtile-name {
    font-size: 16px;
  }
}

/* ---------- FAQ (native details accordion) ---------- */
.faq {
  margin-top: 10px;
}
.faq-item {
  border-top: 1px solid var(--hairline);
}
.faq-item:last-child {
  border-bottom: 1px solid var(--hairline);
}
.faq-item summary {
  list-style: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding: 17px 2px;
  font-weight: 800;
  font-size: 16.5px;
  letter-spacing: -0.01em;
  color: var(--ink);
}
.faq-item summary::-webkit-details-marker {
  display: none;
}
.faq-mark {
  position: relative;
  flex: none;
  width: 14px;
  height: 14px;
}
.faq-mark::before,
.faq-mark::after {
  content: "";
  position: absolute;
  background: var(--green);
  border-radius: 2px;
}
.faq-mark::before {
  left: 0;
  top: 6px;
  width: 14px;
  height: 2px;
}
.faq-mark::after {
  left: 6px;
  top: 0;
  width: 2px;
  height: 14px;
  transform-origin: 50% 50%;
  transition: transform 0.3s cubic-bezier(0.77, 0, 0.175, 1);
}
.faq-item[open] .faq-mark::after {
  transform: rotate(90deg);
}
.faq-item p {
  padding: 0 2px 18px;
  font-weight: 700;
  font-size: 14.5px;
  line-height: 1.5;
  color: var(--muted);
  max-width: 44ch;
}

/* ---------- the cost, answered by the reader ----------
   The control is the product's own language: the slider handle is a frog eye,
   and the consequence is set as a small ledger rather than one floating number. */
.calc {
  margin: 30px auto 0;
  max-width: 300px;
}
.calc-read {
  display: block;
  font-weight: 900;
  font-size: 56px;
  line-height: 1;
  letter-spacing: -2.6px;
  color: var(--ink);
}
.calc-read i {
  font-style: normal;
  font-size: 0.5em;
  letter-spacing: -1px;
  color: var(--muted-soft);
}
.calc-read-sub {
  display: block;
  margin-top: 7px;
  font: 700 11px/1 var(--mono);
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: var(--muted-soft);
}
.calc-range {
  -webkit-appearance: none;
  appearance: none;
  display: block;
  width: 100%;
  margin-top: 20px;
  height: 44px; /* hit area; the track itself stays fine */
  background: none;
  cursor: pointer;
}
/* filled to the handle, --p is set by app.js */
.calc-range::-webkit-slider-runnable-track {
  height: 6px;
  border-radius: 3px;
  background: linear-gradient(
    to right,
    var(--green) 0 calc(var(--p, 30) * 1%),
    var(--hairline) calc(var(--p, 30) * 1%) 100%
  );
}
.calc-range::-moz-range-track {
  height: 6px;
  border-radius: 3px;
  background: var(--hairline);
}
.calc-range::-moz-range-progress {
  height: 6px;
  border-radius: 3px;
  background: var(--green);
}
/* the handle is one of his eyes: white field, green ring, ink pupil */
.calc-range::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 30px;
  height: 30px;
  margin-top: -12px;
  border-radius: 50%;
  background: radial-gradient(circle at 50% 50%, var(--ink) 0 5.5px, #fff 5.5px);
  box-shadow: inset 0 0 0 4px var(--green), 0 5px 14px rgba(20, 35, 26, 0.2);
  transition: transform 0.14s var(--ease-pop);
}
.calc-range::-moz-range-thumb {
  width: 30px;
  height: 30px;
  border: 0;
  border-radius: 50%;
  background: radial-gradient(circle at 50% 50%, var(--ink) 0 5.5px, #fff 5.5px);
  box-shadow: inset 0 0 0 4px var(--green), 0 5px 14px rgba(20, 35, 26, 0.2);
}
.calc-range:active::-webkit-slider-thumb {
  transform: scale(1.1);
}
.calc-range:focus-visible {
  outline: none;
}
.calc-range:focus-visible::-webkit-slider-thumb {
  box-shadow: inset 0 0 0 4px var(--green), 0 0 0 6px var(--green-tint);
}
.calc-ticks {
  display: flex;
  justify-content: space-between;
  padding: 0 12px; /* line the ends up with the handle travel */
  margin-top: -2px;
  font: 700 11px/1 var(--mono);
  color: var(--muted-soft);
}

/* ---- the ledger ---- */
.cost {
  margin: 40px auto 0;
  max-width: 340px;
  text-align: left;
}
.cost-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
  padding: 15px 2px;
  border-top: 1px solid var(--hairline);
}
.cost-row:last-child {
  border-bottom: 1px solid var(--hairline);
}
.cost-row dt {
  /* the brand face, not system mono: it sits beside the figures, so it should
     read as the same family rather than as a machine label */
  font-weight: 800;
  font-size: 15.5px;
  line-height: 1.3;
  letter-spacing: -0.012em;
  color: var(--muted);
}
.cost-row dd {
  flex: none;
  font-weight: 900;
  font-size: 25px;
  line-height: 1;
  letter-spacing: -1px;
  color: var(--ink);
  white-space: nowrap;
}
.cost-row dd i {
  display: inline-block;
  /* reserved for the longest form ("months"), so going singular does not
     drag the whole figure sideways */
  min-width: 3.6em;
  margin-left: 0.28em;
  text-align: left;
  font-style: normal;
  font-size: 0.52em;
  font-weight: 800;
  letter-spacing: 0;
  color: var(--muted-soft);
}
/* the one that lands: same type as the row above, only the label leans darker */
.cost-row.is-lead dt {
  color: var(--muted);
}
.cost-note {
  margin-top: 14px;
  font: 700 11px/1 var(--mono);
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: var(--muted-soft);
}
/* ---- the figures ----
   slot-text owns these elements: it splits them into per-character cells and
   rolls only the characters that changed, animating its own width. All we do
   is keep the digits tabular so the cells stay even. */
.slot {
  font-variant-numeric: tabular-nums;
}
@media (prefers-reduced-motion: reduce) {
  .calc-range::-webkit-slider-thumb {
    transition: none;
  }
}

/* ---------- the saved rule arrives ----------
   The payoff of the whole demo: it drops into the pond as the frog lands,
   rather than simply being there once the chrome fades back. */
.rrow-enter {
  animation: rrowIn 0.4s 0.32s cubic-bezier(0.23, 1, 0.32, 1) both;
}
@keyframes rrowIn {
  0% {
    opacity: 0;
    transform: translateY(14px) scale(0.97);
  }
  100% {
    opacity: 1;
    transform: none;
  }
}
@media (prefers-reduced-motion: reduce) {
  .rrow-enter {
    animation: none;
  }
}

/* ---------- remaining motion polish ---------- */
/* primary tap targets that had no press feedback at all */
.pk-frog,
.leap-frog {
  transition: transform 0.09s cubic-bezier(0.23, 1, 0.32, 1);
}
.pk-frog:active {
  transform: scale(0.97);
}
.pond-device:not(.is-editor):not(.sinking) .leap-frog:active {
  transform: translateY(566px) scale(0.332);
}

/* the cost figures: reserve the digit box so slot-text is not animating
   `width` on almost every step (it only rolls when the count is stable) */
.cost-row dd .slot {
  min-width: 3.4ch;
  justify-content: flex-end;
}

/* the waitlist holds its height and cross-fades, instead of collapsing the
   row and snapping the page up at the one moment that matters */
.waitlist {
  min-height: 56px;
  align-items: center;
  transition: opacity 0.22s var(--ease-swim);
}
.waitlist.clearing {
  opacity: 0;
}
.waitlist.done {
  justify-content: center;
  font-weight: 800;
  font-size: 15px;
  color: var(--green-text);
  text-align: center;
}

/* the FAQ panel animates with its marker instead of snapping.
   Progressive enhancement: a no-op where ::details-content is unsupported. */
@supports (interpolate-size: allow-keywords) {
  :root {
    interpolate-size: allow-keywords;
  }
  .faq-item::details-content {
    block-size: 0;
    overflow: hidden;
    transition: block-size 0.32s cubic-bezier(0.23, 1, 0.32, 1),
      content-visibility 0.32s allow-discrete;
  }
  .faq-item[open]::details-content {
    block-size: auto;
  }
}

@media (prefers-reduced-motion: reduce) {
  .rrow-enter,
  .pond-device.breathing .pond-breathe {
    animation: none;
  }
  .waitlist,
  .pk-row,
  .pk-frog,
  .leap-frog {
    transition: none;
  }
  @supports (interpolate-size: allow-keywords) {
    .faq-item::details-content {
      transition: none;
    }
  }
}

/* ---------- the cost: one panel holding the answer and its price ---------- */
.calc-panel {
  margin: 28px auto 0;
  max-width: 400px;
  padding: 24px 24px 26px;
  border-radius: 26px;
  background: color-mix(in srgb, var(--paper) 92%, transparent);
  -webkit-backdrop-filter: saturate(1.1) blur(10px);
  backdrop-filter: saturate(1.1) blur(10px);
  box-shadow: var(--shadow-card), 0 0 0 1px rgba(20, 35, 26, 0.05);
}
.calc-panel .calc {
  margin-top: 4px;
}

/* ---------- footer nav ---------- */
.foot-nav {
  display: flex;
  gap: 14px;
}
.foot-nav a {
  font-weight: 700;
  font-size: 13.5px;
  color: var(--muted);
  text-decoration: none;
  transition: color 0.15s linear;
}
.foot-nav a:hover {
  color: var(--ink);
}



/* ---------- margin notes ----------
   Hand-drawn asides pinned to the thing they point at. The <svg> is meant to
   be replaced by a drawesome export: keep .annot-line and the viewBox, swap
   the paths, and give each path .annot-draw so it inherits the draw-on. */
.annot {
  position: absolute;
  display: flex;
  align-items: center;
  gap: 9px;
  color: var(--muted-soft);
  pointer-events: none;
}
.annot-line {
  flex: none;
  width: 21px;
  height: auto;
  overflow: visible;
}
.annot-text {
  font-family: "Caveat", var(--font);
  font-weight: 600;
  font-size: 24px;
  line-height: 1.2;
  letter-spacing: 0.01em;
  color: var(--muted);
  text-align: left;
  white-space: nowrap;
}
/* pinned to the right of the frog, pointing back at his belly */
.annot-belly {
  /* anchored past his right edge, so the note never sits on top of him */
  left: calc(100% + 6px);
  top: 40%;
  transform: rotate(-3deg);
}
/* the pen stroke draws itself in when it scrolls up */
.annot-draw {
  stroke-dasharray: var(--len, 260);
  stroke-dashoffset: var(--len, 260);
}
.annot.in .annot-draw {
  animation: annotDraw 0.75s 0.15s var(--ease-swim) forwards;
}
/* each line wipes in left to right, one after the other, so it reads as
   being written rather than fading up */
.annot-ln {
  display: block;
  clip-path: inset(-14% 100% -14% 0);
}
.annot.in .annot-ln {
  animation: annotWrite 0.44s 0.42s cubic-bezier(0.42, 0, 0.36, 1) forwards;
}
.annot.in .annot-ln:nth-child(2) {
  animation-delay: 0.82s;
}
@keyframes annotWrite {
  to {
    clip-path: inset(-14% 0 -14% 0);
  }
}
@keyframes annotDraw {
  to {
    stroke-dashoffset: 0;
  }
}
/* it needs room beside the column, so it only shows when there is room */
@media (max-width: 780px) {
  .annot {
    display: none;
  }
}
@media (prefers-reduced-motion: reduce) {
  .annot-draw {
    stroke-dasharray: none;
    stroke-dashoffset: 0;
    animation: none;
  }
  .annot-ln {
    clip-path: none;
    animation: none;
  }
}

/* ---------- background life ----------
   Pen doodles hopping and drifting in the empty gutters beside the column,
   drawn in the same hand as the margin note. Decorative only: never behind
   text, never takes a click, gone on any screen without gutters to spare. */
body {
  position: relative;
}
.bg-sprite {
  position: absolute;
  width: 0;
  height: 0;
  overflow: hidden;
}
.bg-life {
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
}
main,
.foot {
  position: relative;
  z-index: 1;
}
.bg-frog,
.bg-fly {
  position: absolute;
  left: var(--x);
  top: var(--y);
  transform: rotate(var(--r, 0deg)) scale(var(--s, 1));
  transform-origin: 50% 100%;
}
.bg-frog svg {
  display: block;
  width: 54px;
  height: auto;
  color: var(--green-deep);
  opacity: 0.26;
  animation: bgHop 7.5s var(--d, 0s) ease-in-out infinite;
}
.bg-fly svg {
  display: block;
  width: 27px;
  height: auto;
  color: var(--muted);
  opacity: 0.34;
  animation: bgDrift 11s var(--d, 0s) ease-in-out infinite;
}
/* mostly still, with one hop near the end of the cycle */
@keyframes bgHop {
  0%,
  72%,
  100% {
    transform: translateY(0) scaleY(1);
  }
  76% {
    transform: translateY(2px) scaleY(0.92);
  }
  84% {
    transform: translateY(-18px) scaleY(1.06);
  }
  92% {
    transform: translateY(0) scaleY(0.97);
  }
}
@keyframes bgDrift {
  0%,
  100% {
    transform: translate(0, 0);
  }
  30% {
    transform: translate(16px, -12px);
  }
  55% {
    transform: translate(4px, 9px);
  }
  80% {
    transform: translate(-13px, -5px);
  }
}
/* the gutters only exist once the viewport is wider than the column */
@media (max-width: 1040px) {
  .bg-life {
    display: none;
  }
}
@media (prefers-reduced-motion: reduce) {
  .bg-frog svg,
  .bg-fly svg {
    animation: none;
  }
}


/* ---------- hand underlines ----------
   Drawn under a single word, twice over, the way you would actually stress
   something on paper. Sits in its own layer so it never shifts the text. */
.step-t {
  min-width: 0;
}
.uline {
  position: relative;
  display: inline-block;
}
.uline-mark {
  position: absolute;
  left: -5%;
  bottom: -0.2em;
  width: 110%;
  height: 0.32em;
  color: var(--green);
  overflow: visible;
  pointer-events: none;
}
/* drawn on when its section arrives, second pass just behind the first */
.reveal.in .uline-mark .annot-draw {
  animation: annotDraw 0.55s 0.3s var(--ease-swim) forwards;
}
.reveal.in .uline-mark .annot-draw:nth-child(2) {
  animation-delay: 0.52s;
}
@media (prefers-reduced-motion: reduce) {
  .uline-mark .annot-draw {
    stroke-dasharray: none;
    stroke-dashoffset: 0;
    animation: none;
  }
}

/* the answer takes no room at all until there is one: the wrapper animates
   from 0fr to 1fr, so nothing below it sits over an empty gap */
.cost-wrap {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 0.45s var(--ease-swim);
}
.cost-wrap.is-open {
  grid-template-rows: 1fr;
}
.cost-inner {
  min-height: 0;
  overflow: hidden;
}
@media (prefers-reduced-motion: reduce) {
  .cost-wrap {
    transition: none;
  }
}

/* ---------- the price, on the ledger card ----------
   The reader answers with the slider and the cost is posted underneath in
   the same card as the control, set as a ledger rather than a sentence. */
.cost-card {
  /* same card as the slider above it, and it only exists once answered */
  margin: 12px auto 20px; /* bottom room so the shadow is not clipped */
  max-width: 400px;
  padding: 6px 24px 20px;
  border-radius: 26px;
  background: color-mix(in srgb, var(--paper) 92%, transparent);
  -webkit-backdrop-filter: saturate(1.1) blur(10px);
  backdrop-filter: saturate(1.1) blur(10px);
  box-shadow: var(--shadow-card), 0 0 0 1px rgba(20, 35, 26, 0.05);
  text-align: left;
  opacity: 0;
  transform: translateY(10px);
  transition: opacity 0.3s var(--ease-swim), transform 0.4s var(--ease-swim);
}
.cost-card.is-shown {
  opacity: 1;
  transform: none;
}
/* the ledger sits flush inside the card rather than floating in the band */
.cost-card .cost {
  margin: 0;
  max-width: none;
}
/* the card edge already frames the top row, so it needs no rule of its own */
.cost-card .cost-row:first-child {
  border-top: 0;
}
/* the one line that is a gain, so it reads in the green rather than the ink */
.cost-back {
  margin-top: 14px;
  font-weight: 700;
  font-size: 14px;
  line-height: 1.45;
  color: var(--green-text);
}
.cost-back b {
  /* the global b is ink, but the whole gain line belongs to the green */
  color: inherit;
  font-weight: 800;
  white-space: nowrap;
}
/* each row is posted just after the card arrives, one under the other */
.cost-card.is-shown .cost-row,
.cost-card.is-shown .cost-back {
  animation: costPost 0.42s 0.14s var(--ease-swim) both;
}
.cost-card.is-shown .cost-row:nth-child(2) {
  animation-delay: 0.24s;
}
.cost-card.is-shown .cost-back {
  animation-delay: 0.36s;
}
@keyframes costPost {
  0% {
    opacity: 0;
    transform: translateY(7px);
  }
  100% {
    opacity: 1;
    transform: none;
  }
}
@media (prefers-reduced-motion: reduce) {
  .cost-card {
    transition: opacity 0.15s linear;
    transform: none;
  }
  .cost-card.is-shown .cost-row,
  .cost-card.is-shown .cost-back {
    animation: none;
  }
}

/* ---------- the pond stage ----------
   The device no longer fills the column: once there is room it shrinks and
   sits left, leaving margin on the right for its note. */
.pond-stage {
  position: relative;
  margin-top: 26px;
}
.pond-stage .pond-device {
  margin-top: 0;
}
.calc-panel {
  position: relative;
}

/* the note on the left of the slider */
.annot-drag {
  /* level with the slider itself, not the middle of the card */
  right: calc(100% + 10px);
  top: 59%;
  transform: translateY(-50%) rotate(-2deg);
}
/* mirrored, so it opens away from the card */
.annot-drag .annot-bracket {
  transform: scaleX(-1);
}
.annot-drag .annot-text {
  text-align: right;
}

/* the note beside the editor: only while the wheels are actually there */
.annot-scroll {
  left: calc(100% + 16px);
  top: 12%;
  transform: rotate(1.5deg);
  opacity: 0;
  transition: opacity 0.3s 0.35s var(--ease-swim);
}
.pond-device.is-editor ~ .annot-scroll {
  opacity: 1;
}
.annot-scrollmark {
  width: 24px;
}

@media (min-width: 781px) {
  /* the stage shrinks to the phone, so anything pinned to its edge sits
     against the phone rather than out at the column edge */
  .pond-stage {
    max-width: 310px;
    margin-right: auto;
  }
}

/* the editor note draws itself as the editor arrives, and resets when it
   leaves, so it plays again the next time he leaps */
.pond-device.is-editor ~ .annot-scroll .annot-draw {
  animation: annotDraw 0.55s 0.35s var(--ease-swim) forwards;
}
.pond-device.is-editor ~ .annot-scroll .annot-draw:nth-child(2),
.pond-device.is-editor ~ .annot-scroll .annot-draw:nth-child(3) {
  animation-delay: 0.6s;
}
.pond-device.is-editor ~ .annot-scroll .annot-ln {
  animation: annotWrite 0.45s 0.7s cubic-bezier(0.42, 0, 0.36, 1) forwards;
}
.pond-device.is-editor ~ .annot-scroll .annot-ln:nth-child(2) {
  animation-delay: 1.05s;
}
@media (prefers-reduced-motion: reduce) {
  .pond-device.is-editor ~ .annot-scroll .annot-draw {
    stroke-dashoffset: 0;
    animation: none;
  }
  .pond-device.is-editor ~ .annot-scroll .annot-ln {
    clip-path: none;
    animation: none;
  }
}

/* ---------- the rule toggle is a real control ---------- */
.rrow-tog {
  border: 0;
  padding: 0;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: background-color 0.2s linear, transform 0.09s
    cubic-bezier(0.23, 1, 0.32, 1);
}
.rrow-tog::after {
  transition: left 0.24s cubic-bezier(0.23, 1, 0.32, 1);
}
.rrow-tog:active {
  transform: scale(0.94);
}
.rrow-tog:focus-visible {
  outline: 3px solid var(--green-tint);
  outline-offset: 2px;
}
@media (prefers-reduced-motion: reduce) {
  .rrow-tog,
  .rrow-tog::after {
    transition: none;
  }
}

/* ---------- the flyer ----------
   He passes over the closing line, then the sky is empty for a while: a pass
   reads as an event, a continuous loop reads as a GIF. The crossing and the
   arc share one duration so they are phase locked, and nothing runs at all
   until the section is actually on screen. */
.flypath {
  position: relative;
  /* his height, plus the arc, plus the extra the bank adds to his box */
  height: 186px;
  margin-bottom: 4px;
  overflow: hidden;
  pointer-events: none;
  /* he fades at both edges instead of being cut off by the lane: the mask is
     wider than he is, so he is most of the way in before he is fully opaque */
  -webkit-mask-image: linear-gradient(
    to right,
    transparent 0,
    #000 24%,
    #000 76%,
    transparent 100%
  );
  mask-image: linear-gradient(
    to right,
    transparent 0,
    #000 24%,
    #000 76%,
    transparent 100%
  );
}
.flyer {
  position: absolute;
  top: 50%;
  left: 0;
  margin-top: -66px;
  transform: translateX(-220px); /* parked off stage until he is needed */
}
.flyfrog {
  display: block;
  width: 150px;
  height: auto;
  transform-origin: 50% 60%;
}
/* only once the closing section is in view */
.flypath.aloft .flyer {
  animation: flyAcross 15s linear infinite;
}
.flypath.aloft .flyfrog {
  animation: flyArc 15s cubic-bezier(0.42, 0, 0.58, 1) infinite;
}
/* the crossing takes the first 45%; the rest of the cycle he is gone */
@keyframes flyAcross {
  0% {
    transform: translateX(-220px);
  }
  45%,
  100% {
    transform: translateX(700px);
  }
}
/* in low, up over the middle, away down the far side, banking into it */
@keyframes flyArc {
  0% {
    transform: translateY(14px) rotate(-7deg);
  }
  12% {
    transform: translateY(0) rotate(-2deg);
  }
  23% {
    transform: translateY(-10px) rotate(2deg);
  }
  34% {
    transform: translateY(0) rotate(6deg);
  }
  45%,
  100% {
    transform: translateY(14px) rotate(9deg);
  }
}
@media (prefers-reduced-motion: reduce) {
  .flypath.aloft .flyer,
  .flypath.aloft .flyfrog {
    animation: none;
  }
  .flyer {
    left: 50%;
    margin-left: -75px;
    transform: none;
  }
}

/* the illustrated missions: sized by a box rather than by width, so poses
   with very different aspect ratios all sit the same in their tile */
.mtile-pic {
  width: auto;
  height: auto;
  max-width: 76%;
  max-height: 82%;
  right: -3%;
  bottom: -5%;
  opacity: 1;
}
