/* ==========================================================================
   Paldo & Jonah — teaser landing page
   Palette locked to the official brand guide (_docs/paldo-jonah-brand-guide.md)
   Structure follows _docs/teaser-landing-page-improvement-plan.md
   ========================================================================== */

:root{
  --purple:      #5B3FD1;
  --purple-soft: #8B6DFF;
  --purple-deep: #4A2FB6;
  --coral:       #FF6B6B;
  --peach:       #FFA58F;
  --cream:       #FFF8F2;
  --navy:        #1E1B3A;

  --ink:        var(--navy);
  --ink-soft:   #4A4667;
  --card:       #FFFFFF;
  --tint-purple:#F1EDFF;
  --tint-coral: #FFEFEC;
  --tint-peach: #FFF3E4;

  --radius-sm: 14px;
  --radius:    22px;
  --radius-lg: 34px;

  --shadow-sm: 0 4px 14px rgba(30,27,58,.06);
  --shadow:    0 10px 30px rgba(30,27,58,.08);
  --shadow-lg: 0 22px 50px rgba(30,27,58,.14);

  --font-display: "Baloo 2", "Nunito", ui-rounded, "Segoe UI", system-ui, sans-serif;
  --font-body:    "Nunito", ui-rounded, "Segoe UI", system-ui, sans-serif;
  --font-script:  "Caveat Brush", "Brush Script MT", cursive;

  --shell: 1180px;

  /* ── Motion tokens ──────────────────────────────────────────────────
     Durations stay inside the plan's 300–700ms band (§26). Each linear()
     spring is preceded by a cubic-bezier fallback: an unsupported linear()
     invalidates only its own declaration, so the previous value survives. */
  --ease-out:    cubic-bezier(.22,1,.36,1);
  --ease-spring: cubic-bezier(.34,1.56,.64,1);
  --ease-spring: linear(
    0, 0.006, 0.025 2.8%, 0.101 6.1%, 0.539 18.9%, 0.721 25.3%, 0.849 31.5%,
    0.937 38.1%, 0.968 41.8%, 0.991 45.7%, 1.006 50.1%, 1.015 60.2%,
    1.006 80.2%, 1
  );

  --reveal-dur: .6s;
  --float-dur:  6s;

  /* ── Liquid Glass ───────────────────────────────────────────────────────
     Glass is a *material*, not a colour: it has almost no appearance of its
     own and borrows everything from what sits behind it. That is why these
     are tokens rather than fixed fills — each surface sets its own tint and
     lets the backdrop supply the rest.

     Three things separate this from ordinary frosted blur, and all three are
     needed or it reads as grey plastic:

       1. saturation. Blur alone desaturates whatever is behind it. Pushing
          saturate() back above 100% is what keeps the purple blob and the
          characters *coloured* through the panel.
       2. a specular rim. Real glass catches a bright line along its top edge
          where the light enters, and a fainter bounce along the bottom. This
          is the single strongest cue; without it nothing looks like glass.
       3. a curvature sheen. A vertical gradient — bright at the top, clear
          through the middle, lifting again at the base — reads as a lens
          with thickness rather than a flat sheet of film.
     ───────────────────────────────────────────────────────────────────── */
  --glass-blur: 20px;
  --glass-sat:  180%;

  /* the film itself; components override --glass-fill to tint it */
  --glass-fill:     rgba(255,255,255,.42);
  --glass-fill-warm:rgba(255,248,242,.55);

  /* edge lighting */
  --glass-rim:      rgba(255,255,255,.75);
  --glass-rim-low:  rgba(255,255,255,.22);
  --glass-edge:     rgba(255,255,255,.55);

  /* the curvature sheen, reused by every glass surface */
  --glass-sheen: linear-gradient(
    177deg,
    rgba(255,255,255,.50) 0%,
    rgba(255,255,255,.12) 38%,
    rgba(255,255,255,.06) 62%,
    rgba(255,255,255,.26) 100%
  );

  /* glass floats, so its shadow is wider and softer than a card's */
  --glass-shadow:
    0 10px 34px rgba(30,27,58,.11),
    0 2px 8px rgba(30,27,58,.05);
}

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

/* The inline <svg> holding the refraction filter. It has no visual output of
   its own and must not occupy layout — but display:none would stop Chrome
   resolving the filter reference, so it is collapsed instead of hidden. */
.glass-defs{
  position:absolute;
  width:0; height:0;
  overflow:hidden;
  pointer-events:none;
}

html{
  scroll-behavior:smooth;
  /* the hero blob bleeds past the shell on purpose — clip instead of hidden
     so position:sticky on the header keeps working */
  overflow-x:clip;
}

/* keep the sticky header from covering anchor targets */
#why,#join,#top{ scroll-margin-top:92px; }

body{
  margin:0;
  background:var(--cream);
  color:var(--ink);
  font-family:var(--font-body);
  font-size:17px;
  line-height:1.5;
  -webkit-font-smoothing:antialiased;
  overflow-x:clip;
}

img{ max-width:100%; display:block; }
a{ color:inherit; }

.shell{
  width:100%;
  max-width:var(--shell);
  margin-inline:auto;
  padding-inline:clamp(20px, 4vw, 58px);
}

.sr-only{
  position:absolute; width:1px; height:1px; padding:0; margin:-1px;
  overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; border:0;
}

.skip-link{
  position:absolute; left:-999px; top:8px; z-index:99;
  background:var(--purple); color:#fff; padding:10px 16px; border-radius:12px;
  text-decoration:none; font-weight:700;
}
.skip-link:focus{ left:16px; }

:focus-visible{
  outline:3px solid var(--purple-soft);
  outline-offset:3px;
  border-radius:6px;
}

