/* ============================================================================
 * pleshr — landing page
 *
 * "Black paper and one stamp." The page is a matte printed invitation, not a
 * lit screen: its material is paper grain and hairlines, not glass and glow.
 * Colour is spent the way a club spends a door stamp — once, small, and it
 * means something. The promise this page has to make is "someone runs this
 * properly and nobody will see your name", so the craft signal is restraint,
 * never heat.
 *
 * Three bans carry the whole look:
 *   1. no glassmorphism on anything that is not floating over scrolling content
 *   2. no coloured drop shadow anywhere, except the one primary button
 *   3. no gradient on any surface that is not a headline or that button
 *
 * Tokens are lifted 1:1 from the app's own src/styles/globals.css so the two
 * properties read as one company. The old stylesheet invented its own glass
 * palette and painted the brand gradient 13 times; that is what made it look
 * generated. Audit: `grep -c 'rgba(255,255,255' styles.css` must stay 0.
 *
 * LOAD-BEARING, DO NOT "TIDY":
 *   .hp-field              honeypot — must stay visually hidden
 *   .form-state            display:none/.visible — app.js toggles success+error
 *   .usp-card p            white-space:pre-line renders deliberate \n breaks
 *   .supporter-carousel    gap is READ by app.js (getComputedStyle .columnGap);
 *                          never add scroll-snap here, it fights the marquee
 *   .role-option           display:none — the label is the control
 *   .js .fade-in           IntersectionObserver adds .visible
 * ========================================================================= */

/* ── Typeface ──────────────────────────────────────────────────────────────
 * Self-hosted subsets. NEVER a font CDN: serving Google Fonts from the client
 * leaks visitor IPs to a third country (LG München I, Az. 3 O 17493/20), which
 * on a page like this is exactly the promise we are making. See fonts/OFL.txt.
 * Both are variable; opsz is driven by font-optical-sizing, never pinned. */
@font-face {
  font-family: 'Fraunces';
  src: url('/join/fonts/fraunces-var.woff2') format('woff2-variations');
  font-weight: 300 500;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'InterVar';
  src: url('/join/fonts/inter-var.woff2') format('woff2-variations');
  font-weight: 400 700;
  font-style: normal;
  font-display: swap;
}

:root {
  /* the app's ladder, verbatim */
  --ink:        #0A0A0F;   /* the page ground, and nothing else */
  --surface:    #14141A;   /* every card and panel */
  --surface-2:  #1C1C24;   /* inputs, chips, hover */
  --line:       #232330;   /* THE structural tool: hairlines, dividers, edges */
  --line-2:     #2E2E3A;   /* border of anything interactive */
  --line-3:     #3A3A48;   /* rail scrollbar thumb only */
  --text:       #f1f1f1;
  --text-2:     #b1b3b3;
  --text-3:     #868889;
  --stamp:      #D6456E;   /* brand-500. the accent, spent sparingly */
  --ring:       #E2617F;   /* focus rings only */
  --success:    #00a75d;
  --danger:     #d93025;
  --feather:    linear-gradient(135deg, #E05656 0%, #C93A72 50%, #9257D6 100%);

  --font-display: 'Fraunces', Georgia, 'Times New Roman', serif;
  --font:         'InterVar', Inter, system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;

  --r-band:  2rem;
  --r-card:  1.5rem;
  --r-input: 0.75rem;
  --r-check: 0.5rem;

  --transition: 0.22s ease;
  --max-w: 1100px;

  /* aliases kept so no legacy selector breaks mid-edit */
  --bg: var(--ink);
  --fg: var(--text);
  --muted: var(--text-2);
  --accent-1: #E05656;
  --accent-2: #C93A72;
  --accent-3: #9257D6;
  --grad: var(--feather);
  --radius: var(--r-card);
  --radius-sm: var(--r-input);
}

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

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  background: var(--ink);
  color: var(--text);
  font-family: var(--font);
  font-size: 0.9375rem;         /* 15px — one body size for the whole page */
  line-height: 1.65;
  font-feature-settings: 'cv02','cv03','cv04','cv11';
  font-optical-sizing: auto;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
}

/* Paper grain. This is the single highest-leverage texture on a black page:
   it stops large dark areas banding on cheap panels and reads as printed
   stock rather than screen. Fixed so it never scrolls with content. */
body::before {
  content: '';
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 0;
  opacity: 0.035;
  background-image: 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='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E");
}
main, header, footer { position: relative; z-index: 1; }

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

h1, h2, h3, h4 { margin: 0; text-wrap: balance; }
p { margin: 0; }

a { color: inherit; }

:focus-visible {
  outline: 2px solid var(--ring);
  outline-offset: 2px;
}

.container { width: 100%; max-width: var(--max-w); margin: 0 auto; padding: 0 20px; }
.text-center { text-align: center; }
.mb-0 { margin-bottom: 0 !important; }

section { padding: 48px 0; }
@media (min-width: 700px) { section { padding: 72px 0; } }

/* ── The one surface recipe ─────────────────────────────────────────────── */
.glass,
.usp-card,
.giveaway-card,
.form-card,
.legal-card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-card);
  box-shadow: none;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}

/* ── The stamp: the page's signature detail ─────────────────────────────── */
.eyebrow,
.giveaway-badge,
.footer-age {
  display: inline-block;
  font-size: 0.6875rem;
  font-weight: 700;
  line-height: 1;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-3);
  background: none;
  border: 0;
  padding: 0;
  border-radius: 0;
}
.eyebrow::before,
.giveaway-badge::before,
.footer-age::before {
  content: '';
  display: block;
  width: 24px;
  height: 1px;
  background: var(--stamp);
  margin-bottom: 10px;
}

/* ── Type scale ─────────────────────────────────────────────────────────── */
.hero-headline {
  font-family: var(--font-display);
  font-weight: 300;
  font-size: clamp(2.5rem, 8vw, 4.5rem);
  line-height: 1.05;
  letter-spacing: -0.02em;
  margin-bottom: 20px;
}
.section-title,
.legal-title {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(1.75rem, 4vw, 2.5rem);
  line-height: 1.15;
  letter-spacing: -0.015em;
  color: var(--text);
  margin-bottom: 10px;
}
.giveaway-card h2 {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(1.5rem, 3vw, 1.875rem);
  line-height: 1.2;
  letter-spacing: -0.01em;
  margin: 12px 0 12px;
}
.section-intro { color: var(--text-2); margin-bottom: 18px; max-width: 58ch; }
.section-intro.text-center { margin-left: auto; margin-right: auto; }

/* The gradient survives in exactly two places: the wordmark and the hero. */
.grad-text,
.hero-headline {
  background: var(--feather);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;
}
/* A section heading is not the brand mark. The gradient is allowed on exactly
   two things: the header wordmark and the hero headline. Everything else that
   carries .grad-text — the form section title, the footer logo — is solid. */
.section-title.grad-text,
.section-title .grad-text {
  background: none;
  color: var(--text);
  -webkit-text-fill-color: currentColor;
}
.footer-logo.grad-text {
  background: none;
  color: var(--text-3);
  -webkit-text-fill-color: currentColor;
}

/* ── Skip link (functional) ─────────────────────────────────────────────── */
.skip-link {
  position: absolute;
  top: -999px;
  left: 0;
  background: var(--stamp);
  color: #fff;
  padding: 8px 16px;
  font-size: 0.875rem;
  font-weight: 600;
  border-radius: 0 0 8px 0;
  z-index: 9999;
  text-decoration: none;
}
.skip-link:focus { top: 0; }

