/* Ceremony Sparkling Tea: holding page.
   Figma: desktop 4148:512 (1440 x 1024), mobile 4148:543 (390 x 892), file KpyfhnxxttsbKcxbBPKgC2.
   Figma text boxes are trimmed to cap height, so spacing below is cap-to-cap (text-box: trim-both). */

/* Static Saans, not the variable file (uneven spacing after "t" on hinted rasterisers). Licensed by Displaay:
   keep these files out of public repositories. */
@font-face {
  font-family: "Saans";
  src: url("fonts/Saans-Medium.woff") format("woff");
  font-weight: 500;
  font-display: swap;
}
@font-face {
  font-family: "Saans";
  src: url("fonts/Saans-Regular.woff") format("woff");
  font-weight: 400;
  font-display: swap;
}

/* ---- Layout model ----
   The design spaces the three words evenly and centres each line of copy in the gap between two words.
   --d is that gap (Figma: 199 desktop, 182 mobile). It is solved from the viewport height so the page fits
   one screen: viewport = top pad + words + 2 * gap + bottom pad + newsletter, with pads = --k * gap (Figma
   ratio). The gap is clamped; beyond --d-max the stack stays vertically centred, below --d-min the page
   scrolls (only on very short screens such as landscape phones).
   Height uses svh (toolbars shown): the page fits without scrolling, so mobile browser toolbars never
   collapse and nothing reflows as they would with dvh. 100vh is the fallback for older browsers. */
:root {
  --ink: #000;
  --paper: #fff;
  --grey: #606060;
  --font-sans: "Saans", "Helvetica Neue", Arial, sans-serif;
  --gutter: 20px;
  --vh: 100vh;

  /* Copy */
  --copy-size: 15px;
  --copy-cap: calc(var(--copy-size) * .721); /* Saans cap height: 721/1000 */

  /* Newsletter (Figma 4148:532): divider, 25, text, 25, form 50, 31, divider */
  --nl-pt: 25px;
  --nl-gap: 25px;
  --nl-pb: 31px;
  --nl-text-h: var(--copy-cap);
  --nl-form-h: 50px;
  --safe-bottom: env(safe-area-inset-bottom, 0px);
  --nl-h: calc(2px + var(--nudge) + var(--nl-pt) + var(--nl-text-h) + var(--nl-gap) + var(--nl-form-h) + var(--nl-pb) + var(--safe-bottom));

  /* Spacing solve */
  --k: .61;
  --d-min: 88px;
  --d-max: 240px;
  --pad-min: 24px;
  --nudge: 5px; /* Figma sits the stack slightly above centre (top 121, bottom 126) */

  /* Wordmark width (CEREMONY and SPARKLING; TEA is 0.3372 of it). Shrinks on short desktop screens so the
     minimum layout still fits. Word heights total 0.3609 * width. */
  --w: max(300px, min(650px, 100vw - 38px, (var(--vh) - var(--nl-h) - 2 * var(--d-min) - 2 * var(--pad-min)) / .3609));
  --words: calc(var(--w) * .3609);
  --d: clamp(var(--d-min), (var(--vh) - var(--words) - var(--nl-h)) / (2 + 2 * var(--k)), var(--d-max));

  /* Gradient (Figma "Gradient" fill). Sizes are fractions of --gw: the wordmark width, or more on larger windows
     so the glow grows with the browser. At the Figma frame (1440 x 1024) both give 650. Width leads; height caps
     it so very wide, short windows do not get a glow far taller than the screen. */
  --gw: max(var(--w), min(100vw * .45, var(--vh) * .79));
  --g-r1: .756;
  --g-r2: .39;
  --g-offset-x: .177;
  --g-offset-y: .183;
  --g-mid2: 47.1%;
}
@supports (height: 100svh) {
  :root { --vh: 100svh; }
}

@media (max-width: 749px) {
  :root {
    --copy-size: 12px;
    /* Figma 4148:545: divider, 35, text (3 lines), 25, input 50, 10, button 50, 31, divider */
    --nl-pt: 35px;
    --nl-gap: 25px;
    --nl-pb: 31px;
    --nl-text-h: calc(36px + var(--copy-cap));
    --nl-form-h: 110px;
    --k: .39;
    --d-min: 84px;
    --d-max: 220px;
    --pad-min: 20px;
    --nudge: 11px; /* top 71, bottom 82 */
    --w: min(650px, 100vw - 38px);
    --g-r1: .74;
    --g-mid2: 56.4%;
  }
}
/* Short phones (iPhone SE, small Androids with toolbars): tighten the newsletter before the words. */
@media (max-width: 749px) and (max-height: 720px) {
  :root {
    --nl-pt: 22px;
    --nl-gap: 18px;
    --nl-pb: 22px;
    --nudge: 0px;
  }
}

