/* ============================================================
   Hot Glitter! Chili Crisp — coming soon
   Colors + type per HotGlitter_BrandGuide_V1 D.pdf §0.2 / §0.5 / §0.6
   ============================================================ */

:root {
  /* core brand — §0.2 */
  --scorchin-red:  #CD171A;
  --crispy-gold:   #E1872D;
  --dark-plum:     #3B0118;
  /* web palette — §0.6 */
  --tenacious-tan: #E2C8AF;
  --djenta:        #DA027D;
  --chartreuse:    #B6BF51;
  /* polaroid frame stock */
  --frame:         #F5F1E8;

  /* Film grain, generated not downloaded: an SVG fractal-noise tile as a data
     URI. ~400 bytes, no licensing questions, tune via baseFrequency/opacity. */
  --grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='4' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)' opacity='0.42'/%3E%3C/svg%3E");

  --maxw: 640px;
  --ease: cubic-bezier(.4, 0, .2, 1);
}

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

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

body {
  margin: 0;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  background: var(--dark-plum);
  color: var(--tenacious-tan);
  font-family: Lato, system-ui, -apple-system, sans-serif;
  font-size: 17px;
  line-height: 1.6;
  overflow-x: hidden;
}

/* ---------- endless drifting topo background ----------
   The layer is pinned to the viewport and we animate background-position,
   NOT transform. The tile repeats infinitely inside the element, so shifting
   by exactly one tile (620px) loops perfectly and there is no element edge to
   slide into view — at any viewport size. Moving a finite element with
   transform runs out of overhang and exposes a hard edge. */
.topo {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background: url('../img/pattern-topo.svg') repeat 0 0;
  background-size: 620px 620px;
  opacity: .5;
  animation: drift 140s linear infinite;
}
@keyframes drift { to { background-position: 620px 620px; } }

/* ---------- layout ---------- */
.wrap {
  position: relative;
  z-index: 1;
  flex: 1;
  width: 100%;
  max-width: var(--maxw);
  margin: 0 auto;
  padding: clamp(2.5rem, 7vw, 5rem) 1.5rem 2rem;
  text-align: center;
}

/* viewBox is cropped to the artwork, so this margin is the real gap —
   no baked-in whitespace underneath.
   The nudge is optical, not geometric: the exclamation mark and "CHILI CRISP"
   load the right side, so a mathematically centred lockup reads as sitting
   right of centre. Percentage so it scales with the logo. */
.logo {
  width: min(78%, 420px);
  height: auto;
  margin: 0 auto .55rem;
  display: block;
  transform: translateX(-2.2%);
}

.eyebrow {
  margin: 0 0 1.25rem;
  font-family: 'Bebas Neue', Impact, sans-serif;
  font-size: clamp(1.9rem, 5.2vw, 2.3rem);
  letter-spacing: .18em;   /* wider than .launch on purpose — a single short
                              line can carry tracking that stacked lines can't */
  line-height: 1.05;
  text-transform: uppercase;
  color: var(--crispy-gold);
}

.headline {
  margin: 0 0 .75rem;
  font-family: 'Bebas Neue', Impact, sans-serif;
  font-weight: 400;
  font-size: clamp(2.9rem, 11vw, 4.6rem);
  line-height: .95;
  letter-spacing: .01em;
  color: #fff;
  text-wrap: balance;
}

/* Three stacked lines carry far more weight than one, so this sits at the same
   size as .eyebrow rather than the 2.8rem the single line was using — the block
   still reads louder overall, just without swamping the headline. */
.launch {
  margin: 0 0 1.75rem;
  font-family: 'Bebas Neue', Impact, sans-serif;
  font-size: clamp(1.9rem, 5.2vw, 2.3rem);
  letter-spacing: .14em;
  line-height: 1.02;
  text-transform: uppercase;
  color: var(--scorchin-red);
}
.launch span,
.launch strong { display: block; font-weight: 400; }
.launch strong { color: var(--crispy-gold); }

/* Lead line — Lato italic, matching the brand guide's H2 role (§0.6).
   The three-beat rhythm carries it; it doesn't need to shout. */