/* ── Header ─────────────────────────────────────────────────────────────── */
.site-header {
  position: sticky;
  top: 0;
  z-index: 100;
  height: 66px;
  display: flex;
  align-items: center;
  background: color-mix(in srgb, var(--ink) 82%, transparent);
  backdrop-filter: blur(16px) saturate(150%);
  -webkit-backdrop-filter: blur(16px) saturate(150%);
  border-bottom: 1px solid var(--line);
}
.site-header .container { display: flex; align-items: center; justify-content: space-between; }

.wordmark {
  font-family: var(--font);
  font-size: 1.375rem;
  font-weight: 700;
  letter-spacing: -0.02em;
  text-decoration: none;
  color: var(--text);
  line-height: 1;
}
.lang-toggle {
  display: inline-flex;
  padding: 3px;
  gap: 2px;
  background: var(--surface-2);
  border: 1px solid var(--line-2);
  border-radius: 999px;
}
.lang-btn {
  appearance: none;
  border: 0;
  background: none;
  cursor: pointer;
  font-family: inherit;
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  color: var(--text-3);
  padding: 5px 12px;
  border-radius: 999px;
  transition: color var(--transition);
}
.lang-btn:hover { color: var(--text-2); }
.lang-btn.active { color: var(--text); background: var(--ink); }

/* ── Hero ───────────────────────────────────────────────────────────────── */
/* ── Hero photograph ────────────────────────────────────────────────────
   The WHOLE frame, scaled and placed — not cropped to a band. That matters:
   `cover` on a landscape crop scales to the box HEIGHT on a wide screen and
   throws the outer figures away, which is exactly the thing the shot is for.
   The untouched portrait (0.8:1) is always taller than the hero box, so cover
   scales it to the WIDTH instead — both figures stay pinned to the edges at
   every viewport, and only the vertical window changes. */
.hero {
  position: relative;
  isolation: isolate;
  overflow: hidden;        /* clips the oversized parallax layer */
  min-height: 78vh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 56px 0 64px;
  text-align: center;
}
.hero::before,
.hero::after {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
}
.hero::before {
  z-index: -2;
  /* The 2000px file covers phones and every 1x desktop; only a high-DPI desktop
     pulls the 3000px one (see the query right below). image-set picks WebP and
     falls back to JPEG, and the plain url() above it catches older Safari,
     which supports neither image-set's type() nor WebP in every version. */
  background-image: url('/join/img/hero-2000-2a9fdb3c.jpg');
  background-image: image-set(url('/join/img/hero-2000-7ee7e692.webp') type('image/webp'),
                              url('/join/img/hero-2000-2a9fdb3c.jpg') type('image/jpeg'));
  background-repeat: no-repeat;
  background-size: cover;
  background-position: center 22%;   /* the window, not the hips */
}

/* Retina desktops only — the one case where 2000px is genuinely upscaled. */
@media (min-width: 900px) and (min-resolution: 2dppx) {
  .hero::before {
    background-image: url('/join/img/hero-3000-be376234.jpg');
    background-image: image-set(url('/join/img/hero-3000-55c97589.webp') type('image/webp'),
                                url('/join/img/hero-3000-be376234.jpg') type('image/jpeg'));
  }
}
/* ── Parallax ───────────────────────────────────────────────────────────
   Driven by scroll position in CSS, never JavaScript, and deliberately NOT
   `background-attachment: fixed` — that is the usual trick and it is broken on
   iOS Safari and janky on Android, which is most of this site's traffic.

   DESKTOP ONLY, and for a concrete reason. `cover` scales the frame to whichever
   axis needs it. On a wide screen that is the WIDTH, so the picture lands at
   1440x1800 inside a 702px-tall box — about 1100px of vertical slack sitting
   there unused, which the parallax can move through for free.
   On a phone it is the HEIGHT, so the picture lands at 498x623 in a 390x623 box:
   zero vertical slack. Making room there means scaling the picture up, i.e. the
   parallax and the zoom are the same knob. The framing wins, so phones get the
   picture exactly as composed and no motion.

   Animating background-position (not transform) is what keeps the layer the
   same size as the hero — no oversized box, so no zoom. */
@keyframes hero-parallax {
  from { background-position: center 14%; }
  to   { background-position: center 34%; }
}
@keyframes hero-parallax-mobile {
  from { background-position: center 15%; }
  to   { background-position: center 85%; }
}
/* The photograph resolves underneath everything else. Declared BEFORE the
   parallax block on purpose: same specificity, so source order decides, and
   when this sat after the parallax it replaced its animation-name list and the
   scroll effect silently stopped. Longhands throughout — the `animation`
   shorthand resets animation-timeline. */
.hero::before {
  animation-name: settle-in;
  animation-duration: 1100ms;
  animation-timing-function: ease-out;
  animation-fill-mode: both;
}

/* Two animations on one layer: the entrance runs on the document timeline,
   the parallax on the scroll timeline. Listed as longhands so neither clobbers
   the other's timeline — which the `animation` shorthand would. */
@supports (animation-timeline: scroll()) {
  @media (min-width: 900px) {
    .hero::before {
      animation-name: settle-in, hero-parallax;
      animation-duration: 1100ms, auto;
      animation-timing-function: ease-out, linear;
      animation-fill-mode: both, both;
      animation-timeline: auto, scroll(root block);
      animation-range: normal, 0 90vh;
    }
  }
  @media (max-width: 899px) {
    .hero::before {
      animation-name: settle-in, hero-parallax-mobile;
      animation-duration: 1100ms, auto;
      animation-timing-function: ease-out, linear;
      animation-fill-mode: both, both;
      animation-timeline: auto, scroll(root block);
      animation-range: normal, 0 80vh;
    }
  }
}

/* Hold the photograph back until it has actually decoded.
   `settle-in` runs on the document timeline, so it used to finish ~1.1s after
   DOMContentLoaded — long before a 450KB photo had arrived — and the picture
   then snapped in at full opacity with no fade left to play. Blanking
   animation-name until the image is ready means the entrance (and the
   parallax) begin the moment it lands, so the fade covers the arrival instead
   of running out before it.

   Higher specificity than the parallax rules above, so it wins while pending
   and stops applying the instant app.js adds .is-photo-ready. Gated on .js:
   with scripting off the class never arrives and the original behaviour
   stands, so the hero can never be left blank. prefers-reduced-motion already
   forces `opacity: 1 !important` on this layer further down, which overrides
   the hold entirely — that is intended: no fade, just the picture. */
.js .hero:not(.is-photo-ready)::before {
  animation-name: none;
  opacity: 0;
}

/* Enough wash to hold the type, not so much that the photograph disappears.
   The centre is where the headline sits; the edges, where the figures are,
   stay comparatively clear. */
.hero::after {
  z-index: -1;
  background:
    radial-gradient(105% 78% at 50% 50%, rgba(10,10,15,0.72) 0%, rgba(10,10,15,0.40) 46%, rgba(10,10,15,0.06) 78%),
    linear-gradient(to bottom, rgba(10,10,15,0.45) 0%, rgba(10,10,15,0.10) 26%, rgba(10,10,15,0.62) 84%, var(--ink) 100%);
}

/* Narrow screens are TALLER than the picture's 0.8 ratio, so `cover` would
   scale to the height and crop the sides off — losing both figures, which is
   the one thing this shot exists for. Fit the width instead and let the scrim
   carry the bottom into the page. */
