/* ============================================================
   boba:3 — landing page
   tokens, layout, responsive, motion
   ============================================================ */

:root {
  /* surface */
  --bg-purple-top:    #D5C3EA;
  --bg-purple-bottom: #B89DDA;

  /* ink */
  --ink-dark:    #2A1B40;
  --ink-shadow:  rgba(54, 0, 112, 0.50);  /* purple drop on headline text */
  --ink-stroke:  #9764C3;                  /* outline on headline text */
  --ink-light:   #FBF6E9;

  /* frosted-glass UI (echoes the in-game brand system) */
  --frost-fill:   rgba(255, 255, 255, 0.55);
  --frost-stroke: rgba(42, 27, 64, 0.55);
  --frost-shadow: 0 4px 0 rgba(42, 27, 64, 0.20);

  /* form frame — solid lavender panel (per Figma spec, no border, no shadow) */
  --frame-fill:   #EACFFF;

  /* input — F9F0FF fill, dark purple stroke */
  --input-fill:   #F9F0FF;
  --input-stroke: #8B61B5;
  --input-ink:    #8B61B5;

  /* button — solid purple gradient (per Figma spec, no border) */
  --btn-grad-start: #BD91E4;
  --btn-grad-end:   #906DBA;

  /* cat sizing — tuned by viewport in media queries */
  --cat-size: 320px;
}

/* ============================================================
   reset
   ============================================================ */

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

html, body {
  margin: 0;
  padding: 0;
  height: 100%;
}

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

img {
  display: block;
  max-width: 100%;
  height: auto;
  -webkit-user-drag: none;
  user-select: none;
}

button {
  font: inherit;
  color: inherit;
  background: none;
  border: 0;
  padding: 0;
  cursor: inherit;
}

input { font: inherit; }

.visually-hidden {
  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;
  top: -100px;
  left: 12px;
  background: var(--ink-dark);
  color: var(--ink-light);
  padding: 8px 12px;
  border-radius: 8px;
  z-index: 100;
  text-decoration: none;
  font-family: 'Dongle', sans-serif;
  font-size: 22px;
}
.skip-link:focus { top: 12px; }

/* ============================================================
   page shell
   ============================================================ */

body {
  font-family: 'Dongle', system-ui, sans-serif;
  font-weight: 700;
  color: var(--ink-dark);
  background: linear-gradient(180deg, var(--bg-purple-top) 0%, var(--bg-purple-bottom) 100%);
  background-attachment: fixed;
  display: grid;
  grid-template-rows: auto 1fr;     /* topbar + stage; footer removed */
  min-height: 100vh;
  min-height: 100dvh;
  overflow-x: hidden;
  /* native cursor is the SVG sparkle as a fallback; on fine-pointer devices
     JS adds .has-custom-cursor on <html> to swap it for the animated div. */
  cursor: url('assets/cursor.svg') 18 18, auto;
}

button, input, a, label, [role="button"] {
  cursor: url('assets/cursor.svg') 18 18, pointer;
}

/* fine-pointer devices: hide native cursor, the JS-driven custom cursor takes over */
html.has-custom-cursor,
html.has-custom-cursor body,
html.has-custom-cursor button,
html.has-custom-cursor input,
html.has-custom-cursor a,
html.has-custom-cursor label,
html.has-custom-cursor [role="button"] {
  cursor: none;
}

/* ============================================================
   custom cursor — JS positions it; CSS animates it on press
   ============================================================ */

.custom-cursor {
  position: fixed;
  top: 0;
  left: 0;
  width: 36px;
  height: 36px;
  pointer-events: none;
  z-index: 9999;
  /* offsets are baked into translate so element rotates from its center */
  translate: var(--cur-x, -100px) var(--cur-y, -100px);
  opacity: 0;                                 /* hidden until first pointer move */
  transition: opacity 200ms ease;
  filter: drop-shadow(0 0 6px rgba(255, 255, 255, 0.55))
          drop-shadow(0 2px 6px rgba(54, 0, 112, 0.18));
  /* off by default; JS opts-in when a fine pointer is detected */
  display: none;
}
html.has-custom-cursor .custom-cursor { display: block; }
.custom-cursor.is-visible { opacity: 1; }

.custom-cursor-img {
  width: 100%;
  height: 100%;
  display: block;
  /* idle state: gentle continuous shimmer */
  animation: cursorShimmer 2.4s ease-in-out infinite;
  transform-origin: 50% 50%;
}