.lede {
  margin: 0 auto .85rem;
  max-width: 34ch;
  font-size: clamp(1.12rem, 3vw, 1.3rem);
  font-style: italic;
  line-height: 1.35;
  color: var(--tenacious-tan);
  text-wrap: balance;
}

.blurb {
  margin: 0 auto 1.15rem;
  max-width: 46ch;
  font-size: clamp(1rem, 2.6vw, 1.06rem);
  opacity: .88;
  text-wrap: pretty;
}

/* The closer — a countdown, so each beat gets its own line. The descending
   four/three/two/one only reads as a count when the lines stack. */
.brim {
  margin: 0 auto 2.25rem;
  max-width: none;
  font-family: 'Bebas Neue', Impact, sans-serif;
  font-size: clamp(1.15rem, 3.4vw, 1.45rem);
  letter-spacing: .07em;
  line-height: 1.24;
  color: var(--crispy-gold);
  text-wrap: balance;
}
.brim span { display: block; }

/* ---------- buttons (per §0.6) ---------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .55rem;
  padding: .85rem 1.9rem;
  border: 0;
  border-radius: 9999px;              /* full pill — §0.6 */
  font-family: 'Bebas Neue', Impact, sans-serif;
  font-size: 1.15rem;
  letter-spacing: .13em;
  text-transform: uppercase;
  text-decoration: none;
  color: #fff;
  cursor: pointer;
  transition: background-color .2s var(--ease), transform .2s var(--ease);
}
.btn:hover  { background-color: var(--djenta); }      /* hover  — §0.6 */
.btn:active { background-color: var(--crispy-gold); } /* click  — §0.6 */
.btn:focus-visible {
  outline: 3px solid var(--crispy-gold);
  outline-offset: 3px;
}

/* §0.6 specifies chartreuse with a WHITE label — that combination is 1.99:1,
   well under the 3:1 WCAG AA floor for large text, on the primary CTA.
   Keeping the specified pill colour and darkening the label gets 8.77:1. */