/* ---- Base ---- */
*, *::before, *::after { box-sizing: border-box; }
html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  overscroll-behavior: none;
  background: var(--paper);
}
body {
  margin: 0;
  color: var(--ink);
  background: var(--paper);
  font: 500 var(--copy-size)/18px var(--font-sans);
  letter-spacing: .1em;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  font-synthesis: none;
}

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

/* Copy and labels are trimmed to cap height, as in Figma. */
.trim { text-box: trim-both cap alphabetic; }

/* ---- Page ---- */
.page {
  display: grid;
  grid-template-rows: 1fr auto;
  min-height: var(--vh);
  overflow: clip; /* the gradient bleeds past the stack; never let it create scroll */
  isolation: isolate;
}

.hero {
  display: grid;
  place-items: center;
  padding: var(--pad-min) var(--gutter) calc(var(--pad-min) + var(--nudge));
}

.hero__stack {
  position: relative;
  display: grid;
  grid-template-rows: auto var(--d) auto var(--d) auto;
  justify-items: center;
  align-items: center;
  text-align: center;
  text-transform: uppercase;
}

.word {
  display: block;
  width: var(--w);
  height: auto;
  color: var(--ink);
}
.word--tea { width: calc(var(--w) * .3372); }

.hero__copy {
  margin: 0;
  max-width: min(var(--copy-w), 100vw - 2 * var(--gutter));
}
.hero__copy--intro { --copy-w: 368px; }
.hero__copy--story { --copy-w: 493px; }
@media (max-width: 749px) {
  .hero__copy--intro { --copy-w: 294px; }
  .hero__copy--story { --copy-w: 332px; }
}

/* ---- Gradient ----
   Two radial layers measured from the Figma fill: yellow primary centred on the stack, green secondary to the
   lower right. Each layer is its own circle moved with transform (compositor only, no repaint per frame).
   holding.js sets --gx/--gy (-0.5..0.5): primary follows the pointer, secondary moves against it, matching the
   featured-product gradient system. */
.glow {
  --gx: 0;
  --gy: 0;
  position: absolute;
  top: 50%;
  left: 50%;
  z-index: -1;
  pointer-events: none;
}
.glow__layer {
  position: absolute;
  border-radius: 50%;
  will-change: transform;
}
.glow__layer--primary {
  --r: calc(var(--gw) * var(--g-r1));
  inset: calc(-1 * var(--r)) auto auto calc(-1 * var(--r));
  width: calc(2 * var(--r));
  height: calc(2 * var(--r));
  background: radial-gradient(closest-side, #f2f058 16.75%, #f3f044 37.5%, #f9f274 51.92%, #fff5a4 66.35%, #fffad1 83.17%, #fff);
  transform: translate(calc(var(--gx) * var(--gw) * .51), calc(var(--gy) * var(--gw) * .4));
}
.glow__layer--secondary {
  --r: calc(var(--gw) * var(--g-r2));
  inset: calc(var(--gw) * var(--g-offset-y) - var(--r)) auto auto calc(var(--gw) * var(--g-offset-x) - var(--r));
  width: calc(2 * var(--r));
  height: calc(2 * var(--r));
  background: radial-gradient(closest-side, rgb(156 224 59 / .75), rgb(156 224 59 / .35) var(--g-mid2), rgb(156 224 59 / 0));
  transform: translate(calc(var(--gx) * var(--gw) * -.39), calc(var(--gy) * var(--gw) * -.33));
}

/* ---- Newsletter (Figma Global / Newsletter) ---- */
.signup {
  padding: var(--nl-pt) var(--gutter) var(--nl-pb);
  border-block: 1px solid var(--ink);
  margin-bottom: var(--safe-bottom);
  text-align: center;
}
.signup__intro {
  margin: 0 auto var(--nl-gap);
  font: inherit;
  text-transform: uppercase;
}
.signup__form {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 20px;
}
@media (max-width: 749px) {
  .signup__intro { max-width: 350px; }
  .signup__form { grid-template-columns: 1fr; gap: 10px; }
}

.signup__input,
.signup__button {
  height: 50px;
  margin: 0;
  border: 1px solid var(--ink);
  border-radius: 0;
  font-family: var(--font-sans);
  font-size: 14px;
  line-height: 17px;
}
.signup__input {
  width: 100%;
  min-width: 0;
  padding: 0 10px;
  background: transparent;
  color: var(--ink);
  font-weight: 400;
  letter-spacing: 0;
  appearance: none;
}
.signup__input:focus { outline: none; } /* the caret marks focus; no ring on the field */
.signup__input::placeholder { color: var(--grey); opacity: 1; }
.signup__input:autofill { box-shadow: inset 0 0 0 50px var(--paper); -webkit-text-fill-color: var(--ink); }
/* iOS zooms into inputs under 16px on focus; touch devices get 16px instead of the drawn 14px. */
@media (pointer: coarse) {
  .signup__input { font-size: 16px; }
}

.signup__button {
  display: grid;
  place-items: center;
  padding: 0 10px;
  background: var(--ink);
  color: var(--paper);
  font-weight: 500;
  letter-spacing: .1em;
  text-transform: uppercase;
  transition: background-color .2s ease-out;
}
/* Hover (desktop) and pressed (mobile) states: Figma 4148:501, 4148:508 */
@media (hover: hover) {
  .signup__button:hover { background: var(--grey); }
}
.signup__button:active { background: var(--grey); }
.signup__form[data-state="busy"] .signup__button,
.signup__form[data-state="success"] .signup__button { background: var(--ink); }

.signup__button:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 2px;
}