/* on press: magical spin + scale pop */
.custom-cursor.pressed .custom-cursor-img {
  animation: cursorSpin 600ms cubic-bezier(0.34, 1.56, 0.64, 1);
}

/* hover-on-button micro-effect: a tiny pulse */
.custom-cursor.over-target .custom-cursor-img {
  animation: cursorShimmer 1.4s ease-in-out infinite;
  scale: 1.15;
}

/* ============================================================
   topbar
   ============================================================ */

.topbar {
  display: flex;
  justify-content: center;
  align-items: center;
  padding: 14px 16px 12px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.6);
  background: rgba(255, 255, 255, 0.10);
  backdrop-filter: blur(2px);
  -webkit-backdrop-filter: blur(2px);
}

.topbar-logo {
  height: 36px;
  width: auto;
  filter: drop-shadow(0 2px 0 rgba(42, 27, 64, 0.18));
  animation: fadeIn 600ms ease-out 200ms backwards;
}

/* ============================================================
   stage — content + cat row
   ============================================================ */

.stage {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr);
  align-items: center;
  gap: clamp(24px, 6vw, 80px);
  padding: clamp(24px, 6vw, 80px) clamp(24px, 8vw, 120px);
}

/* ============================================================
   content (left column) — centered horizontally
   ============================================================ */

.content {
  position: relative;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;            /* center w/ the BOBA logo */
  text-align: center;
  max-width: 720px;
  margin: 0 auto;
  width: 100%;
  /* form sits one larger gap below the headline group */
  gap: clamp(20px, 2.6vw, 32px);
}

/* equal vertical rhythm between PLAY ↔ BOBA logo ↔ WHEN IT LAUNCHES */
.headline-group {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(6px, 1vw, 14px);
  width: 100%;
}

/* ============================================================
   headline text — white fill, purple stroke, purple drop
   ============================================================ */

.play-line,
.tagline {
  margin: 0;
  line-height: 1;                 /* tight, predictable line box for equal gap rhythm */
  letter-spacing: 0.06em;
}

/* PLAY and WHEN IT LAUNCHES share the same scale (per Shilat) */
.play-line,
.tagline {
  font-size: clamp(34px, 4vw, 56px);
}
.play-line { animation: wordmarkEnter 500ms ease-out 200ms backwards; }
.tagline   { animation: wordmarkEnter 500ms ease-out 300ms backwards; }

/*
  white-with-stroke text effect using a layered span:
  - <span> base layer is white, with -webkit-text-stroke for crisp purple outline
  - paint-order ensures stroke goes BEHIND fill so letters stay readable
  - text-shadow adds the soft purple drop below
*/
.play-line span,
.tagline span {
  display: inline-block;
  color: #FFFFFF;
  -webkit-text-stroke: 3.5px var(--ink-stroke);
  paint-order: stroke fill;
  text-shadow: 0 5px 0 var(--ink-shadow);
}

.wordmark {
  margin: 0;
  line-height: 0;
  animation: wordmarkEnter 500ms cubic-bezier(0.34, 1.56, 0.64, 1) 100ms backwards;
}
.wordmark img {
  width: clamp(280px, 36vw, 520px);
  height: auto;
  filter: drop-shadow(0 6px 0 rgba(42, 27, 64, 0.18));
}

/* ============================================================
   form frame (the soft lavender panel)
   per Figma: solid #EACFFF, 42px radius, 48px padding, no border, no shadow
   ============================================================ */

.form-frame {
  width: 100%;
  max-width: 720px;
  padding: clamp(18px, 3.4vw, 48px);
  background: var(--frame-fill);
  border-radius: clamp(28px, 3vw, 42px);
  animation: fadeInUp 500ms ease-out 600ms backwards;
}

.signup-form {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: clamp(12px, 1.6vw, 24px);
  width: 100%;
  transition: opacity 400ms ease;
}
.signup-form[data-submitted="true"] {
  opacity: 0.85;
  pointer-events: none;
}

.signup-form input[type="email"] {
  flex: 1 1 220px;
  min-width: 0;
  min-height: 64px;
  /* Dongle's cap-height sits in the upper half of the em-box, so the
     visual character gets pulled toward the top. extra padding-top
     compensates and visually centers the text in the pill. */
  padding: 18px 28px 8px;
  font-family: inherit;
  font-weight: 700;
  font-size: clamp(28px, 3vw, 44px);
  line-height: 1;
  letter-spacing: 0.03em;
  color: var(--input-ink);
  background: var(--input-fill);
  border: 5px solid var(--input-stroke);
  border-radius: 999px;
  outline: none;
  transition: border-color 180ms ease, box-shadow 180ms ease, transform 180ms ease;
  text-align: center;
}
.signup-form input::placeholder {
  color: var(--input-ink);
  opacity: 0.85;
  font-weight: 700;
}
.signup-form input:focus-visible {
  box-shadow: 0 0 0 4px rgba(139, 97, 181, 0.30);
}