/* MOBILE — and this is the case that matters most, the site is used on phones.
   The picture is 0.8:1; a phone viewport is about 0.46:1. Showing its full
   width (the only way both figures stay at the edges) therefore means it can
   only occupy a band at the top — that is geometry, not a choice. So make the
   band deliberate: fit the width, then dissolve the bottom edge into the page
   with a mask instead of letting it stop on a hard line, and start the type
   just inside the fade so the two halves read as one composition. */
@media (max-width: 899px) {
  .hero {
    min-height: 0;
    padding: 120px 0 36px;          /* lockup dropped into the sky, clear of the header */
    justify-content: flex-start;
  }
  .hero::before {
    /* cover, not width-fit: on a phone the box is taller than the frame's
       0.8 ratio, so cover scales it UP and trims a little off each side —
       which is the "zoom" that pushes the two figures further apart and out
       to the edges. Nothing is cropped from the file itself; this is purely
       placement, so the sky and the full bodies are all still in there. */
    /* auto 110% rather than cover: the picture is scaled to 110% of the hero's
       HEIGHT, so it always covers and always leaves exactly 10% of slack to
       move through. Keyed to the box height, not a fixed pixel width, so it
       holds on any phone regardless of how the German text wraps. That 10% is
       the agreed cost of having parallax on mobile at all — see the note on
       the desktop keyframes. */
    background-size: auto 110%;
    background-position: center 50%;
  }
  .hero::after {
    background:
      linear-gradient(to bottom, rgba(10,10,15,0.30) 0%, rgba(10,10,15,0.05) 24%, rgba(10,10,15,0.55) 52%, rgba(10,10,15,0.92) 74%, var(--ink) 88%);
  }
  /* a touch smaller so the lockup + photo together do not run away with the
     whole first screen */
  .hero-logo { width: 84px; height: 84px; border-radius: 21px; margin-bottom: 12px; }
  .hero-wordmark { font-size: 3.5rem; }      /* 56px */
  .hero-tagline  { font-size: 0.625rem; margin-top: -8px; }
  .hero-lockup { margin-bottom: 20px; }
  .hero-headline { margin-bottom: 14px; }
  .hero-subhead { margin-bottom: 22px; }
}

/* THE LOGO LOCKUP, set to the Canva artwork's own proportions.
   Read off the design elements: the wordmark is 149.333px and the tagline 40px
   (ratio 0.268), and the tagline's top sits 143.2px below the wordmark's box
   top — i.e. 0.96x the wordmark size, which tucks it up into the descender of
   the "p" rather than dropping it a whole line below. Both are centred on the
   same axis, which is what puts "Kinky" under the "l" of "pleshr".
   Title case and letterSpacing 0, exactly as in the artwork. */
.hero-lockup {
  display: flex;
  flex-direction: column;
  align-items: center;
  margin-bottom: 32px;
}
.hero-logo {
  width: 120px; height: 120px;
  margin: 0 0 18px;
  border-radius: 30px;
  animation: none;
  box-shadow: 0 18px 50px -18px rgb(0 0 0 / 0.75);
}
.hero-wordmark {
  color: var(--text);           /* white, as in the artwork */
  font-family: var(--font);
  font-size: 4.5rem;            /* 72px */
  font-weight: 700;
  line-height: 1.1;
  letter-spacing: -0.03em;
  text-shadow: 0 2px 18px rgb(0 0 0 / 0.55);
}
.hero-tagline {
  font-size: 0.75rem;           /* 12px — the size that lands "Kinky" on the "l" */
  font-weight: 600;
  line-height: 1;
  letter-spacing: 0;
  color: #ff4d8f;
  margin-top: -10px;            /* tucks under the baseline instead of a new line */
  text-shadow: 0 2px 10px rgb(0 0 0 / 0.6);
}
.hero-subhead {
  color: var(--text-2);
  font-size: 1.0625rem;
  line-height: 1.55;
  max-width: 46ch;
  margin: 0 auto 30px;
  text-shadow: 0 1px 12px rgb(0 0 0 / 0.5);
}