/* Button labels share one cell and cross-fade between states. */
.signup__label {
  grid-area: 1 / 1;
  opacity: 0;
  visibility: hidden;
  transform: translateY(.5em);
  transition: opacity .3s ease, transform .3s ease, visibility 0s linear .3s;
}
.signup__form[data-state="idle"] [data-label="idle"],
.signup__form[data-state="busy"] [data-label="busy"],
.signup__form[data-state="success"] [data-label="success"],
.signup__form[data-state="error"] [data-label="error"] {
  opacity: 1;
  visibility: visible;
  transform: none;
  transition: opacity .3s ease .1s, transform .3s ease .1s, visibility 0s;
}
.signup__dots span { animation: dot 1.2s infinite both; }
.signup__dots span:nth-child(2) { animation-delay: .2s; }
.signup__dots span:nth-child(3) { animation-delay: .4s; }
@keyframes dot {
  0%, 80%, 100% { opacity: 0; }
  40% { opacity: 1; }
}

.signup__trap { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

/* ---- Cursor (Figma 4153:605): Static = CST Device-04, Active = Device-03 over clickable elements ----
   Two layers, fine pointers only:
   1. Standard: CSS cursor images (with a white keyline so they show on black). Always set, so it is what you
      get without JS, on browsers that fail the checks in holding.js, or if the follow cursor is switched off.
   2. Follow: holding.js draws the cursor as an element (white, mix-blend-mode: difference: black on white,
      white on the black button) and adds .has-follow-cursor, which turns the native cursor off by setting the
      variables below to none. Text fields keep the native I-beam and the follow cursor hides over them. */
@media (pointer: fine) {
  :root {
    --cursor: url("cursor.svg") 16 16, auto;
    --cursor-click: url("cursor-click.svg") 16 16, pointer;
  }
  .has-follow-cursor {
    --cursor: none;
    --cursor-click: none;
  }
  html { cursor: var(--cursor); }
  a, button, label, [role="button"] { cursor: var(--cursor-click); }
  input:not([type="submit"]) { cursor: text; }
  .signup__form[data-state="busy"] .signup__button,
  .signup__form[data-state="success"] .signup__button { cursor: var(--cursor); }
}

.follow-cursor {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 2147483647;
  width: 32px;
  height: 32px;
  margin: -16px 0 0 -16px; /* hotspot at the centre, as the CSS cursor (16 16) */
  color: #fff;
  mix-blend-mode: difference;
  pointer-events: none;
  opacity: 0;
  will-change: transform;
}
.follow-cursor.is-visible { opacity: 1; }
.follow-cursor[data-state="text"] { opacity: 0; }
.follow-cursor svg {
  position: absolute;
  inset: 0;
  display: block;
}
.follow-cursor:not([data-state="active"]) .follow-cursor__active,
.follow-cursor[data-state="active"] .follow-cursor__static { visibility: hidden; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    transition-delay: 0s !important;
  }
}