.btn-notify {
  background-color: var(--chartreuse);
  color: var(--dark-plum);
}
.btn-notify:hover { transform: translateY(-1px); }
/* hover/active are dark backgrounds, so the label goes back to white there */
.btn-notify:hover, .btn-notify:active { color: #fff; }

.btn-ig {
  background-color: var(--scorchin-red);
  margin-top: 0;
}
.btn-ig:hover { transform: translateY(-1px); }
.ig-icon { width: 1.15em; height: 1.15em; flex: none; }

/* ---------- signup ---------- */
.signup {
  display: flex;
  flex-wrap: wrap;
  gap: .65rem;
  justify-content: center;
  margin: 0 auto 1rem;
  max-width: 460px;
}

.signup input[type="email"] {
  flex: 1 1 240px;
  min-width: 0;
  padding: .85rem 1.25rem;
  border: 2px solid rgba(226, 200, 175, .35);
  border-radius: 9999px;
  background: rgba(0, 0, 0, .25);
  color: var(--tenacious-tan);
  font: inherit;
  font-size: 1rem;
  transition: border-color .2s var(--ease);
}
.signup input::placeholder { color: rgba(226, 200, 175, .5); }
.signup input:focus {
  outline: none;
  border-color: var(--crispy-gold);
}
.signup input:user-invalid { border-color: var(--scorchin-red); }

/* Takes no room until it has something to say — an always-reserved line was
   padding the gap below the form with invisible space. When it does appear it
   sits small and tight under the input, like a field note. */
.form-msg {
  flex: 1 0 100%;
  margin: 0;
  font-size: .8rem;
  line-height: 1.3;
  color: var(--crispy-gold);
}
.form-msg:not(:empty) { margin-top: .3rem; }
.form-msg.is-error { color: #ff8a8d; }

/* ---------- "in the wild" polaroid stack ---------- */
.wild {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1.15rem;
  padding: 1rem 1.5rem 3rem;
}
.wild[hidden] { display: none; }

.wild-eyebrow {
  margin: 0;
  font-family: 'Bebas Neue', Impact, sans-serif;
  font-size: clamp(1rem, 3vw, 1.25rem);
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--crispy-gold);
}

.stack {
  position: relative;
  width: min(74vw, 300px);
  aspect-ratio: 1 / 1.19;          /* polaroid proportion incl. the chin */
  touch-action: none;              /* drag is handled in JS */
  user-select: none;
}
.stack:focus-visible {
  outline: 3px solid var(--crispy-gold);
  outline-offset: 14px;
  border-radius: 6px;
}

.pola {
  position: absolute;
  inset: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  padding: 11px 11px 0;
  /* Aged film border: grain multiplied onto warm, unevenly yellowed stock.
     This is the FRAME's own background, painted behind .shot — so the texture
     shows only in the border and chin. The photo is never touched. */
  background-image:
    var(--grain),
    radial-gradient(125% 95% at 28% 4%, #FCF9F1 0%, #F4EEE1 42%, #EADFC9 78%, #E2D5BC 100%);
  background-size: 160px 160px, auto;
  background-blend-mode: multiply, normal;
  border-radius: 3px;
  box-shadow:
    0 12px 28px rgba(0,0,0,.45),
    0 2px 6px rgba(0,0,0,.3),
    inset 0 0 0 1px rgba(120,95,60,.14);   /* soft edge, not a hard border */
  transform-origin: 50% 60%;
  will-change: transform;
  cursor: grab;
}
.pola.dragging { cursor: grabbing; }
.pola:not(.dragging) {
  transition: transform .45s cubic-bezier(.22,.9,.3,1), opacity .3s linear;
}

/* The photograph itself — no filter, no colour wash, no tone change.
   The pixels are exactly as shot. */
.shot {
  position: relative;
  flex: 1;
  min-height: 0;
  overflow: hidden;
  background-color: #2a0512;
  /* background-image is set inline by js/main.js so the URL resolves against
     the document rather than this stylesheet */
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
}

/* The one thing that does reach the print: the shadow the frame's aperture
   casts onto the emulsion. It's lighting, not grading — no hue or saturation
   shift, just a soft darkening in the outermost few pixels so the photo reads
   as sitting *under* the border rather than pasted onto it.
   Delete this rule and the photo is edge-to-edge untouched. */
.shot::after {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  box-shadow:
    inset 0 1px 0 rgba(0,0,0,.30),         /* crisp top lip */
    inset 0 0 7px rgba(0,0,0,.22);         /* soft falloff all round */
}

.cap {
  flex: none;
  padding: .65rem .2rem .9rem;
  text-align: center;
  font-family: 'Permanent Marker', cursive;
  font-size: .9rem;
  line-height: 1.2;
  color: #4a2a30;
  transform: rotate(-1.2deg);
}

/* opacity floors below are set by contrast, not taste: tan on plum needs
   >= .70 to clear 4.5:1 for body-size text */
.wild-hint {
  margin: 0;
  font-size: .78rem;
  letter-spacing: .15em;
  text-transform: uppercase;
  opacity: .70;          /* was .55 — 3.95:1, failed AA */
}
.wild-hint .k {
  font-family: 'Bebas Neue', Impact, sans-serif;
  letter-spacing: .1em;
  color: var(--crispy-gold);
}
.wild-hint .dot { opacity: .5; margin: 0 .35rem; }

/* photo credit — present and legible, but it shouldn't compete with the stack */
.credit {
  margin: -.35rem 0 0;
  font-size: .72rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  opacity: .75;          /* was .42 — 2.80:1, failed AA */
}
.credit a {
  color: inherit;
  text-decoration: none;
  border-bottom: 1px solid currentColor;
  padding-bottom: 1px;
}
.credit a:hover { opacity: .8; }

/* ---------- footer ---------- */
.foot {
  position: relative;
  z-index: 1;
  padding: 1rem 1.5rem 2.5rem;
  text-align: center;
  font-size: .85rem;
  letter-spacing: .06em;
  opacity: .70;           /* was .6 — 4.49:1, failed AA by 0.01 */
}
.foot p { margin: 0; }

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

@media (prefers-reduced-motion: reduce) {
  .topo { animation: none; }
  .btn { transition: none; }
  .btn:hover { transform: none; }
  .pola:not(.dragging) { transition: none; }
}