/* ── Buttons ────────────────────────────────────────────────────────────── */
.btn-primary,
.btn-submit,
.retry-btn,
.btn-ig {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  font-family: inherit;
  font-size: 0.875rem;
  font-weight: 700;
  line-height: 1;
  padding: 15px 28px;
  border-radius: 999px;
  border: 1px solid transparent;
  cursor: pointer;
  text-decoration: none;
  transition: filter var(--transition), background-color var(--transition), border-color var(--transition);
}
/* The one place a coloured shadow is allowed on the whole page. */
.btn-primary, .btn-submit {
  background: var(--stamp);
  color: #fff;
  box-shadow: 0 4px 20px -6px color-mix(in srgb, #C93A72 55%, transparent);
}
.btn-primary:hover, .btn-submit:hover { filter: brightness(1.08); }
.btn-primary:active, .btn-submit:active { filter: brightness(0.94); }
.btn-submit { width: 100%; padding: 16px 28px; }
.btn-submit:disabled { opacity: 0.5; cursor: not-allowed; box-shadow: none; }

.retry-btn, .btn-ig, .btn-ig-secondary {
  background: var(--surface-2);
  color: var(--text);
  border-color: var(--line-2);
  box-shadow: none;
}
.retry-btn:hover, .btn-ig:hover, .btn-ig-secondary:hover { background: var(--line); }
.btn-ig svg,
.btn-ig-secondary svg { width: 19px; height: 19px; flex: 0 0 auto; }
.btn-ig-secondary {
  display: inline-flex; align-items: center; gap: 8px;
  font-size: 0.8125rem; font-weight: 600;
  padding: 11px 18px; border-radius: 999px;
  border: 1px solid var(--line-2); text-decoration: none;
}

.btn-loading::after {
  content: '';
  display: inline-block;
  width: 16px; height: 16px;
  border: 2px solid color-mix(in srgb, #fff 40%, transparent);
  border-top-color: #fff;
  border-radius: 50%;
  animation: spin 0.75s linear infinite;
  margin-left: 10px;
  vertical-align: middle;
}

/* ── The rail: one utility, applied to two places ───────────────────────── */
.rail {
  overflow-x: auto;
  overscroll-behavior-x: contain;   /* stops iOS treating a swipe as "back" */
  scroll-snap-type: x proximity;    /* proximity, not mandatory — mandatory fights scrollIntoView */
  padding: 6px 20px 14px;
  margin: 0 -20px;
  scrollbar-width: thin;
  scrollbar-color: var(--line-3) transparent;
}
.rail::-webkit-scrollbar { height: 6px; }
.rail::-webkit-scrollbar-thumb { background: var(--line-3); border-radius: 999px; }
.rail::-webkit-scrollbar-track { background: transparent; }
.rail > * { scroll-snap-align: start; }
@media print { .rail { overflow: visible; display: grid; grid-auto-flow: row; } }

/* ── USP ────────────────────────────────────────────────────────────────── */
/* ── Feature stage ──────────────────────────────────────────────────────
   A static iPhone mockup on the left and a text box on the right that sits
   deliberately low — the asymmetry is the point. Neither moves. Swiping the
   box scrolls the cards; the screenshot inside the phone crossfades to match.

   The nine .usp-card articles keep their markup and their order exactly,
   because app.js localises them BY INDEX and reads the first h3 and first p
   inside each. Restructuring them would break the EN toggle silently. */
/* clips the entrance travel; see the motion block below */
.usp-section { overflow-x: clip; }
.usp-stage { display: grid; gap: 22px; }

/* The mockup is the real lightswind <Iphone16Pro>, pre-rendered into the page
   (see the comment in index.html). It draws its own frame, buttons, island and
   camera from its own SVG + Tailwind classes, which are appended at the bottom
   of this file. All that is left here is where it sits in the layout. */
.usp-phone {
  position: relative;
  width: 100%;
  max-width: 260px;
  margin: 0 auto;
}
.usp-phone svg { display: block; width: 100%; height: auto; }

/* THE SCREEN IS NOT INSIDE THE SVG. The component drew it in a <foreignObject>,
   and WebKit (Safari, and every browser on iOS) applies neither the SVG's
   viewBox scaling nor its clip-path to HTML in there once that HTML has
   positioned or fading children: the 397px-wide screen rendered at full size
   and spilled over the whole section on iPhones and iPads. So the SVG draws
   the frame only, and the screen is an ordinary box laid over the frame's
   screen rect (x18 y18, 397x846 of the 433x882 frame). Its content keeps the
   component's own px-sized markup at native size and is scaled down to fit:
   --usp-k = frame width / 433, kept exact by app.js; the per-layout defaults
   below are only what shows before it runs (or without script). */
.usp-phone { --usp-k: .6005; }                /* 260 / 433 */
.usp-phone svg { max-height: none; scale: none; } /* the overlay tracks the box: no 85vh cap, no hover zoom */
.usp-screen {
  position: absolute;
  left: 4.157%;   /*  18 / 433 */
  top: 2.041%;    /*  18 / 882 */
  width: 91.686%; /* 397 / 433 */
  height: 95.918%;/* 846 / 882 */
  border-radius: 12.594% / 5.910%; /* the frame's rx 50 */
  overflow: hidden;
  /* Safari lets fading (composited) children escape a rounded overflow clip
     unless the clipping box is a layer of its own. */
  -webkit-mask-image: -webkit-radial-gradient(white, black);
  isolation: isolate;
}
.usp-screen-native {
  width: 397px;
  height: 846px;
  transform-origin: 0 0;
  transform: scale(var(--usp-k));
}

/* our screenshots, inside the screen above */
.usp-shot {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity 420ms ease;
}
.usp-shot.is-active { opacity: 1; }

/* the box: this element IS the scroll viewport, so the frame stays put and
   only the cards inside travel */
.usp-grid {
  display: flex;
  /* positioned + z-index so the box paints ABOVE the mockup. .usp-phone is
     position:relative, and a positioned element paints over a non-positioned
     sibling regardless of DOM order — which had the phone clipping the card
     text where the two overlap. */
  position: relative;
  z-index: 1;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-band);
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
}
.usp-grid::-webkit-scrollbar { display: none; }
.usp-grid > .usp-card {
  flex: 0 0 100%;
  scroll-snap-align: center;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: flex-start;
  background: none;
  border: 0;
  border-radius: 0;
  padding: 26px 24px;
}
/* inside the stage the cards are slides, not a staggered grid — the observer
   would otherwise leave the off-screen ones at opacity 0 */
.usp-stage .usp-card,
.usp-stage .js .usp-card { opacity: 1 !important; transform: none !important; }

.usp-dots {
  display: flex;
  justify-content: center;
  gap: 7px;
  padding-top: 4px;
}
.usp-dot {
  width: 7px; height: 7px;
  padding: 0;
  border: 0;
  border-radius: 999px;
  background: var(--line-2);
  cursor: pointer;
  transition: background-color 200ms ease, width 200ms ease;
}
.usp-dot.is-active { background: var(--stamp); width: 20px; }

/* The card icon was only ever sized inside the max-width:899px block, so on
   desktop it computed to 0x0 and simply vanished. Base size lives here; the
   phone block below still overrides it (same specificity, later in the file). */
.usp-stage .usp-icon { width: 34px; height: 34px; }
.usp-stage .usp-icon svg { width: 18px; height: 18px; }

/* Phones get the same asymmetry rather than a stack: the mockup sits left and
   the box overlaps its lower right, so the two read as one layered composition.
   Both occupy the same grid cell and are pinned to opposite corners — that is
   what creates the overlap without any absolute positioning to go wrong. */
@media (max-width: 899px) {
  .usp-stage {
    grid-template-columns: 1fr;
    grid-template-rows: auto auto;
    gap: 0;
  }
  .usp-phone {
    grid-area: 1 / 1;
    justify-self: start;
    align-self: start;
    width: 46%;
    max-width: 180px;
    margin: 0;
    --usp-k: .4157; /* 180 / 433 */
  }
  .usp-grid {
    grid-area: 1 / 1;
    justify-self: end;
    align-self: start;
    width: 62%;
    /* Starts past halfway down the mockup and runs below it. A smaller box and
       a shallower overlap: enough for the two to read as layers, not so much
       that the box sits on the device. Aligning it to the BOTTOM instead made
       it taller than the phone and swallowed the screen entirely. */
    margin-top: 54%;
    box-shadow: 0 24px 50px -22px rgb(0 0 0 / 0.85);
  }
  .usp-grid > .usp-card { padding: 16px 15px; }
  .usp-grid > .usp-card p { font-size: 0.8125rem; line-height: 1.5; }
  .usp-grid > .usp-card h3 { font-size: 0.9375rem; margin: 11px 0 6px; }
  .usp-grid > .usp-card h3::after { margin-top: 9px; }
  .usp-stage .usp-icon { width: 32px; height: 32px; }
  .usp-stage .usp-icon svg { width: 16px; height: 16px; }
  .usp-dots {
    grid-area: 2 / 1;
    justify-content: flex-end;
    padding-top: 16px;
  }
}

/* Desktop keeps the phone composition instead of stretching the panel across
   the whole column. Capping the stage and centring it is what makes it read
   like the mobile layout: a 1fr panel next to a 300px mockup became a wide,
   shallow banner (712x190) with the text stranded on one line. */
@media (min-width: 900px) {
  .usp-stage {
    width: min(620px, 52%);
    margin-inline: auto;
    grid-template-columns: 1fr;
    grid-template-rows: auto auto;
    column-gap: 0;
    gap: 0;
  }
  .usp-phone {
    grid-area: 1 / 1;
    justify-self: start;
    align-self: start;
    width: 47%;
    max-width: 280px;
    margin: 0;
    --usp-k: .6467; /* 280 / 433 */
  }
  .usp-grid {
    grid-area: 1 / 1;
    justify-self: end;
    align-self: start;
    width: 63%;
    margin-top: 50%;
    min-height: 0;
    box-shadow: 0 30px 60px -26px rgb(0 0 0 / 0.85);
  }
  .usp-dots {
    grid-area: 2 / 1;
    justify-content: flex-end;
    padding-top: 18px;
  }
  .usp-grid > .usp-card { padding: 22px 24px; }
  .usp-grid > .usp-card p { font-size: 0.875rem; line-height: 1.55; }
  .usp-grid > .usp-card h3 { font-size: 1.0625rem; }
}

/* Entrance: mockup and panel glide in from opposite sides and settle. Driven by
   .is-in on the STAGE (app.js) rather than per-element observers, so the two
   always animate as one composition with a short stagger. Guarded by .js so the
   panel is never stuck invisible when scripting is off. */
.js .usp-stage .usp-phone,
.js .usp-stage .usp-grid,
.js .usp-stage .usp-dots {
  opacity: 0;
  transition: opacity 980ms cubic-bezier(.22,.8,.26,1),
              transform 1250ms cubic-bezier(.19,.78,.24,1);
  will-change: opacity, transform;
}
/* The mockup flies in from the left, the panel from the right. Both start
   outside the stage box on every width — the section clips horizontally
   (.usp-section, overflow-x: clip) so travelling past the container edge can
   never give the page a horizontal scrollbar the way it did before. */
.js .usp-stage .usp-phone { transform: translate3d(-72px, 12px, 0) scale(.965); }
.js .usp-stage .usp-grid  { transform: translate3d(76px, 14px, 0); transition-delay: 240ms; }
.js .usp-stage .usp-dots  { transform: translate3d(0, 12px, 0); transition-delay: 470ms; }
.js .usp-stage.is-in .usp-phone,
.js .usp-stage.is-in .usp-grid,
.js .usp-stage.is-in .usp-dots {
  opacity: 1;
  transform: none;
  will-change: auto;
}

/* ── Supporters ─────────────────────────────────────────────────────────── */
/* The marquee. gap is read by app.js via getComputedStyle().columnGap, and the
   hidden scrollbar + absence of scroll-snap are deliberate: snapping fights the
   continuous auto-scroll. Do not convert this to .rail. */
.supporter-carousel {
  display: flex;
  gap: 22px;
  overflow-x: auto;
  padding: 6px 20px 14px;
  margin: 0 -20px;
  scrollbar-width: none;
}
.supporter-carousel::-webkit-scrollbar { display: none; }

.supporter-card {
  position: relative;
  flex: 0 0 auto;
  width: min(340px, 84vw);
  aspect-ratio: 4 / 5;
  scroll-snap-align: center;
  overflow: hidden;
  border-radius: 22px;
  border: 1px solid rgba(255,255,255,0.12);
  box-shadow: 0 24px 60px -22px rgba(0,0,0,0.85), 0 2px 10px rgba(0,0,0,0.4);
}
.supporter-photo {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center 20%;
  display: block;
}
.supporter-scrim {
  position: absolute;
  inset: 0;
  background: linear-gradient(
    to top,
    rgba(10,10,15,0.94) 0%,
    rgba(10,10,15,0.72) 20%,
    rgba(10,10,15,0.18) 44%,
    transparent 62%
  );
  pointer-events: none;
}
.supporter-badge {
  position: absolute;
  top: 14px;
  left: 14px;
  z-index: 2;
  background: var(--feather);
  color: #fff;
  font-size: 0.66rem;
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  padding: 6px 12px;
  border-radius: 999px;
  box-shadow: 0 6px 18px rgba(201,58,114,0.5);
}
.supporter-overlay {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 2;
  padding: 0 22px 24px;
  text-align: center;
}
/* height + width:auto, never a square box: these are real logos with real
   aspect ratios and forcing them into 42x42 squashed every wide one. */
.supporter-logo {
  height: 46px;
  width: auto;
  max-width: 78%;
  margin: 0 auto 10px;
  display: block;
  filter: drop-shadow(0 3px 12px rgba(0,0,0,0.6));
}
.supporter-name {
  height: 46px;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 10px;
  font-size: 2.2rem;
  font-weight: 800;
  letter-spacing: -0.01em;
  color: #fff;
  line-height: 1;
  text-shadow: 0 2px 5px rgba(0,0,0,0.6), 0 6px 24px rgba(0,0,0,0.8);
}
.supporter-role {
  display: inline-block;
  font-size: 0.72rem;
  font-weight: 600;
  color: #fff;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  padding: 5px 14px;
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.16);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}
/* Small IG button — the only clickable element on the card. Top-right, round. */
.supporter-ig {
  position: absolute;
  top: 14px;
  right: 14px;
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  color: #fff;
  text-decoration: none;
  background: rgba(10,10,15,0.48);
  border: 1px solid rgba(255,255,255,0.24);
  box-shadow: 0 2px 10px rgba(0,0,0,0.35);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  transition: background-color var(--transition), border-color var(--transition);
}
.supporter-ig:hover, .supporter-ig:focus-visible {
  background: rgba(10,10,15,0.72);
  border-color: rgba(255,255,255,0.4);
}
.supporter-ig svg { width: 20px; height: 20px; flex: 0 0 auto; }