.signup-btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 64px;
  /* same Dongle ascender compensation as the input */
  padding: 18px 36px 8px;
  font-family: inherit;
  font-weight: 700;
  font-size: clamp(28px, 3vw, 44px);
  line-height: 1;
  letter-spacing: 0.06em;
  color: #FFFFFF;
  background: linear-gradient(180deg, var(--btn-grad-start) 0%, var(--btn-grad-end) 100%);
  border: 0;
  border-radius: 999px;
  transition: transform 160ms ease, filter 160ms ease;
  text-shadow: 0 1px 0 rgba(42, 27, 64, 0.20);
}
.signup-btn:hover {
  transform: scale(1.03) translateY(-1px);
  filter: brightness(1.06) saturate(1.04);
}
.signup-btn:active {
  transform: scale(0.97) translateY(1px);
  filter: brightness(0.96);
}
.signup-btn:focus-visible {
  outline: 3px solid var(--input-stroke);
  outline-offset: 3px;
}

/* ============================================================
   cat stage (right column)
   ============================================================ */

.cat-stage {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding-bottom: clamp(20px, 3vw, 36px);
}

/*
  Layering:  .cat-stage
                ├─ ground shadow (separate element, has its own pulse)
                └─ .cat                   <-- entrance + JS bob (vertical translate)
                     └─ .cat-breathe       <-- CSS squash/stretch
                          ├─ body
                          ├─ face anchor(s) → face image(s) translate per cursor
                          └─ reflection
*/

.cat {
  position: relative;
  width: var(--cat-size);
  aspect-ratio: 378 / 375;
  transform: translate3d(0, var(--cat-bob, 0px), 0);
  animation: catEnter 600ms cubic-bezier(0.34, 1.56, 0.64, 1) 100ms backwards;
  filter: drop-shadow(0 12px 24px rgba(42, 27, 64, 0.10));
  will-change: transform;
}

.cat-breathe {
  position: relative;
  width: 100%;
  height: 100%;
  transform-origin: 50% 82%;       /* squash from the base, like a real squish */
  animation: catBreathe 3.4s ease-in-out 700ms infinite;
}

