/* ============================================================
   SPARE ME! — Teaser landing page
   ------------------------------------------------------------
   The page is a poster locked to the Figma frame (1440 x 1024).
   --u  = one Figma pixel, scaled to fit the viewport
   --fx = the frame's left edge, --fy = the frame's top edge
   Every position and size below is the literal Figma value
   multiplied by --u, so the composition never re-flows.
   ============================================================ */

@font-face {
  font-family: "Neue Montreal";
  src: url("fonts/NeueMontreal-Bold.otf") format("opentype");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

:root {
  --green:  #04954E;
  --yellow: #FFEA03;
  --cta:    #D4E919;
  --rule:   #D9D9D9;
  --slogan: rgba(255, 234, 3, 0.45);
  --placeholder: rgba(255, 255, 255, 0.70); /* a11y: raised from Figma's 45% */

  /* fit the 1440 x 1024 frame inside the viewport, preserving its ratio */
  --u:  min(0.09765625vh,  0.06944444vw);   /* fallback for old browsers */
  --u:  min(0.09765625dvh, 0.06944444vw);   /* dvh = the live visible height */
  --fx: calc(50vw - 720 * var(--u));
  --fy: calc(50dvh - 512 * var(--u));
}

*, *::before, *::after { box-sizing: border-box; }
html, body { height: 100%; }
body {
  margin: 0;
  background: var(--green);
  color: var(--yellow);
  font-family: "Neue Montreal", "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-weight: 700;
  overflow: hidden;
  -webkit-font-smoothing: antialiased;
}
img, svg { display: block; }
a { color: var(--cta); text-decoration: none; }
a:hover { color: var(--yellow); }

.poster {
  position: relative;
  width: 100%;
  height: 100dvh;
  overflow: hidden;
  opacity: 0;
  transition: opacity 700ms ease;
}
.is-ready .poster { opacity: 1; }

/* ---------- Eyebrow — Figma x1082 y45, 16.5513px ---------- */
.eyebrow {
  position: absolute;
  top: calc(var(--fy) + 45 * var(--u));
  right: calc(var(--fx) + 72 * var(--u));
  margin: 0;
  font-size: calc(16.5513 * var(--u));
  line-height: calc(15.401 * var(--u));
  letter-spacing: -0.03em;
  color: var(--yellow);
  white-space: nowrap;
}

/* ---------- Logo — Figma 787.196 x 261.536 at x576.769 y121.589 ---------- */
.logo {
  position: absolute;
  top: calc(var(--fy) + 121.589 * var(--u));
  right: calc(var(--fx) + 76.035 * var(--u));
  width: calc(787.196 * var(--u));
  height: calc(261.536 * var(--u));
}

/* ---------- Slogan — Figma y357.552, 51.0805px, right edge 1364.518 ---------- */
.slogan {
  position: absolute;
  top: calc(var(--fy) + 357.552 * var(--u));
  right: calc(var(--fx) + 75.482 * var(--u));
  margin: 0;
  font-size: calc(51.0805 * var(--u));
  line-height: calc(53.402 * var(--u));
  letter-spacing: -0.03em;
  color: var(--slogan);
  white-space: nowrap;
}

/* ---------- Hero — Figma 684 x 921 at x-42 y166.641 ----------
   Vertically locked to the frame. Horizontally it bleeds off the
   real left edge of the screen (rather than off the frame edge),
   so the photograph never shows a floating crop line on wide
   monitors. On viewports at or below the Figma ratio the two are
   the same thing.                                                */
.hero {
  position: absolute;
  left: calc(-42 * var(--u));
  top: calc(var(--fy) + 166.641 * var(--u));
  width: calc(684 * var(--u));
  height: calc(921 * var(--u));
}
.hero__photo {
  position: absolute;
  left: 0;
  top: 7.1661%;      /* Figma 66 / 921  — kept as ratios so the hero */
  width: 100%;       /* block can be rescaled per breakpoint without   */
  height: 92.8339%;  /* the lettering losing registration with it      */
  object-fit: cover;
  object-position: center;
}

/* ---------- Handwritten "COMING SOON!" ---------- */
.coming-soon {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  color: var(--yellow);
  overflow: visible;
  pointer-events: none;
}
.cs-letter {
  clip-path: inset(0 0 100% 0);
  pointer-events: none;              /* enabled by JS once drawn */
}
.cs-wob {
  transform-box: fill-box;
  transform-origin: 50% 50%;
  /* transform is driven per-frame by the spring loop in script.js */
}
.is-drawn .cs-letter { pointer-events: auto; }

/* ---------- Signup — Figma 427 wide at x946 y929.216 ---------- */
.signup {
  position: absolute;
  top: calc(var(--fy) + 929.216 * var(--u));
  right: calc(var(--fx) + 67 * var(--u));
  width: calc(427 * var(--u));
}
.signup__row {
  display: flex;
  align-items: baseline;
  gap: calc(24 * var(--u));
  padding-bottom: calc(3.1 * var(--u));   /* underline lands at Figma y22.131 */
  border-bottom: calc(1.302 * var(--u)) solid var(--rule);
  transition: border-color 240ms ease;
}
.signup__row:hover { border-bottom-color: #FFFFFF; }
.signup__row:focus-within { border-bottom-color: var(--yellow); }

.signup__input {
  flex: 1 1 auto;
  min-width: 0;
  appearance: none;
  background: none;
  border: 0;
  padding: 0;
  color: #FFFFFF;
  font: inherit;
  font-size: calc(15.62195 * var(--u));
  line-height: 1;
  letter-spacing: 0.06em;
}
.signup__input::placeholder { color: var(--placeholder); }
.signup__input:focus { outline: none; }

.signup__cta {
  flex: 0 0 auto;
  appearance: none;
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
  color: var(--cta);
  font: inherit;
  font-size: calc(25.27632 * var(--u));
  line-height: 1;
  letter-spacing: -0.02em;
  white-space: nowrap;
  transition: transform 220ms cubic-bezier(.22,.61,.36,1), color 220ms ease, opacity 220ms ease;
}
.signup__cta:hover { transform: translateY(calc(-3 * var(--u))); color: var(--yellow); }
.signup__cta:disabled { opacity: 0.5; cursor: default; transform: none; }

.signup__msg {
  margin: calc(13 * var(--u)) 0 0;
  min-height: calc(18 * var(--u));
  font-size: calc(15.62195 * var(--u));
  line-height: calc(18 * var(--u));
  letter-spacing: 0.06em;
  color: var(--yellow);
  opacity: 0;
  transform: translateY(calc(4 * var(--u)));
  transition: opacity 300ms ease, transform 300ms ease;
}
.signup__msg.is-visible { opacity: 1; transform: none; }
.signup__msg.is-error { color: #FFFFFF; }

/* ---------- Branded success state ---------- */
.signup__row,
.signup__msg { transition: opacity 260ms ease, transform 260ms ease, border-color 240ms ease; }
.signup.is-success .signup__row {
  opacity: 0;
  transform: translateY(calc(-5 * var(--u)));
  pointer-events: none;
}
.signup.is-success .signup__msg { opacity: 0; }

.signup__success {
  position: absolute;
  top: 0;
  right: 0;
  text-align: right;
}
.signup__strike,
.signup__strike-sub { margin: 0; white-space: nowrap; }

.signup__strike {
  font-size: calc(52 * var(--u));
  line-height: calc(48 * var(--u));
  letter-spacing: -0.035em;
  color: var(--yellow);
  clip-path: inset(-30% 0 0 0);
  animation: strike-in 480ms cubic-bezier(.14, .9, .24, 1.24) 150ms both;
}
.signup__strike-sub {
  margin-top: calc(10 * var(--u));
  font-size: calc(15.62195 * var(--u));
  line-height: calc(18 * var(--u));
  letter-spacing: 0.06em;
  color: rgba(255, 255, 255, 0.7);
  animation: sub-in 300ms ease 520ms both;
}
@keyframes strike-in {
  from { opacity: 0; transform: translateY(calc(22 * var(--u))); clip-path: inset(100% 0 0 0); }
  60%  { opacity: 1; }
  to   { opacity: 1; transform: translateY(0);                   clip-path: inset(-30% 0 0 0); }
}
@keyframes sub-in {
  from { opacity: 0; transform: translateY(calc(5 * var(--u))); }
  to   { opacity: 1; transform: none; }
}

:focus-visible {
  outline: max(2px, calc(2 * var(--u))) solid var(--yellow);
  outline-offset: max(3px, calc(4 * var(--u)));
}

/* Honeypot — off-screen rather than display:none, which bots skip */
.signup__trap {
  position: absolute;
  left: -9999px;
  width: 1px; height: 1px;
  opacity: 0;
  pointer-events: none;
}

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

/* ---------- Film grain ---------- */
.grain {
  position: fixed;
  inset: -60px;
  z-index: 40;
  pointer-events: none;
  opacity: 0.055;
  background-image: url("assets/grain.png");
  background-size: 200px 200px;
  animation: grain-shift 1500ms steps(1, end) infinite;
  will-change: transform;
}
@keyframes grain-shift {
  0%   { transform: translate3d(  0px,   0px, 0); }
  20%  { transform: translate3d(-37px,  19px, 0); }
  40%  { transform: translate3d( 23px, -41px, 0); }
  60%  { transform: translate3d(-18px, -23px, 0); }
  80%  { transform: translate3d( 44px,  11px, 0); }
  100% { transform: translate3d(  0px,   0px, 0); }
}

/* ---------- Custom cursor ---------- */
.cursor {
  position: fixed;
  left: 0; top: 0;
  z-index: 50;
  width: 46px; height: 46px;
  margin: -23px 0 0 -23px;
  pointer-events: none;
  opacity: 0;
  transition: opacity 300ms ease;
  will-change: transform;
}
.has-cursor .cursor { opacity: 1; }
.has-cursor,
.has-cursor a,
.has-cursor button,
.has-cursor input,
.has-cursor .cs-letter { cursor: none; }

/* ---------- Load-in choreography ---------- */
.anim { opacity: 0; }
.is-ready .anim {
  animation: rise 980ms cubic-bezier(.16, 1, .3, 1) forwards;
  animation-delay: var(--d, 0ms);
}
@keyframes rise {
  from { opacity: 0; transform: translateY(calc(18 * var(--u))); }
  to   { opacity: 1; transform: none; }
}
.hero__photo.anim { animation-duration: 1240ms; }
.logo, .hero, .coming-soon { will-change: transform; }

/* ---------- Ambient life ----------
   Sub-perceptual drift so the poster never looks frozen. Each layer
   moves on its own clock, so they never line up into a visible pulse. */
.is-ready .logo {
  animation: rise 980ms cubic-bezier(.16,1,.3,1) var(--d, 0ms) forwards,
             breathe 13s 2.4s ease-in-out infinite alternate;
}
.is-ready .hero        { animation: drift-hero 14.5s 2.2s ease-in-out infinite alternate; }
.is-ready .coming-soon { animation: drift-type 17.5s 3.1s ease-in-out infinite alternate; }

@keyframes breathe    { from { transform: scale(1); }        to { transform: scale(1.007); } }
@keyframes drift-hero { from { transform: translate3d(0,0,0); }
                        to   { transform: translate3d(1.5px, -2.5px, 0); } }
@keyframes drift-type { from { transform: translate3d(0,0,0); }
                        to   { transform: translate3d(-1.5px, 1.5px, 0); } }

.is-ready .cs-letter {
  animation: cs-draw 380ms ease-out forwards;
  animation-delay: calc(900ms + var(--i) * 110ms);
}
@keyframes cs-draw {
  from { clip-path: inset(0 0 100% 0); }
  to   { clip-path: inset(-25% -25% -25% -25%); }  /* room for the hover wobble */
}

/* ---------- Reduced motion ---------- */
@media (prefers-reduced-motion: reduce) {
  .poster { transition: none; }
  .anim, .is-ready .anim { opacity: 1; animation: none; transform: none; }
  .cs-letter, .is-ready .cs-letter { clip-path: none; animation: none; }
  .cs-wob { transition: none; transform: none; }
  .grain { animation: none; }
  .is-ready .logo, .is-ready .hero, .is-ready .coming-soon { animation: none; }
  .signup__strike, .signup__strike-sub { animation: none; clip-path: none; opacity: 1; }
  .signup.is-success .signup__row { transform: none; }
  .cursor { display: none; }
  .has-cursor, .has-cursor a, .has-cursor button,
  .has-cursor input, .has-cursor .cs-letter { cursor: auto; }
  .signup__cta:hover { transform: none; }
}


/* ============================================================
   TABLET — PORTRAIT
   Art-directed on its own 834 x 1194 poster frame. Nothing is
   stacked: the logo goes full-measure across the top, the hero
   drops to the lower left and keeps its bleed, and the signup
   line moves into the green the hero leaves free on the right.
   Landscape tablets keep the desktop frame — their ratio is
   already close to the Figma's 1.406.
   ============================================================ */
@media (max-aspect-ratio: 1/1) and (min-width: 601px) {
  :root {
    --u:  min(0.0837521vh,  0.1199041vw);   /* 834 x 1194 */
    --u:  min(0.0837521dvh, 0.1199041vw);
    --fx: calc(50vw - 417 * var(--u));
    --fy: calc(50dvh - 597 * var(--u));
  }
  .eyebrow {
    top: calc(var(--fy) + 56 * var(--u));
    right: calc(var(--fx) + 48 * var(--u));
    font-size: calc(19 * var(--u));
    line-height: calc(18 * var(--u));
  }
  .logo {
    top: calc(var(--fy) + 104 * var(--u));
    right: calc(var(--fx) + 48 * var(--u));
    width: calc(738 * var(--u));
    height: calc(245.19 * var(--u));
  }
  .slogan {
    top: calc(var(--fy) + 358 * var(--u));   /* lockup tightened ~40% */
    right: calc(var(--fx) + 48 * var(--u));
    font-size: calc(47.88 * var(--u));
    line-height: calc(50 * var(--u));
  }
  .hero {
    left: calc(-60 * var(--u));
    top: calc(var(--fy) + 400 * var(--u));
    width: calc(480 * var(--u));
    height: calc(646.3 * var(--u));
  }
  .signup {
    top: calc(var(--fy) + 1076 * var(--u));
    right: calc(var(--fx) + 48 * var(--u));
    width: calc(738 * var(--u));
  }
  .signup__row  { gap: calc(16 * var(--u)); padding-bottom: calc(4 * var(--u)); }
  .signup__input, .signup__msg { font-size: calc(19 * var(--u)); }
  .signup__cta  { font-size: calc(30 * var(--u)); }
  .signup__strike { font-size: calc(58 * var(--u)); line-height: calc(52 * var(--u)); }
  .signup__strike-sub { font-size: calc(19 * var(--u)); margin-top: calc(12 * var(--u)); }
}

/* ============================================================
   MOBILE
   Its own 390 x 844 frame. Same three-beat rhythm as desktop —
   oversized logo, dominant hero bleeding off the left edge,
   signup line at the foot — recomposed vertically rather than
   stacked, with the negative space kept intact.
   ============================================================ */
@media (max-width: 600px) {
  :root {
    --u:  min(0.1184834vh,  0.2564103vw);   /* 390 x 844 */
    --u:  min(0.1184834dvh, 0.2564103vw);
    --fx: calc(50vw - 195 * var(--u));
    --fy: calc(50dvh - 422 * var(--u));
  }
  .eyebrow {
    top: calc(var(--fy) + 44 * var(--u));
    right: calc(var(--fx) + 24 * var(--u));
    font-size: calc(12 * var(--u));
    line-height: calc(12 * var(--u));
  }
  .logo {
    top: calc(var(--fy) + 92 * var(--u));
    right: calc(var(--fx) + 24 * var(--u));
    width: calc(342 * var(--u));
    height: calc(113.65 * var(--u));
  }
  .slogan {
    top: calc(var(--fy) + 213 * var(--u));   /* lockup tightened ~40% */
    right: calc(var(--fx) + 24 * var(--u));
    font-size: calc(22.19 * var(--u));
    line-height: calc(23 * var(--u));
  }
  .hero {
    left: calc(-30 * var(--u));
    top: calc(var(--fy) + 258 * var(--u));
    width: calc(360 * var(--u));
    height: calc(484.7 * var(--u));
  }
  .signup {
    top: calc(var(--fy) + 754 * var(--u));
    right: calc(var(--fx) + 24 * var(--u));
    width: calc(342 * var(--u));
  }
  .signup__row  { gap: calc(12 * var(--u)); padding-bottom: calc(3 * var(--u)); }
  .signup__input { font-size: calc(15 * var(--u)); }
  .signup__msg   { font-size: calc(14 * var(--u)); margin-top: calc(10 * var(--u)); }
  .signup__cta   { font-size: calc(23.5 * var(--u)); }
  .signup__strike { font-size: calc(34 * var(--u)); line-height: calc(32 * var(--u)); }
  .signup__strike-sub { font-size: calc(14 * var(--u)); margin-top: calc(8 * var(--u)); }
}

/* Touch devices: no bespoke cursor, native one restored. */
@media (hover: none), (pointer: coarse) {
  /* iOS Safari force-zooms the page when a focused input is under 16px and
     never zooms back out. A 16px floor prevents it. At mobile scale the
     design size is ~15px, so this is visually indistinguishable. */
  .signup__input { font-size: max(16px, calc(15 * var(--u))); }
  .cursor { display: none; }
  .has-cursor, .has-cursor a, .has-cursor button,
  .has-cursor input, .has-cursor .cs-letter { cursor: auto; }
  .cs-letter { pointer-events: none; }
}