/* ── Comparison ─────────────────────────────────────────────────────────── */
.comparison-intro { color: var(--text-2); margin-bottom: 18px; }
.comparison-table {
  width: 100%;
  border-collapse: collapse;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-card);
  overflow: hidden;
}
.comparison-table th,
.comparison-table td {
  padding: 15px 16px;
  text-align: left;
  font-size: 0.9375rem;
  border-bottom: 1px solid var(--line);
}
.comparison-table thead th {
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-3);
  background: var(--surface-2);
}
.comparison-table tbody tr:last-child td { border-bottom: 0; }
.comparison-table tbody tr:hover td { background: var(--surface-2); }
.comparison-table td:first-child { color: var(--text); font-weight: 600; }
.comparison-table td:nth-child(2) { color: var(--text); }
.comparison-table td:nth-child(3) { color: var(--text-3); }
/* the one gradient spine, marking our column */
.col-pleshr-label { position: relative; }
.col-pleshr-label::before {
  content: '';
  position: absolute; left: 0; top: 0; bottom: 0;
  width: 2px;
  background: var(--feather);
}
.comparison-table td:nth-child(2) { box-shadow: inset 2px 0 0 -1px var(--line); }

@media (max-width: 699px) {
  /* The table itself becomes a block so its internal boxes stop fighting the
     flex tbody. NO negative margin here: a <tbody> is wrapped in anonymous
     table boxes, which swallow the bleed and left the first card hanging off
     the left edge with its text clipped. The rail stays inside the container
     gutter instead, which also lines the cards up with every other section. */
  .comparison-table { display: block; background: none; border: 0; border-radius: 0; }
  .comparison-table thead { display: none; }
  #comparison-tbody {
    display: flex;
    gap: 14px;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scroll-snap-type: x proximity;
    padding: 2px 0 14px;
    margin: 0;
    scrollbar-width: thin;
    scrollbar-color: var(--line-3) transparent;
  }
  #comparison-tbody::-webkit-scrollbar { height: 6px; }
  #comparison-tbody::-webkit-scrollbar-thumb { background: var(--line-3); border-radius: 999px; }
  #comparison-tbody tr {
    display: block;
    flex: 0 0 min(82%, 330px);
    scroll-snap-align: start;
    margin-bottom: 0;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--r-card);
    padding: 16px;
  }
  .comparison-table td { display: block; border-bottom: 0; padding: 0; }
  .comparison-table td:first-child {
    font-size: 0.6875rem; font-weight: 700; letter-spacing: 0.1em;
    text-transform: uppercase; color: var(--text-3); margin-bottom: 12px;
  }
  .comparison-table td:nth-child(2),
  .comparison-table td[data-other-label] { position: relative; padding-left: 0; box-shadow: none; }
  .comparison-table td:nth-child(2)::before,
  .comparison-table td[data-other-label]::before {
    content: attr(data-label);
    display: block;
    font-size: 0.625rem; font-weight: 700; letter-spacing: 0.09em;
    text-transform: uppercase; color: var(--text-3);
    margin-bottom: 3px;
  }
  .comparison-table td:nth-child(2) { margin-bottom: 12px; }
  .comparison-table td[data-other-label]::before { content: attr(data-other-label); }
}

/* ── Mission + giveaway ─────────────────────────────────────────────────── */
.giveaway-card { padding: 28px 24px; border-radius: var(--r-band); }
.giveaway-card p { color: var(--text-2); margin-bottom: 10px; }
.giveaway-card p:last-child { margin-bottom: 0; }
/* The CTA is a sibling of the body div with no margin of its own, so it sat
   flush against the last line of text. */
.giveaway-card .btn-primary { margin-top: 22px; }
.grad-divider { display: none; }   /* replaced by the section hairline */
.giveaway-section + .giveaway-section { border-top: 1px solid var(--line); }