.cat-body,
.cat-reflection {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

/* anchor centers each face layer inside the body box;
   js translates the inner img by --face-x / --face-y */
.cat-face-anchor {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  pointer-events: none;
}
.cat-face {
  height: auto;
  transform: translate3d(var(--face-x, 0px), var(--face-y, 0px), 0);
  will-change: transform;
}

/* face1 — ears + whiskers + blush (350×313 native, fills most of body) */
.cat-face--back {
  width: calc(350 / 378 * 100%);
}

/* face2 — eyes + mouth (199×60 native).
   sits at the cat's eye/mouth zone (roughly mid-body, slightly above center) */
.cat-face-anchor--front {
  /* push the centered face2 up a bit so it lands on the eye row, not body center */
  transform: translateY(-3%);
  /* stack regular + happy variants in the same grid cell so they overlap */
  grid-template-areas: "stack";
}
.cat-face-anchor--front > .cat-face {
  grid-area: stack;
}
.cat-face--front {
  width: calc(199 / 378 * 100%);
}

.cat-reflection {
  inset: 0 1.5px;
  mix-blend-mode: screen;
  opacity: 0.95;
}

.cat-ground-shadow {
  width: calc(var(--cat-size) * 0.95);
  height: auto;
  margin-top: calc(var(--cat-size) * -0.18);
  opacity: 0.55;
  pointer-events: none;
  animation: shadowPulse 3.4s ease-in-out 700ms infinite;
}

/* ============================================================
   celebration eyes+mouth swap — only the front face layer changes
   on submit. body / face-back / reflection / shadow all stay live.
   ============================================================ */

.cat-face--happy {
  opacity: 0;
  scale: 0.82;
  transition: opacity 280ms ease, scale 480ms cubic-bezier(0.34, 1.56, 0.64, 1);
}

/* on submit: regular front face fades out, happy face pops in */
body.is-submitted .cat-face--front:not(.cat-face--happy) {
  opacity: 0;
  transition: opacity 240ms ease;
}
body.is-submitted .cat-face--happy {
  opacity: 1;
  scale: 1;
  transition-delay: 80ms;        /* small offset so the swap reads */
}

/* ============================================================
   sparkles — ambient decoration
   uses sparkle.png (white, glowy) — soft + alive
   ============================================================ */

.sparkles {
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 0;
}

.sparkle {
  position: absolute;
  display: block;
  background-image: url('assets/sparkle.png');
  background-size: contain;
  background-repeat: no-repeat;
  background-position: center;
  opacity: 0;
  filter: drop-shadow(0 0 8px rgba(255, 255, 255, 0.7));
  animation: twinkle var(--twk-d, 2.8s) ease-in-out infinite,
             driftA   var(--drf-d, 6s)   ease-in-out infinite,
             fadeIn   600ms              ease-out backwards;
}

/* hand-placed positions + sizes; durations + delays staggered for life */
.sparkle--1  { top:  6%;  left:  4%;  width: 36px; height: 36px;
               --twk-d: 2.4s;  --drf-d: 6.0s;
               animation-delay: 0s,    0s,    400ms; }
.sparkle--2  { top: 18%;  left: 28%;  width: 22px; height: 22px;
               --twk-d: 3.1s;  --drf-d: 7.5s;
               animation-delay: 0.5s,  0.7s,  500ms; }
.sparkle--3  { top: 12%;  left: 56%;  width: 44px; height: 44px;
               --twk-d: 2.7s;  --drf-d: 5.4s;
               animation-delay: 0.9s,  0.2s,  600ms; }
.sparkle--4  { top:  4%;  left: 80%;  width: 26px; height: 26px;
               --twk-d: 3.6s;  --drf-d: 8.0s;
               animation-delay: 1.3s,  1.0s,  700ms; }
.sparkle--5  { top: 36%;  left: 90%;  width: 18px; height: 18px;
               --twk-d: 2.0s;  --drf-d: 6.5s;
               animation-delay: 0.7s,  0.3s,  800ms; }
.sparkle--6  { top: 58%;  left:  2%;  width: 30px; height: 30px;
               --twk-d: 3.0s;  --drf-d: 7.2s;
               animation-delay: 1.5s,  0.6s,  900ms; }
.sparkle--7  { top: 70%;  left: 22%;  width: 16px; height: 16px;
               --twk-d: 2.2s;  --drf-d: 5.8s;
               animation-delay: 0.3s,  0.9s, 1000ms; }
.sparkle--8  { top: 82%;  left: 64%;  width: 38px; height: 38px;
               --twk-d: 2.9s;  --drf-d: 6.8s;
               animation-delay: 1.0s,  0.4s, 1100ms; }
.sparkle--9  { top: 88%;  left: 88%;  width: 24px; height: 24px;
               --twk-d: 2.5s;  --drf-d: 7.0s;
               animation-delay: 0.2s,  1.1s, 1200ms; }
.sparkle--10 { top: 44%;  left: 42%;  width: 14px; height: 14px;
               --twk-d: 1.8s;  --drf-d: 5.2s;
               animation-delay: 1.7s,  0.5s, 1300ms; }
.sparkle--11 { top: 28%;  left: 70%;  width: 32px; height: 32px;
               --twk-d: 3.4s;  --drf-d: 8.4s;
               animation-delay: 0.6s,  0.0s, 1400ms; }
.sparkle--12 { top: 64%;  left: 50%;  width: 20px; height: 20px;
               --twk-d: 2.6s;  --drf-d: 6.2s;
               animation-delay: 1.2s,  0.8s, 1500ms; }

.sparkle.spawn {
  animation: spawnPop 700ms ease-out forwards;
  width: 32px;
  height: 32px;
  filter: drop-shadow(0 0 10px rgba(255, 255, 255, 0.8));
}

/* ============================================================
   keyframes
   ============================================================ */

@keyframes fadeIn {
  from { opacity: 0; }
  to   { opacity: 1; }
}

@keyframes fadeInUp {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: translateY(0); }
}

@keyframes wordmarkEnter {
  from { opacity: 0; transform: scale(0.96); }
  to   { opacity: 1; transform: scale(1); }
}

@keyframes catEnter {
  from { opacity: 0; transform: translate3d(0, 16px, 0) scale(0.94); }
  to   { opacity: 1; transform: translate3d(0, var(--cat-bob, 0px), 0) scale(1); }
}