.c-purple{ color:var(--purple); }
.c-coral{ color:var(--coral); }
.c-peach{ color:#FFD9CE; }

/* ── Wordmark + logo mark ─────────────────────────────────────────────── */
.wordmark{
  display:inline-flex; align-items:center; gap:10px;
  text-decoration:none;
  line-height:1;
}
.wordmark-text{
  font-family:var(--font-script);
  font-size:clamp(30px, 3.4vw, 42px);
  letter-spacing:.005em;
  color:var(--purple);
  line-height:1.35;
  white-space:nowrap;
  /* sticker outline: em-based so it stays proportional at every size */
  paint-order:stroke fill;
  -webkit-text-stroke:.13em #fff;
  filter:drop-shadow(0 3px 2px rgba(30,27,58,.14));
}
.w-paldo{ color:var(--purple); }
.wordmark .amp{ color:var(--navy); font-size:.8em; }
.w-jonah{ color:var(--coral); }

/* the full paldo-jonah badge. Its circle is r=47.8% centred at (49.9%,50.4%),
   not a perfectly inscribed one, so the alpha mask is baked into the file at
   those measured bounds — border-radius:50% here would leave black slivers. */
.logo-mark{ display:block; flex:none; width:52px; height:52px; }
.logo-mark img{ width:100%; height:100%; }

.wordmark.small{ display:inline-block; }
.wordmark.small .w-paldo,
.wordmark.small .w-jonah,
.wordmark.small .amp{ font-family:var(--font-script); font-size:30px; }
.footer-brand .wordmark.small{
  font-family:var(--font-script); font-size:30px; color:var(--purple);
}

/* ── Buttons ──────────────────────────────────────────────────────────── */
.btn{
  display:inline-flex; align-items:center; justify-content:center; gap:9px;
  border:none; cursor:pointer; text-decoration:none;
  font-family:var(--font-display);
  font-weight:700; font-size:17px; letter-spacing:.1px;
  padding:15px 28px;
  border-radius:999px;
  white-space:nowrap;
  transition:transform .16s ease, box-shadow .16s ease, filter .16s ease;
}
.btn-purple{
  background:linear-gradient(180deg,#6A4CE4,var(--purple));
  color:#fff;
  box-shadow:0 8px 20px rgba(91,63,209,.32);
}
.btn-coral{
  background:linear-gradient(180deg,#FF7C74,var(--coral));
  color:#fff;
  box-shadow:0 8px 20px rgba(255,107,107,.34);
}
.btn:hover{ transform:translateY(-2px); filter:brightness(1.04); }
.btn:active{ transform:translateY(0); }
.btn:disabled{ cursor:default; filter:none; transform:none; }
.btn-heart{ color:var(--coral); font-size:19px; }
.btn-purple .btn-heart{ color:#FF8E8E; }
.arr{ font-size:1.05em; transition:transform .16s ease; }
.btn:hover .arr{ transform:translateX(3px); }

/* ── Liquid Glass material ────────────────────────────────────────────────
 * One recipe, applied to every glass surface. Components vary only by
 * --glass-fill and radius.
 *
 * The background is two layers: the sheen on top, the tint underneath. Order
 * matters — the sheen has to sit above the fill or the curvature is buried.
 *
 * The rim is drawn with inset box-shadows rather than a border because a
 * border is uniform on all four sides, and real glass isn't: light enters at
 * the top and bounces weakly off the bottom. Two insets of different strength
 * is the whole trick.
 * ───────────────────────────────────────────────────────────────────────── */
.site-header,
.waitlist,
.cur-card,
.phone-nav{
  background:var(--glass-sheen), var(--glass-fill);
  backdrop-filter:blur(var(--glass-blur)) saturate(var(--glass-sat));
  -webkit-backdrop-filter:blur(var(--glass-blur)) saturate(var(--glass-sat));
  box-shadow:
    inset 0 1px 0 0 var(--glass-rim),        /* specular: light enters here */
    inset 0 -1px 0 0 var(--glass-rim-low),   /* weaker bounce off the base */
    var(--glass-shadow);
}

/* True refraction, where the browser can do it.
 *
 * A url() filter in backdrop-filter is the only way to actually bend the
 * backdrop rather than just blur it — the turbulence displaces the pixels
 * behind the panel, so the blob and the characters wobble at the edges the
 * way they would through a real lens.
 *
 * Support is genuinely patchy (Firefox has none), so this sits behind
 * @supports and everything above stands on its own. Deliberately a small
 * scale: past about 12 the characters behind the header start to smear and
 * it stops reading as glass and starts reading as a bug. */
@supports (backdrop-filter: url(#liquid-glass)){
  /* Deliberately NOT the header. Displacement is uniform across whatever it
     is applied to, and across a full-width bar that reads as a smear rather
     than a lens — the characters passing underneath turn to mush. Real glass
     distorts most at its edges, and the smaller the panel, the more of it is
     edge. So refraction goes on the small panels only, where it looks like
     what it is. */
  /* Desktop only, and not for cost reasons alone. A displaced backdrop is
     re-rasterised on every scroll frame, and there are six of these panels;
     on the mid-range Android this audience mostly browses on that is a real
     jank risk for an effect nobody would miss at 375px, where the panels are
     small and there is barely any art behind them to bend. */
  @media (min-width:900px){
    .waitlist,
    .cur-card,
    .phone-nav{
      backdrop-filter:blur(var(--glass-blur)) saturate(var(--glass-sat)) url(#liquid-glass);
    }
  }
}

/* Transparency is a comfort setting, not just a taste one — it is a real
   readability problem for some people, and iOS/macOS expose a toggle for
   exactly this. Honour it: drop the blur, keep the layout. */
@media (prefers-reduced-transparency: reduce){
  .site-header,
  .waitlist,
  .cur-card,
  .phone-nav,
  .waitlist-onband{
    backdrop-filter:none;
    -webkit-backdrop-filter:none;
    background:var(--card);
  }
  .waitlist-onband{ background:rgba(255,255,255,.96); }
}

/* ── Header ───────────────────────────────────────────────────────────── */
.site-header{
  position:sticky; top:0; z-index:40;
  /* warmer and more opaque than the rest: text sits directly on it, and the
     hero art scrolling underneath would otherwise fight the wordmark */
  --glass-fill:rgba(255,248,242,.62);
  --glass-blur:24px;
  /* the header spans the viewport, so a rim on the sides would be a hairline
     to nowhere — only the bottom edge is a real edge */
  box-shadow:
    inset 0 -1px 0 0 rgba(255,255,255,.5),
    0 1px 24px rgba(30,27,58,.07);
}
.header-inner{
  display:flex; align-items:center; gap:24px;
  padding-block:12px;
}
.site-nav{
  display:flex; gap:32px;
  margin-inline:auto;
  font-family:var(--font-display);
  font-weight:600; font-size:16.5px;
}
.site-nav a{
  text-decoration:none; color:var(--ink);
  padding:6px 2px; position:relative;
}
.site-nav a::after{
  content:""; position:absolute; left:0; right:100%; bottom:0; height:3px;
  border-radius:3px; background:var(--coral); transition:right .2s ease;
}
.site-nav a:hover::after{ right:0; }

.header-cta{ padding:13px 26px; font-size:16px; }

/* ── Hero ─────────────────────────────────────────────────────────────── */
/* plan §37: 45% copy / 55% character + phone composition */
.hero{
  display:grid;
  grid-template-columns:minmax(0,.85fr) minmax(0,1.15fr);
  gap:20px; align-items:center;
  padding-block:20px 44px;
}

.hero h1{
  font-family:var(--font-display);
  font-weight:800;
  font-size:clamp(44px, 5.6vw, 76px);
  line-height:.98;
  letter-spacing:-1.5px;
  margin:0 0 20px;
  position:relative;
}
.line-navy,.line-purple{ display:block; }
.line-navy{ color:var(--navy); }
.line-purple{ color:var(--purple); }

.doodle-heart{
  position:absolute; right:-14px; top:52%;
  width:38px; height:auto;
}
/* round the join so the bottom cusp reads as a drawn point, not a miter spike */
.doodle-heart svg{
  width:100%; fill:none; stroke:var(--coral); stroke-width:3.4;
  stroke-linejoin:round; stroke-linecap:round;
}

.lede{
  margin:0 0 12px;
  font-size:clamp(16px,1.3vw,18px);
  line-height:1.6;
  color:var(--ink-soft);
  max-width:44ch;
}
.lede b{ font-weight:800; }
.lede b:not([class]){ color:var(--navy); }
.lede-strong{
  margin-bottom:26px;
  font-family:var(--font-display);
  font-weight:700;
  font-size:clamp(16.5px,1.4vw,19px);
  color:var(--navy);
  line-height:1.5;
}

/* waitlist form */
.waitlist{
  display:flex; align-items:center;
  gap:0; flex-wrap:wrap;
  /* whiter than the ambient glass — an input needs its own ground or the
     placeholder starts competing with the blob behind it */
  --glass-fill:rgba(255,255,255,.62);
  /* the purple ring is brand, not material, so it survives the glass. Dropped
     to 2px and part-transparent so it reads as the lit edge of the lens
     rather than a sticker sitting on top of it */
  border:2px solid rgba(91,63,209,.55);
  border-radius:999px;
  padding:6px 6px 6px 8px;
  max-width:540px;
  position:relative;
  transition:border-color .25s var(--ease-out), box-shadow .25s var(--ease-out);
}
/* focus lifts the whole pane, the way a glass control does when it becomes
   active — not just a ring on the input inside it */
.waitlist:focus-within{
  border-color:var(--purple);
  box-shadow:
    inset 0 1px 0 0 var(--glass-rim),
    inset 0 -1px 0 0 var(--glass-rim-low),
    0 0 0 4px rgba(91,63,209,.12),
    var(--glass-shadow);
}
/* the field has to stay wide enough for "Enter your email address" —
   the button is what gives, not the input */
.waitlist .btn{ padding-inline:20px; font-size:15.5px; flex:none; }
.field{
  display:flex; align-items:center; gap:10px;
  flex:1 1 150px; min-width:0;
  padding-left:12px;
}
.field .mail{
  width:23px; height:23px; flex:none;
  fill:none; stroke:var(--purple); stroke-width:1.7;
  stroke-linecap:round; stroke-linejoin:round;
}
.waitlist input{
  flex:1; min-width:0;
  border:none; outline:none; background:transparent;
  font-family:var(--font-body); font-size:16.5px; color:var(--navy);
  padding:14px 6px;
}
/* Darker than it looks like it needs to be, deliberately. The visible label is
   sr-only, so this placeholder is the only on-screen cue for what the field
   wants — it is carrying meaning, not decoration, and has to clear AA. */
.waitlist input::placeholder{ color:#6E6A8A; }
.waitlist input:disabled{ color:var(--purple); font-weight:700; }
/* honeypot: off-screen rather than display:none, which some bots detect */
.gotcha{
  position:absolute; left:-9999px; top:auto;
  width:1px; height:1px; opacity:0; pointer-events:none;
}
/* Turnstile mount. The widget renders in interaction-only mode, so for almost
   every visitor it is a zero-size iframe that must stay in the layout tree —
   display:none would stop it working — hence a clipped 0-height box rather
   than hiding it. JS adds .is-live only while a real challenge is on screen. */
.turnstile{
  flex-basis:100%;
  display:flex; justify-content:center;
  height:0; overflow:hidden;
}
.turnstile.is-live{
  height:auto; overflow:visible;
  margin:12px 0 4px;
}
/* a 65px-tall challenge inside a 999px pill renders as a giant oval, so the
   form relaxes to a normal card for as long as the challenge is up */
.waitlist:has(.turnstile.is-live){ border-radius:var(--radius); }

.form-note{
  position:absolute; left:24px; top:calc(100% + 10px);
  margin:0; font-size:14.5px; font-weight:700; color:var(--coral);
}
.form-note.ok{ color:var(--purple); }
/* inline "did you mean" correction inside the status note */
.note-fix,
.note-keep{
  border:none; background:none; padding:0;
  font:inherit; cursor:pointer;
}
.note-fix{
  color:var(--purple); font-weight:800;
  text-decoration:underline; text-underline-offset:2px;
}
.note-keep{
  color:var(--ink-soft); font-weight:600; font-size:.92em;
  text-decoration:underline; text-underline-offset:2px;
}
.waitlist-onband .note-fix{ color:#fff; }
.waitlist-onband .note-keep{ color:rgba(255,255,255,.8); }
.waitlist.done{ border-color:var(--purple-soft); }

/* deliberately not a flex container — flex would turn every text run between
   the <b> tags into its own item and open a gap before each comma */
/* the top margin has to clear .form-note, which is absolutely positioned
   10px below the form and only appears after a submit */
.microcopy{
  margin:40px 0 0;
  font-size:14.5px; line-height:1.5; color:var(--ink-soft);
}
.microcopy b{ font-weight:800; }
.lock{
  display:inline-block; vertical-align:-3px;
  width:16px; height:16px; margin-right:5px;
}
.lock svg{
  width:100%; height:100%;
  fill:none; stroke:var(--purple); stroke-width:1.9;
  stroke-linecap:round; stroke-linejoin:round;
}

.tagline{
  position:relative;
  margin:26px 0 0;
  font-family:var(--font-script);
  font-size:clamp(26px,2.7vw,36px);
  line-height:1.2;
  color:var(--navy);
}
.tagline b{ font-weight:400; }
.u-purple{ box-shadow:inset 0 -.14em 0 rgba(139,109,255,.45); }
.u-coral{ box-shadow:inset 0 -.14em 0 rgba(255,107,107,.4); }
.tag-spark{
  position:absolute; right:12%; top:-14px;
  color:var(--purple-soft); font-size:24px;
}

/* ── Hero art: Paldo · phone · Jonah ──────────────────────────────────── */
.hero-art{
  /* the PNGs carry transparent padding at their inner edges. The pull-in
     cancels that dead space so the figures actually flank the phone; it
     scales with --fig-h so the spacing holds at every viewport. */
  --fig-h:clamp(250px, 30vw, 400px);
  --fig-pull:calc(var(--fig-h) * -0.13);
  --phone-w:clamp(168px, 17.5vw, 218px);
  position:relative;
  min-height:440px;
  display:flex; align-items:flex-end; justify-content:center;
}
.hero-art .blob{
  position:absolute; inset:6% -4% 12% -2%;
  background:#EDE7FF;
  border-radius:52% 48% 44% 56% / 56% 52% 48% 44%;
  z-index:0;
}
/* rotate/scale/translate are set as INDEPENDENT properties rather than one
   transform: the idle float owns `translate`, hover owns `rotate`+`scale`, so
   a running animation and a hover transition never overwrite each other. */
.hero-art .fig{
  position:relative; z-index:2;
  display:block;
  height:var(--fig-h);
  filter:drop-shadow(0 14px 22px rgba(30,27,58,.14));
  transition:rotate .35s var(--ease-spring), scale .35s var(--ease-spring);
}
.hero-art .fig img{ height:100%; width:auto; max-width:none; }
.fig-paldo{ margin-right:var(--fig-pull); rotate:-2deg; }
.fig-jonah{ margin-left:var(--fig-pull); rotate:2deg; }

/* sparkles + dashes */
.hero-art .spark,
.hero-art .dash,
.hero-art .mini-heart{ position:absolute; z-index:1; }
.hero-art .spark{
  width:16px; height:16px;
  background:var(--purple);
  clip-path:polygon(50% 0,60% 40%,100% 50%,60% 60%,50% 100%,40% 60%,0 50%,40% 40%);
}
.s1{ left:9%; top:30%; }
.s2{ left:3%; top:44%; width:12px; height:12px; background:var(--purple-soft); }
.s3{ right:2%; top:56%; width:20px; height:20px; background:var(--purple-soft); }
.hero-art .dash{
  width:5px; height:24px; border-radius:4px; background:var(--purple-soft);
}
.d1{ left:15%; top:20%; transform:rotate(-28deg); }
.d2{ left:10%; top:26%; width:5px; height:18px; transform:rotate(-8deg); }
.d3{ right:11%; top:26%; background:var(--coral); transform:rotate(26deg); }
.hero-art .mini-heart{ color:var(--coral); font-size:26px; }
.mh1{ left:2%; top:62%; }
.mh2{ right:5%; top:70%; font-size:20px; color:var(--purple-soft); }

/* ── Speech bubbles (plan §15 — desktop decoration only) ─────────────── */
.bubble{
  position:absolute; z-index:3; top:2%;
  margin:0; padding:12px 18px;
  border-radius:22px;
  font-family:var(--font-script);
  font-size:19px; line-height:1.2; text-align:center;
  color:#fff;
  box-shadow:var(--shadow);
}
.bubble b{ display:block; font-weight:400; font-size:1.12em; }
.bubble em{ display:block; font-style:normal; font-size:.86em; opacity:.92; }
.bubble::after{
  content:""; position:absolute; bottom:-9px;
  width:20px; height:20px; border-radius:0 0 6px 0;
  background:inherit; transform:rotate(45deg);
}
.bubble-paldo{
  left:2%;
  background:var(--purple);
  rotate:-4deg;
}
.bubble-paldo::after{ left:28%; }
.bubble-jonah{
  right:1%;
  background:var(--coral);
  rotate:4deg;
}
.bubble-jonah::after{ right:28%; }

/* ── Phone teaser ─────────────────────────────────────────────────────── */
.phone{
  position:relative; z-index:1;
  flex:none;
  width:var(--phone-w);
  /* 1:1.9 rather than 1:2.05 — four cards is the cap (plan §13), so a taller
     body just leaves dead white space under the last one */
  aspect-ratio:100/182;
  margin-bottom:6%;
  padding:6px;
  border-radius:calc(var(--phone-w) * .155);
  background:linear-gradient(160deg,#2B2750,var(--navy));
  box-shadow:0 26px 50px rgba(30,27,58,.28), 0 0 0 2px rgba(255,255,255,.55);
}
.phone-screen{
  position:relative;
  height:100%;
  display:flex; flex-direction:column;
  border-radius:calc(var(--phone-w) * .125);
  background:linear-gradient(180deg,#F7F4FF,#FFFFFF 34%);
  overflow:hidden;
  /* every inner size is phone-relative so the whole mockup scales as one */
  font-size:calc(var(--phone-w) / 20);
  /* Horizontal inset derived from the phone width, NOT em: several children
     set their own small font-size, so an em padding there resolves against
     that smaller size and silently under-indents. */
  --pad:calc(var(--phone-w) * .072);
}

.phone-status{
  display:flex; align-items:center; justify-content:space-between;
  /* the screen's corner radius is ~.125 × phone width; anything closer than
     that to the edge gets clipped by the curve — which was cutting the "9" */
  padding:.72em var(--pad) .2em;
  font-family:var(--font-display);
  font-weight:700; font-size:.62em; color:var(--navy);
}
.status-icons{ display:flex; align-items:center; gap:.3em; }
.status-icons .si{ width:.85em; height:.85em; fill:var(--navy); stroke:none; }
.status-icons .si:last-child{
  fill:none; stroke:var(--navy); stroke-width:2; stroke-linecap:round;
}

.phone-header{
  display:flex; align-items:center; justify-content:space-between;
  padding:.35em var(--pad) .3em;
}
/* neutral section chrome — fills the screen without revealing a feature */
.ph-section{
  margin:0;
  padding:.15em var(--pad) .45em;
  font-family:var(--font-display);
  font-weight:700; font-size:.6em; letter-spacing:.06em;
  text-transform:uppercase;
  color:#9C98B8;
}
.ph-title{
  font-family:var(--font-display);
  font-weight:800; font-size:.74em; letter-spacing:.04em;
  color:var(--navy);
}
.ph-caret{ color:var(--purple); font-size:.9em; }
.ph-bell{ width:1em; height:1em; }
.ph-bell svg{
  width:100%; height:100%;
  fill:none; stroke:var(--purple); stroke-width:1.8;
  stroke-linecap:round; stroke-linejoin:round;
}

.teaser-cards{
  flex:1;
  list-style:none; margin:0;
  padding:0 var(--pad) .7em;
  display:flex; flex-direction:column; gap:.62em;
}
.tcard{
  display:flex; align-items:center; gap:.62em;
  padding:.85em .7em;
  border-radius:.95em;
  background:#fff;
  box-shadow:0 .18em .5em rgba(30,27,58,.09);
}
.tc-ico{
  flex:none;
  width:2.6em; height:2.6em;
  border-radius:.72em;
  display:grid; place-items:center;
}
.tc-ico svg{
  width:1.45em; height:1.45em;
  fill:none; stroke-width:1.9; stroke-linecap:round; stroke-linejoin:round;
}
.ti-green{ background:#E4F8EC; }  .ti-green  svg{ stroke:#2FA36B; fill:#2FA36B; }
.ti-peach{ background:#FFEEE4; }  .ti-peach  svg{ stroke:#E8763F; }
.ti-blue{  background:#E7EEFF; }  .ti-blue   svg{ stroke:#4B6FD6; }
.ti-purple{background:var(--tint-purple);} .ti-purple svg{ stroke:var(--purple); }
.ti-pink{  background:var(--tint-coral); }  .ti-pink   svg{ stroke:var(--coral); }

.tc-body{ flex:1; min-width:0; }
.tc-body b{
  display:block;
  font-family:var(--font-display);
  font-weight:700; font-size:.78em; line-height:1.25;
  color:var(--navy);
}
.tc-body em{
  display:block; margin-top:.1em;
  font-style:normal; font-size:.64em; line-height:1.3;
  color:#7C789A;
}
/* default is the FINISHED state — if .play never lands (no JS, observer never
   fires) the card still reads correctly. The animation supplies the start. */
.tc-check{
  flex:none; width:1.4em; height:1.4em;
  border-radius:50%; background:#2FA36B;
  display:grid; place-items:center;
}
.tc-check svg{
  width:.7em; height:.7em;
  fill:none; stroke:#fff; stroke-width:3.4;
  stroke-linecap:round; stroke-linejoin:round;
}
.tc-bar{
  display:block; margin-top:.35em;
  height:.32em; border-radius:.32em;
  background:#E7E2F6;
  overflow:hidden;
}
/* width is the finished value; the fill animates via scaleX so the browser
   never re-runs layout mid-animation */
.tc-bar i{
  display:block; height:100%; width:var(--to,65%);
  transform-origin:left center;
  border-radius:inherit;
  background:linear-gradient(90deg,var(--purple-soft),var(--purple));
}
.tc-pct{
  flex:none;
  font-family:var(--font-display); font-weight:700; font-size:.62em;
  color:var(--purple);
}
.tc-star{ flex:none; color:var(--peach); font-size:.8em; }

/* An iOS 26 tab bar: the rim goes on the TOP edge here, not the bottom —
   the bar sits at the base of the screen, so the lit edge is the one facing
   the content above it. Inverting this is what makes a glass bar read as
   attached to the bottom rather than floating in the middle. */
.phone-nav{
  display:flex; align-items:center; justify-content:space-between;
  padding:.6em var(--pad) .95em;
  --glass-fill:rgba(255,255,255,.72);
  --glass-blur:14px;
  box-shadow:
    inset 0 1px 0 0 rgba(255,255,255,.9),
    0 -.15em .6em rgba(30,27,58,.07);
}
.pn-item{
  display:flex; flex-direction:column; align-items:center; gap:.16em;
  color:#A6A2BE;
}
.pn-item svg{
  width:1.15em; height:1.15em;
  fill:none; stroke:currentColor; stroke-width:1.9;
  stroke-linecap:round; stroke-linejoin:round;
}
.pn-item i{ font-style:normal; font-size:.5em; font-weight:700; font-family:var(--font-display); }
.pn-item.is-on{ color:var(--purple); }
.pn-item.is-on svg{ fill:var(--purple); stroke:var(--purple); }
.pn-add{
  width:1.9em; height:1.9em; border-radius:50%;
  background:linear-gradient(180deg,#6A4CE4,var(--purple));
  display:grid; place-items:center;
  box-shadow:0 .25em .5em rgba(91,63,209,.4);
  margin-top:-.5em;
}
.pn-add svg{
  width:1em; height:1em;
  fill:none; stroke:#fff; stroke-width:2.6; stroke-linecap:round;
}

/* One subtle cycle, never a loop (plan §25).
   Every keyframe is `from`-only with fill-mode `backwards`: the start state is
   held during the delay, then it animates to the value already in the base
   rule. Nothing here is required for the card to read correctly. */
@keyframes tc-pop{  from{ transform:scale(0); } }
@keyframes tc-grow{ from{ transform:scaleX(.954); } }   /* 62% of the 65% fill */
@keyframes tc-glow{ 50%{ opacity:1; } }

/* Paint-cheap highlight: an overlay fading in, not a background swap.
   The tint MUST be translucent — an absolutely positioned ::after paints above
   the card's static content, so an opaque fill would blank the text out at the
   peak of the animation instead of washing over it. */
.tcard{ position:relative; }
.tcard::after{
  content:""; position:absolute; inset:0;
  border-radius:inherit;
  background:rgba(255,165,143,.26);
  opacity:0; pointer-events:none;
}

@media (prefers-reduced-motion: no-preference){
  .phone.play .tc-check{ animation:tc-pop .45s var(--ease-spring) .5s backwards; }
  .phone.play .tc-bar i{ animation:tc-grow .9s var(--ease-out) 1.1s backwards; }
  .phone.play [data-card="dinner"]::after{ animation:tc-glow 1.8s ease 1.9s 1; }
}

/* ── "What do Paldo & Jonah mean?" ───────────────────────────────────── */
.naming{ padding-block:34px 46px; }
.naming-title{
  margin:0 0 26px;
  text-align:center;
  font-family:var(--font-display);
  font-weight:800;
  font-size:clamp(26px,3.4vw,40px);
  letter-spacing:-.5px;
  color:var(--navy);
}
.naming-title .script{
  font-family:var(--font-script);
  font-weight:400;
  font-size:1.16em;
  letter-spacing:0;
}
.naming-title .amp{ color:var(--navy); }

.naming-grid{
  display:grid;
  /* the side cards each carry a figure plus a paragraph, so they take the most
     width — but the centre still needs enough not to wrap its short lines into
     an overflow, since .name-card clips */
  grid-template-columns:1.16fr .78fr 1.16fr;
  gap:16px;
  align-items:stretch;
}
.name-card{
  position:relative;
  background:var(--card);
  border-radius:var(--radius-lg);
  box-shadow:var(--shadow);
  padding:20px;
  display:flex; gap:12px;
  overflow:hidden;
}
.name-paldo{ background:linear-gradient(150deg,#F3EFFF,#FBF9FF); }
.name-jonah{ background:linear-gradient(210deg,#FFF0EC,#FFFAF8); flex-direction:row-reverse; }

/* No interior crop box. A fixed-width overflow:hidden wrapper slices the
   silhouette with a straight vertical edge — through Paldo's shoulder and
   Jonah's hair — which reads as a rendering bug. Instead the figure bleeds
   past the card's padding and the card's own overflow:hidden + border-radius
   trims it, so the only cut follows the rounded corner. */
.name-fig{
  flex:none; align-self:flex-end;
  display:flex; align-items:flex-end;
}
.name-fig img{ width:auto; max-width:none; }
.name-paldo .name-fig{ margin:0 0 -20px -38px; }
.name-paldo .name-fig img{ height:236px; }
.name-jonah .name-fig{ margin:0 -38px -20px 0; }
.name-jonah .name-fig img{ height:252px; }

.name-body{ flex:1; min-width:0; }
.name-card h3{
  margin:0 0 6px;
  font-family:var(--font-display);
  font-weight:800; font-size:clamp(20px,2.1vw,26px);
  letter-spacing:.02em;
  color:var(--purple);
}
.name-jonah h3{ color:var(--coral); }
.nc-heart{ font-size:.8em; }
.name-lead{
  margin:0 0 8px;
  font-family:var(--font-display);
  font-weight:700; font-size:16.5px;
  color:var(--navy);
}
.name-copy{
  margin:0 0 14px;
  font-size:14.5px; line-height:1.55;
  color:var(--ink-soft);
}
.name-copy b{ color:var(--navy); font-weight:800; }

.keywords{
  list-style:none; margin:0; padding:0;
  display:flex; flex-wrap:wrap; gap:6px;
}
.keywords li{
  display:inline-flex; align-items:center; gap:5px;
  padding:6px 10px;
  border-radius:11px;
  background:#fff;
  box-shadow:var(--shadow-sm);
  font-family:var(--font-display);
  font-weight:700; font-size:12.5px;
  color:var(--navy);
  white-space:nowrap;
}
.keywords svg{
  width:15px; height:15px; flex:none;
  fill:none; stroke-width:1.9; stroke-linecap:round; stroke-linejoin:round;
}
.kw-purple svg{ stroke:var(--purple); }
.kw-coral  svg{ stroke:var(--coral); }

.name-center{
  flex-direction:column; justify-content:center; align-items:center;
  text-align:center;
  background:linear-gradient(180deg,#FFF6F2,#FFFDFC);
  padding:26px 18px;
}
.name-center p{
  margin:0 0 10px;
  font-family:var(--font-display);
  font-weight:600; font-size:clamp(15.5px,1.5vw,18px);
  line-height:1.4;
  color:var(--navy);
}
.name-center b{ font-weight:800; }
.center-heart{ display:block; width:38px; margin-bottom:12px; }
.center-heart svg{
  width:100%; fill:none; stroke:var(--coral); stroke-width:3.2;
  stroke-linejoin:round; stroke-linecap:round;
}
.center-rule{
  display:block; width:52px; height:3px; border-radius:3px;
  background:var(--peach);
  margin:6px 0 14px;
}
.center-close{ color:var(--ink-soft) !important; font-weight:600 !important; }

/* ── Money is only the beginning ─────────────────────────────────────── */
.beginning{
  display:grid;
  grid-template-columns:minmax(0,.92fr) minmax(0,1.4fr);
  gap:28px; align-items:center;
  padding-block:20px 50px;
}
.beg-kicker{
  margin:0 0 6px;
  font-family:var(--font-display);
  font-weight:700; font-size:clamp(18px,1.9vw,23px);
  line-height:1.25;
  color:var(--navy);
}
.beginning h2{
  margin:0 0 18px;
  font-family:var(--font-display);
  font-weight:800;
  font-size:clamp(28px,3.5vw,44px);
  line-height:1.06;
  letter-spacing:-1px;
  color:var(--navy);
}
.eyes{ font-size:.72em; }
.beg-body{
  margin:0 0 10px;
  font-size:15.5px; line-height:1.6;
  color:var(--ink-soft);
  max-width:44ch;
}
.beg-strong{
  font-family:var(--font-display);
  font-weight:800; font-size:16.5px;
  color:var(--navy);
}

.curiosity{
  list-style:none; margin:0; padding:0;
  display:grid; grid-template-columns:repeat(4,1fr); gap:14px;
  position:relative;
}
/* Glass over flat cream is just grey — the material has nothing to bend. So
   these cards get a backdrop built for them: three wide, heavily blurred
   colour washes sitting behind the row, echoing each card's own tint. They
   are invisible as shapes and only exist to be refracted.
   Absolutely positioned, so it never becomes a grid item. */
.curiosity::before{
  content:"";
  position:absolute; inset:-14% -6%;
  z-index:-1;
  background:
    radial-gradient(38% 60% at 14% 50%, rgba(139,109,255,.30), transparent 70%),
    radial-gradient(34% 58% at 47% 45%, rgba(255,107,107,.24), transparent 70%),
    radial-gradient(38% 60% at 84% 55%, rgba(255,165,143,.28), transparent 70%);
  filter:blur(26px);
  pointer-events:none;
}
.cur-card{
  display:flex; flex-direction:column; align-items:center; gap:8px;
  text-align:center;
  padding:24px 14px 22px;
  border-radius:var(--radius-lg);
  box-shadow:var(--shadow-sm);
  transition:transform .2s ease, box-shadow .2s ease;
}
/* the rim has to be repeated here — a bare box-shadow on hover would replace
   the insets and the card would momentarily stop being glass */
.cur-card:hover{
  transform:translateY(-5px);
  box-shadow:
    inset 0 1px 0 0 rgba(255,255,255,.9),
    inset 0 -1px 0 0 var(--glass-rim-low),
    0 18px 40px rgba(30,27,58,.14);
}
.cur-card b{
  font-family:var(--font-display);
  font-weight:800; font-size:16.5px;
  color:var(--navy);
  line-height:1.2;
}
.cur-card em{
  font-style:normal; font-size:13.5px; line-height:1.4;
  color:var(--ink-soft);
}
.cur-ico{ width:46px; height:46px; display:grid; place-items:center; }
.cur-ico svg{
  width:40px; height:40px;
  fill:none; stroke-width:1.7; stroke-linecap:round; stroke-linejoin:round;
}
/* Each card keeps its identity by tinting the glass rather than by painting a
   solid background — set --glass-fill and the shared material picks it up,
   sheen and rim included. */
.cur-purple{ --glass-fill:rgba(241,237,255,.55); }
.cur-purple .cur-ico svg{ stroke:var(--purple); }
.cur-coral{ --glass-fill:rgba(255,239,236,.55); }
.cur-coral .cur-ico svg{ stroke:var(--coral); fill:var(--coral); }
.cur-peach{ --glass-fill:rgba(255,243,228,.55); }
.cur-peach .cur-ico svg{ stroke:#E8763F; }
.cur-mystery{ --glass-fill:rgba(239,233,255,.55); }
.cur-mystery .cur-ico svg{ stroke:var(--purple-soft); }

/* ── Final CTA band ──────────────────────────────────────────────────── */
.band{ padding-block:10px 56px; }
.band-inner{
  position:relative;
  display:grid;
  grid-template-columns:minmax(0,.62fr) minmax(0,1.5fr) minmax(0,.62fr);
  align-items:end; gap:14px;
  padding:34px 30px 0;
  border-radius:var(--radius-lg);
  background:linear-gradient(105deg,var(--purple-deep) 0%,var(--purple) 38%,#8A4FD6 68%,#C55CA8 100%);
  color:#fff;
  box-shadow:var(--shadow-lg);
  overflow:hidden;
}
.band-inner::before,
.band-inner::after{
  content:""; position:absolute; border-radius:50%;
  background:rgba(255,255,255,.10);
}
.band-inner::before{ width:190px; height:190px; left:-50px; bottom:-80px; }
.band-inner::after{ width:130px; height:130px; right:14%; top:-64px; }

.band-fig{
  position:relative; z-index:1;
  display:block;
  align-self:end;
}
.band-fig img{
  width:100%; height:auto;
  filter:drop-shadow(0 12px 18px rgba(30,27,58,.28));
}
.band-fig-l img{ transform:rotate(-3deg); }
.band-fig-r img{ transform:rotate(3deg); }
.band-bubble{
  position:absolute; top:6%;
  width:2.4em; height:2.4em;
  display:grid; place-items:center;
  background:#fff; border-radius:50%;
  font-size:15px;
  box-shadow:var(--shadow);
}
.bb-l{ right:-4%; }
.bb-r{ left:-4%; }

.band-copy{
  position:relative; z-index:2;
  text-align:center;
  padding-bottom:34px;
}
.band-script{
  margin:0 0 4px;
  font-family:var(--font-script);
  font-size:clamp(22px,2.4vw,30px);
  color:#FFE7DF;
}
.band-copy h2{
  margin:0 0 10px;
  font-family:var(--font-display);
  font-weight:800;
  font-size:clamp(24px,2.7vw,36px);
  line-height:1.12;
  letter-spacing:-.5px;
}
.band-sub{
  margin:0 0 18px;
  font-size:15.5px;
  color:rgba(255,255,255,.92);
}
.band-sub b{ color:#FFE07A; font-weight:800; }
/* The one place on the page with a real backdrop: a purple-to-pink gradient
   plus two soft white circles. Glass has something to refract here, so this
   panel is pushed the furthest — a lower fill and a brighter rim. It still
   can't go fully translucent, because navy input text has to stay legible
   over a mid-purple gradient. .72 is where that stops being comfortable. */
.waitlist-onband{
  margin-inline:auto;
  --glass-fill:rgba(255,255,255,.72);
  --glass-rim:rgba(255,255,255,.95);
  border-color:rgba(255,255,255,.6);
  max-width:520px;
  box-shadow:
    inset 0 1px 0 0 var(--glass-rim),
    inset 0 -1px 0 0 rgba(255,255,255,.3),
    0 14px 40px rgba(30,27,58,.22);
}
.waitlist-onband:focus-within{
  border-color:rgba(255,255,255,.9);
  box-shadow:
    inset 0 1px 0 0 var(--glass-rim),
    inset 0 -1px 0 0 rgba(255,255,255,.3),
    0 0 0 4px rgba(255,255,255,.22),
    0 14px 40px rgba(30,27,58,.22);
}
.waitlist-onband input{ font-size:15.5px; }
/* The panel here is translucent over a mid-purple gradient, so the effective
   background behind this text is ~#DACEF2 rather than white — the page-level
   placeholder colour measures 1.9:1 against it. This is the same grey pushed
   dark enough to clear AA on that ground. */
.waitlist-onband input::placeholder{ color:#5A5578; }
.waitlist-onband .btn{ padding-inline:22px; font-size:15.5px; }
.waitlist-onband .form-note{ color:#FFE7DF; left:50%; transform:translateX(-50%); width:100%; text-align:center; }
.waitlist-onband .form-note.ok{ color:#fff; }
.band-micro{
  margin-top:38px;
  color:rgba(255,255,255,.88);
}
.band-micro .lock svg{ stroke:#fff; }
.band-early{
  margin:8px 0 0;
  font-size:13px;
  color:rgba(255,255,255,.7);
}

/* ── Legal pages (privacy.html / terms.html) ─────────────────────────── */
.legal{
  max-width:760px;
  padding-block:24px 60px;
}
.legal-back{ margin:0 0 22px; font-size:15px; }
.legal-back a{
  text-decoration:none; font-weight:700; color:var(--purple);
}
.legal-back a:hover{ text-decoration:underline; }

.legal h1{
  margin:0 0 6px;
  font-family:var(--font-display);
  font-weight:800;
  font-size:clamp(32px,4.4vw,50px);
  letter-spacing:-1px;
  line-height:1.05;
  color:var(--navy);
}
.legal-meta{
  margin:0 0 26px;
  font-size:14.5px; color:var(--ink-soft);
}
.legal h2{
  margin:34px 0 10px;
  font-family:var(--font-display);
  font-weight:800; font-size:clamp(19px,2vw,23px);
  color:var(--purple);
}
.legal p,
.legal li{
  font-size:16px; line-height:1.68; color:var(--ink-soft);
}
.legal p{ margin:0 0 14px; }
.legal ul{ margin:0 0 16px; padding-left:22px; }
.legal li{ margin-bottom:7px; }
.legal b{ color:var(--navy); font-weight:800; }
.legal a{ color:var(--purple); font-weight:700; }
.legal code{
  font-size:14px;
  background:var(--tint-purple);
  padding:2px 6px; border-radius:6px;
  color:var(--purple-deep);
}

/* the summary box at the top of each page */
.legal-note{
  background:var(--tint-purple);
  border-radius:var(--radius);
  padding:18px 22px;
  margin-bottom:8px;
}
.legal-note p{ margin:0; color:var(--navy); }

/* unresolved items — deliberately loud so they can't ship unnoticed */
.legal-todo{
  background:#FFF4E0;
  border-left:4px solid #E8A33F;
  border-radius:0 12px 12px 0;
  padding:12px 16px;
  font-size:15px;
}
.legal-todo b{ color:#8A5A12; }

/* ── Footer ───────────────────────────────────────────────────────────── */
.site-footer{ padding-block:6px 34px; }
.footer-inner{
  display:flex; align-items:center; gap:20px; flex-wrap:wrap;
  border-top:1px solid rgba(30,27,58,.08);
  padding-top:20px;
}
.footer-brand .wordmark.small{ line-height:1.2; }
.footer-tag{
  margin:0;
  font-family:var(--font-script);
  font-size:16px; color:var(--ink-soft);
}
.footer-nav{
  display:flex; align-items:center; gap:22px;
  margin-inline:auto;
  font-size:15.5px; color:var(--ink-soft);
}
.footer-nav a{ text-decoration:none; }
.footer-nav a:hover{ color:var(--purple); }
.copy{ margin:0; font-size:14px; line-height:1.6; color:var(--ink-soft); text-align:right; }
.copy .by{
  font-weight:700; color:var(--purple);
  text-decoration:none;
  border-bottom:1.5px solid rgba(91,63,209,.28);
}
.copy .by:hover{ border-bottom-color:var(--purple); }
.foot-heart{ color:var(--coral); }

/* ── Scroll reveal ────────────────────────────────────────────────────────
   Native scroll-driven animation, no JS. The hidden state lives ONLY in the
   `from` keyframe — never in a base rule — so anything that can't run the
   animation (no support, reduced motion, no JS at all) simply shows the
   finished content. There is no code path that can leave the page blank,
   which the previous opacity:0 + IntersectionObserver approach had.
   ───────────────────────────────────────────────────────────────────────── */
@keyframes reveal-up{
  from{ opacity:0; transform:translateY(22px); }
}

/* ── Ambient motion (plan §26) ────────────────────────────────────────────
   Everything here is transform/opacity only, so it stays on the compositor.
   `--play` is a custom property, and custom properties inherit — which is the
   trick that lets one class on the section pause every descendant animation
   at once. animation-play-state itself does not inherit.
   ───────────────────────────────────────────────────────────────────────── */
/* Default is RUNNING, and JS pauses what scrolls away — not the reverse.
   If the observer never fires the page still feels alive; pausing is only an
   optimisation, never a prerequisite for the motion to exist. */
.hero, .name-center{ --play:running; }
.hero.is-paused, .name-center.is-paused{ --play:paused; }

@keyframes float-a{ 50%{ translate:0 -4px; } }
@keyframes float-b{ 50%{ translate:0 -5px; } }
@keyframes drift  { 50%{ translate:0 -3px; } }
@keyframes twinkle{ 0%,100%{ opacity:.35; scale:.82; } 50%{ opacity:1; scale:1.1; } }
@keyframes pulse  { 50%{ scale:1.06; } }
@keyframes sway   { 50%{ translate:0 -2px; } }

@media (prefers-reduced-motion: no-preference){
  .hero-art .fig,
  .hero-art .phone,
  .hero-art .spark,
  .hero-art .bubble,
  .doodle-heart,
  .center-heart{
    animation-play-state:var(--play, running);
    animation-iteration-count:infinite;
    animation-direction:alternate;
    animation-timing-function:ease-in-out;
  }

  /* opposite phase so the two never bob in lockstep */
  .fig-paldo{ animation-name:float-a; animation-duration:var(--float-dur); }
  .fig-jonah{ animation-name:float-b; animation-duration:calc(var(--float-dur) + 1.2s); }
  .hero-art .phone{ animation-name:drift; animation-duration:calc(var(--float-dur) + 2s); }

  .hero-art .spark{ animation-name:twinkle; animation-duration:3.2s; }
  .hero-art .s2{ animation-duration:4.1s; animation-delay:-1.4s; }
  .hero-art .s3{ animation-duration:3.7s; animation-delay:-2.2s; }

  .doodle-heart,
  .center-heart{ animation-name:pulse; animation-duration:2.6s; }

  .hero-art .bubble{ animation-name:sway; animation-duration:4.4s; }
  .hero-art .bubble-jonah{ animation-duration:5.1s; animation-delay:-1.8s; }
}

/* ── Character hover reactions (plan §25) ─────────────────────────────────
   .bubble-paldo sits BEFORE .fig-paldo in the DOM, so no sibling combinator
   can reach it. :has() on the container solves it without extra markup, and
   the sparkles reused here are the decorative elements already in the hero.
   ───────────────────────────────────────────────────────────────────────── */
@media (hover: hover) and (prefers-reduced-motion: no-preference){
  .fig-paldo:hover{ rotate:-4deg; scale:1.035; }
  .fig-jonah:hover{ rotate:4deg;  scale:1.035; }

  .hero-art .bubble,
  .hero-art .spark,
  .hero-art .dash,
  .hero-art .mini-heart{
    transition:scale .3s var(--ease-spring), opacity .3s ease, rotate .3s ease;
  }

  /* Paldo → the left-hand decorations */
  .hero-art:has(.fig-paldo:hover) .bubble-paldo{ scale:1.08; rotate:-7deg; }
  .hero-art:has(.fig-paldo:hover) .s1,
  .hero-art:has(.fig-paldo:hover) .s2{ scale:1.5; opacity:1; }
  .hero-art:has(.fig-paldo:hover) .d1,
  .hero-art:has(.fig-paldo:hover) .d2{ scale:1.25; }
  .hero-art:has(.fig-paldo:hover) .mh1{ scale:1.3; }

  /* Jonah → the right-hand decorations */
  .hero-art:has(.fig-jonah:hover) .bubble-jonah{ scale:1.08; rotate:7deg; }
  .hero-art:has(.fig-jonah:hover) .s3{ scale:1.5; opacity:1; }
  .hero-art:has(.fig-jonah:hover) .d3{ scale:1.25; }
  .hero-art:has(.fig-jonah:hover) .mh2{ scale:1.3; }
}

@supports (animation-timeline: view()){
  @media (prefers-reduced-motion: no-preference){
    .naming-title,
    .name-card,
    .beginning-copy,
    .cur-card,
    .band-inner{
      animation:reveal-up var(--reveal-dur) var(--ease-out) both;
      animation-timeline:view();
      animation-range:entry 5% cover 22%;
    }

    /* Stagger. Scroll-driven animations have no time axis, so the offset has
       to come from the scroll range rather than animation-delay. */
    .naming-grid > :nth-child(2){ animation-range:entry 9%  cover 26%; }
    .naming-grid > :nth-child(3){ animation-range:entry 13% cover 30%; }

    .curiosity > :nth-child(2){ animation-range:entry 9%  cover 26%; }
    .curiosity > :nth-child(3){ animation-range:entry 13% cover 30%; }
    .curiosity > :nth-child(4){ animation-range:entry 17% cover 34%; }
  }
}

/* ── Responsive ───────────────────────────────────────────────────────── */

@media (max-width:1080px){
  .naming-grid{ grid-template-columns:1fr 1fr; }
  .name-center{ grid-column:1 / -1; order:3; }
  .beginning{ grid-template-columns:1fr; }
  .beg-body{ max-width:none; }
}

/* plan §38 — tablet: copy, then phone centred with the two flanking */
@media (max-width:900px){
  .site-nav{ display:none; }
  .header-cta{ padding:11px 20px; font-size:15px; }

  .hero{ grid-template-columns:1fr; text-align:center; padding-top:8px; }
  .hero-copy{ order:1; }
  .hero-art{ order:2; min-height:0; margin-top:26px; }
  /* full-bleed the blob turns into a very wide ellipse once the art column
     spans the whole shell — keep it roughly around the group instead */
  .hero-art .blob{
    inset:8% auto 8% 50%;
    width:min(100%, 620px);
    transform:translateX(-50%);
  }
  .doodle-heart{ display:none; }
  .lede{ margin-inline:auto; }
  .waitlist{ margin-inline:auto; }
  .form-note{ left:50%; transform:translateX(-50%); text-align:center; width:100%; }
  .tag-spark{ right:4%; }

  /* §15 — hide the bubbles rather than let them crowd the composition */
  .bubble{ display:none; }

  .band-inner{
    grid-template-columns:1fr 1fr;
    grid-template-areas:
      "copy copy"
      "figl figr";
    padding:30px 24px 0;
    gap:0 10px;
  }
  .band-copy{ grid-area:copy; padding-bottom:16px; }
  .band-fig-l{ grid-area:figl; justify-self:start; max-width:210px; }
  .band-fig-r{ grid-area:figr; justify-self:end; max-width:210px; }
}

@media (max-width:720px){
  .naming-grid{ grid-template-columns:1fr; }
  .name-center{ order:0; }
  .curiosity{ grid-template-columns:repeat(2,1fr); }
}

/* plan §39 — mobile hero: wordmark, headline, copy, waitlist, phone, duo */
@media (max-width:620px){
  body{ font-size:16px; }

  /* the wordmark and the CTA together overrun the bar well before 390px —
     both have to give, or the button gets clipped off the right edge */
  .header-inner{ gap:12px; }
  .wordmark{ gap:7px; }
  .wordmark-text{ font-size:24px; }
  .logo-mark{ width:40px; height:40px; }
  .header-cta{ padding:10px 16px; font-size:14px; }
  .header-cta .btn-heart{ display:none; }

  .hero-art{
    --fig-h:clamp(150px, 40vw, 220px);
    --phone-w:clamp(132px, 34vw, 170px);
    flex-wrap:nowrap;
  }
  /* keeps the centring from the 900px rule — only the vertical inset changes */
  .hero-art .blob{ top:16%; bottom:6%; width:min(112%, 420px); }
  .tagline{ font-size:clamp(24px,7vw,30px); }

  .waitlist{ border-radius:var(--radius); padding:10px; }
  .waitlist .btn{ width:100%; margin-top:6px; }
  .field{ width:100%; }

  .name-card{ padding:16px; }
  .name-paldo .name-fig{ margin:0 0 -16px -30px; }
  .name-paldo .name-fig img{ height:190px; }
  .name-jonah .name-fig{ margin:0 -30px -16px 0; }
  .name-jonah .name-fig img{ height:205px; }

  .band-inner{ padding:26px 18px 0; }
  .band-fig-l,.band-fig-r{ max-width:150px; }
  .band-micro{ margin-top:26px; font-size:13.5px; }

  .footer-inner{ justify-content:center; text-align:center; }
  .copy{ text-align:center; }
  .footer-brand{ width:100%; }
  .footer-nav{ order:3; width:100%; justify-content:center; gap:16px; }
}

@media (max-width:400px){
  .hero-art{ --fig-h:clamp(128px, 36vw, 170px); --phone-w:clamp(118px, 31vw, 145px); }
  .keywords li{ font-size:11.5px; padding:5px 8px; }
  .footer-nav{ gap:12px; font-size:14.5px; }
  .wordmark-text{ font-size:21px; }
  .header-cta{ padding:9px 13px; font-size:13px; }
}

/* Motion is now opt-in: every decorative, idle, and scroll-linked animation
   lives inside `prefers-reduced-motion: no-preference`, so calm is the default
   rather than something undone afterwards. This block stays as a backstop for
   any transition not covered above — and, unlike before, nothing needs to be
   restored here, because every animated element already renders its finished
   state without its animation. */
@media (prefers-reduced-motion:reduce){
  html{ scroll-behavior:auto; }
  *{ transition:none !important; animation:none !important; }
}