@media (min-width: 900px) {
  .mission-section .container,
  .giveaway-section .container { max-width: var(--max-w); }
}

/* ── Form ───────────────────────────────────────────────────────────────── */
.form-section { padding-top: 48px; }
.form-wrapper { max-width: 560px; margin: 0 auto; }
.form-intro { color: var(--text-2); margin-bottom: 20px; }
.form-card { padding: 22px 16px; border-radius: var(--r-band); }
@media (min-width: 560px) { .form-card { padding: 28px 24px; } }

.field { margin-bottom: 13px; }
.field-label {
  display: block;
  font-size: 0.8125rem;
  font-weight: 600;
  letter-spacing: 0.01em;
  color: var(--text-2);
  margin-bottom: 6px;
}
.required-star { color: var(--stamp); }
.field-hint { font-size: 0.8125rem; line-height: 1.55; color: var(--text-3); margin-top: 5px; }

input[type="text"], input[type="email"], textarea, select {
  width: 100%;
  font-family: inherit;
  font-size: 0.9375rem;
  color: var(--text);
  background: var(--surface-2);
  border: 1px solid var(--line-2);
  border-radius: var(--r-input);
  padding: 12px 14px;
  transition: border-color var(--transition);
}
input::placeholder, textarea::placeholder { color: var(--text-3); }
input:focus, textarea:focus { outline: none; border-color: var(--ring); }
textarea { resize: vertical; min-height: 74px; }

#ref[readonly] { background: var(--surface); color: var(--text-2); cursor: default; }
.ref-locked-hint { font-size: 0.8125rem; color: var(--text-3); margin-top: 5px; }

.hp-field {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0,0,0,0);
  white-space: nowrap;
  border: 0;
  pointer-events: none;
}

.role-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.role-option { display: none; }
.role-label {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 3px;
  height: 100%;
  background: var(--surface-2);
  border: 1px solid var(--line-2);
  border-radius: var(--r-input);
  padding: 11px 12px;
  cursor: pointer;
  transition: border-color var(--transition), background-color var(--transition);
}
.role-label:hover { border-color: var(--line-3); }
.role-label-name { font-size: 0.875rem; font-weight: 600; color: var(--text); }
.role-label-desc { font-size: 0.76rem; line-height: 1.35; color: var(--text-3); }
.role-option:checked + .role-label {
  border-color: var(--stamp);
  background: color-mix(in srgb, var(--stamp) 10%, var(--surface-2));
  box-shadow: none;
}
.role-option:focus-visible + .role-label { outline: 2px solid var(--ring); outline-offset: 2px; }

.performer-type-field {
  overflow: hidden;
  max-height: 0;
  opacity: 0;
  transition: max-height 0.35s ease, opacity 0.3s ease, margin 0.3s ease;
}
.performer-type-field.visible { max-height: 120px; opacity: 1; margin-bottom: 13px; }

.consent-field {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  background: var(--surface-2);
  border: 1px solid var(--line-2);
  border-radius: var(--r-input);
  padding: 12px;
  margin-bottom: 10px;
}
.consent-checkbox {
  appearance: none;
  flex: 0 0 auto;
  width: 18px; height: 18px;
  margin: 1px 0 0;
  border: 1px solid var(--line-3);
  border-radius: var(--r-check);
  background: var(--ink);
  cursor: pointer;
  display: grid;
  place-content: center;
  transition: border-color var(--transition), background-color var(--transition);
}
.consent-checkbox::after {
  content: '';
  width: 9px; height: 5px;
  border-left: 2px solid #fff;
  border-bottom: 2px solid #fff;
  transform: rotate(-45deg) scale(0);
  transition: transform 0.14s ease;
}
.consent-checkbox:checked { background: var(--stamp); border-color: var(--stamp); }
.consent-checkbox:checked::after { transform: rotate(-45deg) scale(1); }
.consent-text { font-size: 0.8125rem; line-height: 1.45; color: var(--text-2); }
.consent-text a { color: var(--ring); }

/* ── Form states (functional: app.js toggles .visible) ──────────────────── */
.form-state { display: none; text-align: center; padding: 34px 20px; }
.form-state.visible { display: block; }
.form-state h3 { font-family: var(--font-display); font-weight: 400; font-size: 1.5rem; margin-bottom: 10px; }
.form-state p { color: var(--text-2); }
/* This is a <span> holding an emoji (🎉 / ⚠️), not an icon element — it is
   sized with font-size and must stay display:block to centre. Constraining it
   with width/height rendered it at text size. */
.state-icon { display: block; font-size: 3rem; line-height: 1; margin-bottom: 16px; }
.error-state h3 { color: var(--danger); }

.success-test {
  margin-top: 18px;
  text-align: left;
  background: color-mix(in srgb, var(--success) 12%, var(--surface-2));
  border: 1px solid color-mix(in srgb, var(--success) 35%, transparent);
  border-radius: var(--r-input);
  padding: 14px 16px;
}
.success-test-steps { margin: 8px 0 0; padding-left: 1.1rem; color: var(--text-2); font-size: 0.8125rem; }
.success-test-note { font-size: 0.8125rem; color: var(--text-3); margin-top: 8px; }

/* ── Floating CTA ───────────────────────────────────────────────────────── */
.float-cta {
  position: fixed;
  left: 50%;
  bottom: 18px;
  transform: translate(-50%, 140%);
  z-index: 90;
  opacity: 0;
  transition: transform 0.3s ease, opacity 0.3s ease;
  background: var(--stamp);
  color: #fff;
  font-family: inherit;
  font-size: 0.875rem;
  font-weight: 700;
  padding: 13px 24px;
  border: 0;
  border-radius: 999px;
  cursor: pointer;
  box-shadow: 0 6px 24px -8px rgb(0 0 0 / 0.8);
  text-decoration: none;
}
.float-cta.visible { transform: translate(-50%, 0); opacity: 1; }
@media (min-width: 1100px) and (min-height: 700px) { .float-cta { display: none; } }

/* ── Footer ─────────────────────────────────────────────────────────────── */
.site-footer { margin-top: 56px; border-top: 1px solid var(--line); padding: 34px 0 40px; }
.footer-logo { font-size: 1.125rem; font-weight: 700; color: var(--text-3); margin-bottom: 8px; }
.footer-tagline { color: var(--text-3); font-size: 0.8125rem; margin-bottom: 14px; }
.footer-links { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; font-size: 0.8125rem; }
.footer-links a { color: var(--text-2); text-decoration: none; }
.footer-links a:hover { color: var(--ring); }
.footer-sep { color: var(--line-2); }
.footer-age { margin-top: 14px; }
.operator-block { color: var(--text-3); font-size: 0.8125rem; margin-top: 14px; }

/* ── Legal pages ────────────────────────────────────────────────────────── */
.legal-page { max-width: 48rem; margin: 0 auto; padding: 0 20px; }
.legal-title { margin-bottom: 8px; }
.legal-subtitle { color: var(--text-3); font-size: 0.8125rem; margin-bottom: 28px; }
.legal-card {
  background: none;
  border: 0;
  border-top: 1px solid var(--line);
  border-radius: 0;
  padding: 0;
  margin-top: 2rem;
  padding-top: 1.5rem;
}
.legal-card h2 {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 1.25rem;
  letter-spacing: -0.01em;
  margin-bottom: 10px;
}
.legal-card h3 { font-size: 1rem; font-weight: 600; margin: 16px 0 6px; }
.legal-card p, .legal-card li { color: var(--text-2); font-size: 0.9375rem; line-height: 1.65; }
.legal-card p { margin-bottom: 10px; }
.legal-card ul { list-style: disc; padding-left: 1.25rem; margin: 10px 0; }
.legal-card a { color: var(--ring); }
.legal-back {
  display: inline-flex; align-items: center; gap: 6px;
  color: var(--text-2); text-decoration: none; font-size: 0.875rem; font-weight: 600;
}
.legal-back:hover { color: var(--ring); }
/* The top back-link's chevron carries no inline size (only the bottom one
   does), so without this it lays out at 0x0 and silently disappears. */