/* idle squash & stretch — subtle breathing, ~1.5% scale change */
@keyframes catBreathe {
  0%   { transform: scale(1.000, 1.000); }
  40%  { transform: scale(1.015, 0.988); }   /* gentle inhale squish */
  70%  { transform: scale(0.994, 1.008); }   /* tiny exhale stretch */
  100% { transform: scale(1.000, 1.000); }
}

/* twinkle — opacity + scale + small rotation */
@keyframes twinkle {
  0%, 100% { transform: scale(0.78) rotate(-6deg); opacity: 0.35; }
  50%      { transform: scale(1.10) rotate( 8deg); opacity: 1.00; }
}

/* slow ambient drift — adds layered motion on top of twinkle.
   keyframes use translate via individual transform property
   so it composes with the parent twinkle scale/rotate */
@keyframes driftA {
  0%, 100% { translate: 0 0; }
  25%      { translate: 6px -4px; }
  50%      { translate: -3px 3px; }
  75%      { translate: 4px 5px; }
}

@keyframes shadowPulse {
  0%, 100% { transform: scaleX(1.00); opacity: 0.55; }
  40%      { transform: scaleX(1.03); opacity: 0.58; }   /* matches catBreathe squish */
  70%      { transform: scaleX(0.98); opacity: 0.50; }
}

@keyframes spawnPop {
  0%   { transform: scale(0)   rotate(-20deg); opacity: 0; }
  30%  { transform: scale(1.2) rotate(  0deg); opacity: 1; }
  100% { transform: scale(0)   rotate( 25deg); opacity: 0; }
}

/* cursor: gentle idle shimmer (slight rotation + scale pulse) */
@keyframes cursorShimmer {
  0%, 100% { transform: rotate(0deg)   scale(1.00); }
  50%      { transform: rotate(8deg)   scale(1.06); }
}

/* cursor: full magical spin on click — overshoots slightly */
@keyframes cursorSpin {
  0%   { transform: rotate(0deg)    scale(1.00); }
  35%  { transform: rotate(180deg)  scale(1.45); }
  70%  { transform: rotate(330deg)  scale(0.92); }
  100% { transform: rotate(360deg)  scale(1.00); }
}

/* ============================================================
   responsive — tablet
   ============================================================ */

@media (max-width: 1199px) {
  :root { --cat-size: 280px; }
  .stage { padding: clamp(20px, 4vw, 60px) clamp(20px, 5vw, 60px); gap: 24px; }
  .signup-form input[type="email"] { flex-basis: 160px; }
}

/* ============================================================
   responsive — mobile (<768px) — stack vertical, cat below form
   ============================================================ */

@media (max-width: 767px) {
  :root { --cat-size: 60vw; }

  .topbar { padding: 10px 12px; }
  .topbar-logo { height: 28px; }

  .stage {
    grid-template-columns: 1fr;
    padding: 24px 22px 12px;
    gap: 12px;
  }

  .content { max-width: 100%; order: 1; }

  /* PLAY and WHEN IT LAUNCHES stay equal-sized on mobile too */
  .play-line,
  .tagline { font-size: clamp(28px, 8vw, 44px); }
  .play-line span,
  .tagline   span { -webkit-text-stroke-width: 2.6px; }

  .wordmark img { width: min(82vw, 380px); }

  /* mobile frame: tighter padding, much less rounded corners (per Shilat: not pill on mobile) */
  .form-frame {
    max-width: 380px;
    padding: 14px;
    border-radius: 22px;
  }
  .signup-form { flex-direction: column; gap: 10px; }
  .signup-form input[type="email"],
  .signup-btn {
    flex: 0 0 auto;
    width: 100%;
    min-height: 54px;
    height: 54px;
    font-size: 26px;
    border-width: 4px;            /* thinner stroke on mobile so it fits the smaller pill */
  }
  .signup-btn { border-width: 0; }

  .cat-stage { order: 2; }
  .cat       { max-width: 70vw; }

  .sparkle--2,
  .sparkle--6,
  .sparkle--10,
  .sparkle--11 { display: none; }
}

@media (max-width: 380px) {
  .play-line span,
  .tagline   span { -webkit-text-stroke-width: 2.2px; }
}

/* ============================================================
   reduced motion
   ============================================================ */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
  .cat-face   { transform: none !important; }
  .cat,
  .cat-breathe { transform: none !important; }
  .sparkle    { opacity: 0.7 !important; }
}