.legal-back svg { width: 16px; height: 16px; flex: 0 0 auto; }

/* ── Entrance ───────────────────────────────────────────────────────────
   A single settling movement on first paint: the header drops in, the
   photograph resolves, and the hero type arrives in reading order. Everything
   is short, small and eased out — the point is that the page feels composed,
   not that anything is seen to animate.

   The resting state of every element here is VISIBLE. The keyframes start at
   opacity 0 and `both` holds that only while the animation runs, so if
   animations never run — reduced motion, an old engine, a failed stylesheet —
   nothing is left hidden. That is the difference between a nice entrance and
   an invisible page. */
@keyframes settle-down {
  from { opacity: 0; transform: translate3d(0, -10px, 0); }
  to   { opacity: 1; transform: none; }
}
@keyframes settle-up {
  from { opacity: 0; transform: translate3d(0, 14px, 0); }
  to   { opacity: 1; transform: none; }
}
@keyframes settle-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}

.site-header {
  animation: settle-down 620ms cubic-bezier(0.22, 0.7, 0.2, 1) both;
}
/* the language toggle and wordmark arrive just after the bar itself */
.site-header .wordmark { animation: settle-in 700ms ease-out 120ms both; }
.site-header .lang-toggle { animation: settle-down 620ms cubic-bezier(0.22,0.7,0.2,1) 180ms both; }

/* Hero, in reading order. The numbers are deliberately close together: a long
   stagger reads as a slideshow, a short one reads as one movement. */
.hero-lockup   { animation: settle-up 760ms cubic-bezier(0.22, 0.7, 0.2, 1) 140ms both; }
.hero-headline { animation: settle-up 760ms cubic-bezier(0.22, 0.7, 0.2, 1) 250ms both; }
.hero-subhead  { animation: settle-up 760ms cubic-bezier(0.22, 0.7, 0.2, 1) 340ms both; }
.hero .btn-primary { animation: settle-up 760ms cubic-bezier(0.22, 0.7, 0.2, 1) 430ms both; }

/* ── Motion ─────────────────────────────────────────────────────────────── */
.js .fade-in { opacity: 0; transform: translateY(20px); transition: opacity 0.55s ease, transform 0.55s ease; }
.fade-in.visible { opacity: 1; transform: translateY(0); }

@keyframes spin { to { transform: rotate(360deg); } }
@keyframes fadeUp { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: none; } }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
  .js .fade-in { opacity: 1; transform: none; }
  .js .usp-stage .usp-phone,
  .js .usp-stage .usp-grid,
  .js .usp-stage .usp-dots { opacity: 1; transform: none; }
  .hero::before,
  .site-header,
  .site-header .wordmark,
  .site-header .lang-toggle,
  .hero-lockup,
  .hero-headline,
  .hero-subhead,
  .hero .btn-primary {
    animation: none !important;
    opacity: 1 !important;
    transform: none !important;
  }
}

/* ── Desktop: the hero and the form share row one ──────────────────────── */
/* .hero and .form-section are both direct children of #main-content, so
   explicit grid placement puts the signup form beside the headline with zero
   markup and zero JS change. The form's first field is then on screen at load
   instead of 3,900px down. */
/* The hero is full width again. It was sharing row one with the signup form,
   which put the form above the fold — but a photograph that has to reach both
   screen edges cannot be a grid column, and the picture is the stronger move.
   The form now follows directly underneath. */


#vorregistrieren { scroll-margin-top: 82px; }

/* ── lightswind Iphone16Pro utilities ───────────────────────────────────
   Generated from the PRE-RENDERED markup only (utilities layer, no preflight,
   source(none) so nothing else on the page is scanned). Preflight is excluded
   deliberately: Tailwind's base reset would stomp this stylesheet.
   Regenerate:
     node tools/phone-mock/render.mjs
     pnpm dlx @tailwindcss/cli -i tools/phone-mock/isolated/tw.css \
                               -o tools/phone-mock/isolated/phone.css --minify
   ==================================================================== */
/*! tailwindcss v4.2.4 | MIT License | https://tailwindcss.com */
@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-border-style:solid;--tw-gradient-position:initial;--tw-gradient-from:#0000;--tw-gradient-via:#0000;--tw-gradient-to:#0000;--tw-gradient-stops:initial;--tw-gradient-via-stops:initial;--tw-gradient-from-position:0%;--tw-gradient-via-position:50%;--tw-gradient-to-position:100%;--tw-font-weight:initial;--tw-tracking:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-backdrop-blur:initial;--tw-backdrop-brightness:initial;--tw-backdrop-contrast:initial;--tw-backdrop-grayscale:initial;--tw-backdrop-hue-rotate:initial;--tw-backdrop-invert:initial;--tw-backdrop-opacity:initial;--tw-backdrop-saturate:initial;--tw-backdrop-sepia:initial;--tw-duration:initial}}}@layer theme{:root,:host{--font-sans:ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--color-emerald-500:oklch(69.6% .17 162.48);--color-indigo-950:oklch(25.7% .09 281.288);--color-slate-900:oklch(20.8% .042 265.755);--color-slate-950:oklch(12.9% .042 264.695);--color-neutral-700:oklch(37.1% 0 0);--color-neutral-900:oklch(20.5% 0 0);--color-black:#000;--color-white:#fff;--spacing:.25rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--font-weight-medium:500;--font-weight-semibold:600;--tracking-tight:-.025em;--animate-pulse:pulse 2s cubic-bezier(.4, 0, .6, 1) infinite;--blur-sm:8px;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1)}}@layer utilities{.pointer-events-none{pointer-events:none}.absolute{position:absolute}.relative{position:relative}.inset-0{inset:calc(var(--spacing) * 0)}.top-0{top:calc(var(--spacing) * 0)}.top-2\.5{top:calc(var(--spacing) * 2.5)}.right-0{right:calc(var(--spacing) * 0)}.bottom-2{bottom:calc(var(--spacing) * 2)}.left-0{left:calc(var(--spacing) * 0)}.left-1\/2{left:50%}.z-10{z-index:10}.z-20{z-index:20}.z-30{z-index:30}.z-40{z-index:40}.mx-auto{margin-inline:auto}.block{display:block}.flex{display:flex}.h-1{height:calc(var(--spacing) * 1)}.h-1\.5{height:calc(var(--spacing) * 1.5)}.h-2\.5{height:calc(var(--spacing) * 2.5)}.h-3\.5{height:calc(var(--spacing) * 3.5)}.h-4{height:calc(var(--spacing) * 4)}.h-auto{height:auto}.h-full{height:100%}.max-h-\[85vh\]{max-height:85vh}.w-1\.5{width:calc(var(--spacing) * 1.5)}.w-2\.5{width:calc(var(--spacing) * 2.5)}.w-3\.5{width:calc(var(--spacing) * 3.5)}.w-4{width:calc(var(--spacing) * 4)}.w-32{width:calc(var(--spacing) * 32)}.w-full{width:100%}.max-w-\[100px\]{max-width:100px}.max-w-\[433px\]{max-width:433px}.shrink-0{flex-shrink:0}.-translate-x-1\/2{--tw-translate-x:calc(calc(1 / 2 * 100%) * -1);translate:var(--tw-translate-x) var(--tw-translate-y)}.animate-pulse{animation:var(--animate-pulse)}.cursor-pointer{cursor:pointer}.flex-col{flex-direction:column}.items-center{align-items:center}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.gap-1\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.rounded-full{border-radius:3.40282e38px}.border{border-style:var(--tw-border-style);border-width:1px}.border-neutral-700\/80{border-color:#404040cc}@supports (color:color-mix(in lab, red, red)){.border-neutral-700\/80{border-color:color-mix(in oklab, var(--color-neutral-700) 80%, transparent)}}.border-white\/10{border-color:#ffffff1a}@supports (color:color-mix(in lab, red, red)){.border-white\/10{border-color:color-mix(in oklab, var(--color-white) 10%, transparent)}}.bg-black{background-color:var(--color-black)}.bg-emerald-500{background-color:var(--color-emerald-500)}.bg-indigo-950\/80{background-color:#1e1a4dcc}@supports (color:color-mix(in lab, red, red)){.bg-indigo-950\/80{background-color:color-mix(in oklab, var(--color-indigo-950) 80%, transparent)}}.bg-neutral-900{background-color:var(--color-neutral-900)}.bg-white\/40{background-color:#fff6}@supports (color:color-mix(in lab, red, red)){.bg-white\/40{background-color:color-mix(in oklab, var(--color-white) 40%, transparent)}}.bg-gradient-to-tr{--tw-gradient-position:to top right in oklab;background-image:linear-gradient(var(--tw-gradient-stops))}.from-slate-950{--tw-gradient-from:var(--color-slate-950);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.from-transparent{--tw-gradient-from:transparent;--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.via-indigo-950{--tw-gradient-via:var(--color-indigo-950);--tw-gradient-via-stops:var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-via) var(--tw-gradient-via-position), var(--tw-gradient-to) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-via-stops)}.via-white\/\[0\.07\]{--tw-gradient-via:#ffffff12}@supports (color:color-mix(in lab, red, red)){.via-white\/\[0\.07\]{--tw-gradient-via:color-mix(in oklab, var(--color-white) 7.0%, transparent)}}.via-white\/\[0\.07\]{--tw-gradient-via-stops:var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-via) var(--tw-gradient-via-position), var(--tw-gradient-to) var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-via-stops)}.to-slate-900{--tw-gradient-to:var(--color-slate-900);--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.to-transparent{--tw-gradient-to:transparent;--tw-gradient-stops:var(--tw-gradient-via-stops,var(--tw-gradient-position), var(--tw-gradient-from) var(--tw-gradient-from-position), var(--tw-gradient-to) var(--tw-gradient-to-position))}.fill-\[\#68655f\]{fill:#68655f}.fill-\[\#68655f\]\/80{fill:oklab(50.7589% .000948012 .0100085/.8)}.fill-\[\#141416\]{fill:#141416}.fill-black{fill:var(--color-black)}.fill-current{fill:currentColor}.stroke-\[\#2a2a2d\]{stroke:#2a2a2d}.stroke-neutral-900\/80{stroke:#171717cc}@supports (color:color-mix(in lab, red, red)){.stroke-neutral-900\/80{stroke:color-mix(in oklab, var(--color-neutral-900) 80%, transparent)}}.stroke-\[1\.5\]{stroke-width:1.5px}.stroke-\[2\.5\]{stroke-width:2.5px}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-7{padding-inline:calc(var(--spacing) * 7)}.pt-3\.5{padding-top:calc(var(--spacing) * 3.5)}.pr-1{padding-right:calc(var(--spacing) * 1)}.pl-1{padding-left:calc(var(--spacing) * 1)}.font-sans{font-family:var(--font-sans)}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\[10px\]{font-size:10px}.text-\[13px\]{font-size:13px}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-tight{--tw-tracking:var(--tracking-tight);letter-spacing:var(--tracking-tight)}.text-white{color:var(--color-white)}.opacity-0{opacity:0}.opacity-90{opacity:.9}.shadow-lg{--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a), 0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.drop-shadow-\[0_25px_50px_rgba\(0\,0\,0\,0\.35\)\]{--tw-drop-shadow-size:drop-shadow(0 25px 50px var(--tw-drop-shadow-color,#00000059));--tw-drop-shadow:var(--tw-drop-shadow-size);filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.backdrop-blur-sm{--tw-backdrop-blur:blur(var(--blur-sm));-webkit-backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);backdrop-filter:var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,)}.transition-all{transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-opacity{transition-property:opacity;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-transform{transition-property:transform,translate,scale,rotate;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-200{--tw-duration:.2s;transition-duration:.2s}.duration-300{--tw-duration:.3s;transition-duration:.3s}.duration-500{--tw-duration:.5s;transition-duration:.5s}.select-none{-webkit-user-select:none;user-select:none}@media (hover:hover){.group-hover\:h-\[42px\]:is(:where(.group):hover *){height:42px}.group-hover\:w-\[190px\]:is(:where(.group):hover *){width:190px}.group-hover\:opacity-100:is(:where(.group):hover *){opacity:1}.hover\:scale-\[1\.015\]:hover{scale:1.015}}@media (prefers-color-scheme:dark){.dark\:fill-\[\#0a0a0c\]{fill:#0a0a0c}.dark\:fill-\[\#403e3a\]{fill:#403e3a}.dark\:fill-\[\#403e3a\]\/80{fill:oklab(36.4461% .000686467 .00724795/.8)}.dark\:stroke-\[\#202022\]{stroke:#202022}.dark\:drop-shadow-\[0_25px_50px_rgba\(0\,0\,0\,0\.7\)\]{--tw-drop-shadow-size:drop-shadow(0 25px 50px var(--tw-drop-shadow-color,#000000b3));--tw-drop-shadow:var(--tw-drop-shadow-size);filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}}}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-gradient-position{syntax:"*";inherits:false}@property --tw-gradient-from{syntax:"<color>";inherits:false;initial-value:#0000}@property --tw-gradient-via{syntax:"<color>";inherits:false;initial-value:#0000}@property --tw-gradient-to{syntax:"<color>";inherits:false;initial-value:#0000}@property --tw-gradient-stops{syntax:"*";inherits:false}@property --tw-gradient-via-stops{syntax:"*";inherits:false}@property --tw-gradient-from-position{syntax:"<length-percentage>";inherits:false;initial-value:0%}@property --tw-gradient-via-position{syntax:"<length-percentage>";inherits:false;initial-value:50%}@property --tw-gradient-to-position{syntax:"<length-percentage>";inherits:false;initial-value:100%}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@property --tw-backdrop-blur{syntax:"*";inherits:false}@property --tw-backdrop-brightness{syntax:"*";inherits:false}@property --tw-backdrop-contrast{syntax:"*";inherits:false}@property --tw-backdrop-grayscale{syntax:"*";inherits:false}@property --tw-backdrop-hue-rotate{syntax:"*";inherits:false}@property --tw-backdrop-invert{syntax:"*";inherits:false}@property --tw-backdrop-opacity{syntax:"*";inherits:false}@property --tw-backdrop-saturate{syntax:"*";inherits:false}@property --tw-backdrop-sepia{syntax:"*";inherits:false}@property --tw-duration{syntax:"*";inherits:false}@keyframes pulse{50%{opacity:.5}}
