/* ═══════════════════════════════════════════════════════════════════════════
   Elsewhere — elsewheredating.com
   Brand tokens mirror frontend/theme.js (single source of truth for the app).
   Type: Satoshi (headings) + General Sans (body). Nothing else.
   ═══════════════════════════════════════════════════════════════════════════ */

:root {
  /* Surfaces */
  --bg:            #0a0511;
  --bg-raise:      rgba(255, 255, 255, 0.03);

  /* Brand */
  --purple:        #492c8c;   /* accentPurple */
  --purple-word:   #825fd2;   /* wordmarkAccent — "where" */
  --lavender:      #cbb8ff;
  --lavender-dim:  #a594d8;

  /* Text */
  --text:          #f4f1f9;
  --text-muted:    #9b93ab;
  --text-dim:      rgba(244, 241, 249, 0.42);

  /* Lines */
  --hairline:         rgba(255, 255, 255, 0.07);
  --hairline-strong:  rgba(255, 255, 255, 0.14);

  /* Type */
  --font-body: "General Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --font-head: "Satoshi", "General Sans", -apple-system, sans-serif;

  /* Fluid up to a generous ceiling: the layout breathes with the
     viewport but stops stretching on very large screens, where content
     scattered across the full width reads as empty. */
  --maxw: 1560px;
  --pad: clamp(22px, 5vw, 96px);
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);

  /* iOS SAFE-AREA STRIP COLOR — the ONE knob for the status-bar strip.
     iOS 26 derives the strip from the header's top-edge pixels; a thin
     opaque line of this color sits there (see .site-header::before) and
     feeds it. Tune to match how the scrolled bar RENDERS (its rgba over
     blurred content reads lighter than the raw color). Bar itself is
     rgba(10,5,17,0.88). */
  --safe-area-tint: #07020d;
}

* { box-sizing: border-box; margin: 0; padding: 0; }

/* color-scheme: dark makes the BROWSER's own canvas dark too — the
   overscroll/rubber-band area, the strip behind a collapsing mobile
   toolbar, scrollbars — so no white browser-coloured bar can peek
   through at the edges of the page. */
html {
  background: var(--bg);
  color-scheme: dark;
  scroll-behavior: smooth;
  overscroll-behavior: none;
}

body {
  font-family: var(--font-body);
  background: var(--bg);
  color: var(--text);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overscroll-behavior: none;
  /* Containing block for the document-spanning grain (body::after). */
  position: relative;
}

/* Ambient colour field — large soft blooms drifted at different speeds by
   JS while scrolling. Layering: photos sit at z 0, this layer at z 1, and
   every text/content wrapper at z 2 — so the light washes over the photo
   bands but never over copy. Screen blending makes it read as light
   rather than a purple film. */
.ambient {
  position: fixed;
  /* Starts just below the screen's top edge (iOS 26): a fixed element touching
     the edge participates in how Safari renders the status-bar strip, and this
     one is transparent — it must never be what gets sampled instead of the nav
     bar. The blooms are huge soft gradients; losing the top 12px is invisible. */
  top: 12px;
  right: 0;
  bottom: 0;
  left: 0;
  z-index: 1;
  pointer-events: none;
  overflow: hidden;
}

/* Software rasterizers (flagged by JS via the WebGL renderer string)
   darken low-alpha gradient falloffs — a clean dark page beats broken
   glow decor there, so strip it: blooms, glass blur, halos, glow
   shadows. The trail itself stays (only its tip loses the glow);
   content and photo veils stay. */
html.soft-gpu .ambient,
html.soft-gpu .showcase-phone::before {
  display: none;
}

html.soft-gpu .site-header,
html.soft-gpu .site-header.scrolled {
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}
html.soft-gpu .site-header.scrolled { background-color: rgba(10, 5, 17, 0.96); }

html.soft-gpu .cta { background: none; }

html.soft-gpu .cta-icon { box-shadow: none; }

html.soft-gpu .phone { box-shadow: none; }

/* The tip's halo lives on the ::after (opacity: var(--glow)); in
   software mode JS pins --glow at 0, and this removes it outright as
   belt-and-braces. The dot core and its size easing stay. */
html.soft-gpu .trail-dot::after { display: none; }

/* (The comet's gradient stroke renders fine in software mode — the
   artifact was only ever the blurred halo on the tip — so the trail
   keeps its full fade there.) */

/* Gaussian-ish multi-stop falloff (via color-mix) so the bloom dissolves
   with no visible edge; the plain two-stop version is the fallback for
   browsers without color-mix. */
.amb {
  position: absolute;
  left: var(--x, 0);
  top: var(--y, 0);
  /* Capped: an uncapped 100vw square on a large display is a huge GPU
     texture to blend and move every frame. */
  width: min(var(--w, 60vw), 860px);
  aspect-ratio: 1;
  /* Every stop keeps the SAME hue, only alpha falls — fading toward the
     `transparent` keyword (= transparent BLACK) darkens gradient edges
     on renderers that don't premultiply alpha when interpolating. */
  background: radial-gradient(
    closest-side,
    rgba(var(--h), var(--a)) 0%,
    rgba(var(--h), calc(var(--a) * 0.6)) 32%,
    rgba(var(--h), calc(var(--a) * 0.26)) 56%,
    rgba(var(--h), calc(var(--a) * 0.08)) 74%,
    rgba(var(--h), 0) 88%
  );
  /* screen: the blooms are LIGHT — they must only ever brighten what's
     beneath. Plain alpha compositing dims anything brighter than the
     bloom (photos, glows), leaving dark-edged patches. The perf cost is
     fine now that the layers are size-capped and the real jank source
     (the SVG mask) is gone. */
  mix-blend-mode: screen;
  will-change: transform;
}

/* Film grain — kills the flat-gradient look. Sits above everything, never
   intercepts input.
   ABSOLUTE, not fixed (iOS 26): a fixed full-screen overlay is the topmost
   fixed element at the screen's top edge, so Safari derives the status-bar
   strip from IT (≈ transparent → raw page shows through up there) instead of
   from the nav bar. Document-spanning absolute noise is visually identical —
   the tile is uniform, so it scrolling with the page is imperceptible. */
body::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 40;
  opacity: 0.04;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.82' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

a { color: inherit; text-decoration: none; }
img { max-width: 100%; display: block; }

::selection { background: rgba(130, 95, 210, 0.4); }

h1, h2, h3 {
  font-family: var(--font-head);
  font-weight: 700;
  line-height: 1.08;
  letter-spacing: -0.02em;
}

/* ── Header ─────────────────────────────────────────────────────────────── */

/* NOTE (iOS 26): Safari CLIPS position:fixed elements to below the status
   bar — nothing fixed can paint behind the Dynamic Island — and instead
   renders the scrolling DOCUMENT up there, tinted from the CSS background
   of the topmost fixed element ITSELF (children are ignored; that's why a
   bar whose paint lived on an inner div never registered). So we do what
   linear.app does: background + backdrop-filter directly ON the fixed
   header. At rest it's transparent (hero bleeds to the top, strip shows
   it raw — intentional). Once scrolled, the header turns near-opaque page
   bg; Safari picks that up and paints the strip to match, so strip and
   bar read as one solid-into-glass surface. No viewport-fit=cover — the
   layout stays out of the safe area and nothing needs pinning. */
.site-header {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 30;
  isolation: isolate;
  /* At rest the header must paint NOTHING — no backdrop-filter at all, not
     even blur(0px): iOS 26 treats any backdrop-filter on a fixed bar as an
     active glass layer and applies its own edge treatment to it, which
     showed as a weird short gradient before the bar faded in. */
  background-color: transparent;
  border-bottom: 1px solid transparent;
  transition: background-color 0.35s ease, border-color 0.35s ease;
}

.site-header.scrolled {
  border-bottom-color: var(--hairline);
  /* Near-opaque, not frost: the strip above can only be a solid tint, and
     a mostly-solid bar is what lets the two meet seamlessly (linear.app
     dark header ≈ 95-100% of its page bg for the same reason). The last
     ~12% keeps a hint of the page moving under the glass. */
  background-color: rgba(10, 5, 17, 0.88);
  -webkit-backdrop-filter: blur(12px) saturate(1.4);
  backdrop-filter: blur(12px) saturate(1.4);
}

/* Safe-area strip feeder: iOS derives the strip from the header's top-edge
   pixels, so this pins an opaque line of --safe-area-tint there, dissolving
   down into the bar over ~32px. Eased multi-stop alpha ramp (same trick as
   the hero veil) so no gradient "corner" is visible where it starts/ends.
   Change --safe-area-tint in :root to recolor the strip, nothing else.
   Mobile only (≤880px, same breakpoint as the rest of the phone layout):
   there's no status-bar/Dynamic-Island strip to feed on desktop Safari. */
@media (max-width: 880px) {
  .site-header::before {
    content: "";
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 32px;
    pointer-events: none;
    /* Two-stop fallback, then the eased ramp for color-mix browsers. */
    background: linear-gradient(180deg, var(--safe-area-tint) 0%, transparent 100%);
    background: linear-gradient(180deg,
      var(--safe-area-tint) 0%,
      color-mix(in srgb, var(--safe-area-tint) 86%, transparent) 25%,
      color-mix(in srgb, var(--safe-area-tint) 60%, transparent) 50%,
      color-mix(in srgb, var(--safe-area-tint) 30%, transparent) 75%,
      color-mix(in srgb, var(--safe-area-tint) 10%, transparent) 90%,
      color-mix(in srgb, var(--safe-area-tint) 0%, transparent) 100%);
    opacity: 0;
    transition: opacity 0.35s ease;
  }
  .site-header.scrolled::before { opacity: 1; }
}

/* No blur support (some Android browsers): translucency would let the
   page ghost through, so go fully opaque instead. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .site-header.scrolled { background-color: rgba(10, 5, 17, 0.97); }
}

.header-inner {
  max-width: var(--maxw);
  margin: 0 auto;
  position: relative;
  z-index: 1;
  padding: 14px var(--pad);
  display: flex;
  align-items: center;
  gap: 28px;
}

.logo {
  display: inline-flex;
  align-items: center;
  gap: 9px;
}

.logo b {
  font-family: var(--font-head);
  font-weight: 700;
  font-size: 1.14rem;
  letter-spacing: -0.02em;
}

/* Only "where" is accented — now the lighter lavender, not the old purple. */
.logo b span { color: var(--lavender); }

.nav-links {
  display: flex;
  gap: 26px;
  margin-left: auto;
  font-size: 0.92rem;
  color: var(--text-muted);
}

.nav-links a { transition: color 0.2s ease; }
.nav-links a:hover { color: var(--text); }

/* ── Buttons ────────────────────────────────────────────────────────────── */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-head);
  font-weight: 500;
  font-size: 0.98rem;
  color: #14092a;
  background: #fff;
  border: 0;
  border-radius: 999px;
  padding: 13px 26px;
  cursor: pointer;
  white-space: nowrap;
  transition: transform 0.25s var(--ease-out), background 0.25s ease, box-shadow 0.25s ease;
}

.btn:hover {
  background: var(--lavender);
  transform: translateY(-1px);
  box-shadow: 0 8px 28px rgba(130, 95, 210, 0.25);
}

.btn-sm { padding: 9px 18px; font-size: 0.88rem; }

.btn-line {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-head);
  font-weight: 500;
  font-size: 0.98rem;
  color: var(--text);
  border: 1px solid var(--hairline-strong);
  border-radius: 999px;
  padding: 12px 26px;
  transition: border-color 0.25s ease, background 0.25s ease;
}

.btn-line:hover {
  border-color: rgba(255, 255, 255, 0.32);
  background: var(--bg-raise);
}

/* ── Shared section chrome ──────────────────────────────────────────────── */

.section {
  position: relative;
  z-index: 2;
  max-width: var(--maxw);
  margin: 0 auto;
  padding: clamp(90px, 12vw, 150px) var(--pad);
}

.section-head {
  max-width: 760px;
  margin-bottom: clamp(48px, 7vw, 84px);
}

.section-head h2,
.cta h2 {
  font-size: clamp(2rem, 4.4vw, 3.3rem);
}

.kicker {
  display: block;
  font-family: var(--font-head);
  font-weight: 500;
  font-size: 0.8rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--lavender-dim);
  margin-bottom: 16px;
}

/* Scroll reveal — fails open (html.js gate) if JS never runs. */
html.js .reveal {
  opacity: 0;
  transform: translateY(26px);
  transition: opacity 0.9s var(--ease-out), transform 0.9s var(--ease-out);
  transition-delay: var(--d, 0s);
}

html.js .reveal.in {
  opacity: 1;
  transform: none;
}

/* ── Hero ───────────────────────────────────────────────────────────────── */

.hero {
  position: relative;
  min-height: 100svh;
  display: flex;
  align-items: center;
  overflow: hidden;
}

/* z-index 0 (not -1): body paints an opaque background over negative
   z-index descendants, which hides the photo entirely. */
.hero-media {
  position: absolute;
  inset: 0;
  z-index: 0;
}

/* PHOTO SLOT — assets/photos/hero.jpg · 2560×1440 (16:9), ≤ 500 KB.
   Keep the focal point in the right half: the headline sits on the left.
   Oversized + parallax-shifted by JS, so edges never show. The photo layer
   sits over a gradient fallback that only shows if the file is missing. */
.hero-bg {
  position: absolute;
  inset: -12% 0;
  background-color: #0d0716;
  background-image:
    url("assets/photos/hero.jpg"),
    radial-gradient(70% 60% at 72% 38%, rgba(97, 61, 178, 0.28), rgba(97, 61, 178, 0) 70%);
  background-size: cover;
  background-position: center;
  will-change: transform;
}

/* Legibility veil — a soft scrim on the left where the copy sits, and a
   fade into the page background at the bottom. Kept light so the photo
   actually reads as a photo. */
/* Eased multi-stop ramps: a two-stop gradient fades linearly and the
   eye catches the hard "corner" where it starts and ends; stepping the
   alpha along a smooth curve removes any visible band. */
.hero-veil {
  position: absolute;
  inset: 0;
  background:
    linear-gradient(90deg,
      rgba(10, 5, 17, 0.78) 0%,
      rgba(10, 5, 17, 0.62) 20%,
      rgba(10, 5, 17, 0.4) 40%,
      rgba(10, 5, 17, 0.2) 58%,
      rgba(10, 5, 17, 0.07) 76%,
      rgba(10, 5, 17, 0.015) 90%,
      rgba(10, 5, 17, 0) 100%),
    linear-gradient(180deg,
      rgba(10, 5, 17, 0.5) 0%,
      rgba(10, 5, 17, 0.3) 6%,
      rgba(10, 5, 17, 0.12) 12%,
      rgba(10, 5, 17, 0.03) 17%,
      rgba(10, 5, 17, 0) 22%,
      rgba(10, 5, 17, 0) 52%,
      rgba(10, 5, 17, 0.05) 60%,
      rgba(10, 5, 17, 0.16) 68%,
      rgba(10, 5, 17, 0.35) 76%,
      rgba(10, 5, 17, 0.6) 84%,
      rgba(10, 5, 17, 0.85) 92%,
      var(--bg) 100%);
}

.hero-content {
  position: relative;
  z-index: 2;
  width: 100%;
  max-width: var(--maxw);
  margin: 0 auto;
  padding: 140px var(--pad) 110px;
}

.hero-title {
  font-size: clamp(2.7rem, 6.2vw, 5.6rem);
  letter-spacing: -0.03em;
  line-height: 1.04;
  max-width: 13ch;
}

.hl { display: block; overflow: hidden; }

.hl-in {
  display: block;
  transform: translateY(112%);
  animation: hero-rise 1s var(--ease-out) forwards;
}

.hl:nth-child(2) .hl-in { animation-delay: 0.12s; }

@keyframes hero-rise {
  to { transform: translateY(0); }
}

.hero-sub {
  max-width: 540px;
  margin-top: 26px;
  font-size: clamp(1.08rem, 1.3vw, 1.22rem);
  color: var(--text-muted);
  opacity: 0;
  animation: hero-fade 0.9s var(--ease-out) 0.35s forwards;
}

.hero-cta {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  margin-top: 34px;
  opacity: 0;
  animation: hero-fade 0.9s var(--ease-out) 0.5s forwards;
}

.hero-fine {
  margin-top: 22px;
  font-size: 0.85rem;
  color: var(--text-dim);
  opacity: 0;
  animation: hero-fade 0.9s var(--ease-out) 0.62s forwards;
}

.hero-fine i { font-style: normal; margin: 0 7px; opacity: 0.6; }

@keyframes hero-fade {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: none; }
}

/* ── Showcase: pinned phone + scrolling features ────────────────────────── */

.showcase {
  position: relative;
  z-index: 2;
  max-width: var(--maxw);
  margin: 0 auto;
  padding: clamp(70px, 9vw, 120px) var(--pad) 0;
}

/* Copy column sits on the page's left margin (same line as the nav logo
   and every other section head); the scroll trail runs down the middle;
   the phone balances the remaining space. */
.showcase-grid {
  display: grid;
  grid-template-columns: minmax(0, 620px) auto minmax(0, 1fr);
  gap: clamp(10px, 1vw, 18px);
  align-items: start;
}

/* Scroll trail — nothing is visible ahead of the tip: the thread draws
   on behind a glowing dot as a comet tail (bright at the tip, dissolving
   further back), and a node surfaces on the line as it reaches each
   feature. Whole thing starts invisible; JS drives the opacity. */
/* The thread is drawn mostly to the LEFT of this column (negative svg
   coordinates over the feature block's empty right margin), so the
   column itself is just spacing before the phone. Never intercept
   clicks/selection over the text area it overlaps. */
.trail {
  position: relative;
  align-self: stretch;
  width: clamp(54px, 5vw, 90px);
  opacity: 0;
  pointer-events: none;
}

/* No CSS filters here: the strokes are mutated every scroll frame
   (dashoffset + gradient), and a filter would re-render on each one —
   the single biggest source of scroll lag. The dot's glow is a
   box-shadow on its own composited layer instead. */
.trail svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  overflow: visible;
}

/* Both the thread and its branches are stroked with the sliding comet
   gradient, so they share one smooth fade. */
.trail path {
  fill: none;
  stroke-linecap: round;
  stroke: url(#trailGrad);
  stroke-width: 1.5;
}

/* The glowing tip. */
.trail-dot {
  position: absolute;
  left: 0;
  top: 0;
  width: 8px;
  height: 8px;
  margin: -4px 0 0 -4px;
  border-radius: 50%;
  background: #fff;
  will-change: transform;
}

/* Glow on a pseudo so it can fade independently of the core: parked on
   the heading's period the dot is a plain full stop, and the glow comes
   up as it starts moving. JS drives --glow each frame; the default keeps
   the glow on if JS never writes it. */
.trail-dot::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  opacity: var(--glow, 1);
  box-shadow:
    0 0 12px 2px rgba(203, 184, 255, 0.8),
    0 0 32px 8px rgba(130, 95, 210, 0.35);
}

/* Larger than the shared section-head size so the sentence's final period
   reaches out toward the middle of the grid — the scroll trail's path is
   anchored to that period and draws out of it. */
.showcase .section-head h2 {
  font-size: clamp(2.3rem, 5.2vw, 3.9rem);
}

.showcase-copy {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  padding-bottom: clamp(40px, 6vh, 80px);
}

/* Emphasis (opacity + scale) is written inline every frame by JS as a
   continuous function of scroll position — no transition here, or the
   per-frame values would lag. The html.js base and .active rules only
   cover the moments JS isn't driving styles (initial paint, reduced
   motion, script failure). */
.feature {
  min-height: clamp(230px, 30vh, 340px);
  display: flex;
  flex-direction: column;
  justify-content: center;
  width: 100%;
  max-width: 560px;
  transform-origin: left center;
}

html.js .feature {
  opacity: 0.45;
  transform: scale(0.96);
  /* Promoted: opacity/scale are written every scroll frame — without a
     layer each write repaints the text. */
  will-change: opacity, transform;
}

html.js .feature.active {
  opacity: 1;
  transform: scale(1);
}

.feature-num {
  font-family: var(--font-head);
  font-weight: 500;
  font-size: 0.8rem;
  letter-spacing: 0.16em;
  color: var(--lavender-dim);
  margin-bottom: 14px;
}

.feature h3 {
  font-size: clamp(1.5rem, 2.4vw, 2rem);
  margin-bottom: 12px;
}

.feature p {
  color: var(--text-muted);
  font-size: 1.06rem;
  max-width: 46ch;
}

/* Full-viewport sticky wrap: the phone stays vertically centred on screen
   for the whole section, whatever its rendered height. */
.showcase-phone {
  position: sticky;
  top: 0;
  height: 100svh;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* Soft halo behind the phone so it sits in a pool of light rather than
   on flat black. */
.showcase-phone::before {
  content: "";
  position: absolute;
  width: min(680px, 90%);
  aspect-ratio: 1;
  border-radius: 50%;
  background: radial-gradient(closest-side, rgba(97, 61, 178, 0.16), rgba(97, 61, 178, 0) 72%);
  pointer-events: none;
}

/* Phone frame. The screen is ~9:19.5 — any modern phone screenshot fits.
   Width also capped by viewport height so the frame always fits on screen. */
.phone {
  position: relative;
  width: min(360px, 78vw, calc((100svh - 150px) * 9 / 19.5));
  border-radius: 46px;
  padding: 11px;
  background: #000;
  border: 1px solid var(--hairline-strong);
  box-shadow:
    0 30px 80px rgba(0, 0, 0, 0.55),
    0 0 120px rgba(97, 61, 178, 0.18);
}

.phone::before {
  /* Dynamic-island nub */
  content: "";
  position: absolute;
  top: 22px;
  left: 50%;
  transform: translateX(-50%);
  width: 86px;
  height: 22px;
  border-radius: 999px;
  background: #08040e;
  z-index: 2;
}

.phone-screen {
  position: relative;
  aspect-ratio: 9 / 19.5;
  border-radius: 36px;
  overflow: hidden;
  background: rgb(15, 6, 25); /* app bgPrimary */
}

/* PHOTO SLOT — /assets/photos/screenshot.png · raw app screenshot at native
   resolution (e.g. 1179×2556 iPhone or 1080×2340 Android). No frame, no
   rounding — the CSS crops and rounds it. */
.phone-screen img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Skeleton UI under the screenshot — visible until one exists. */
.screen-placeholder {
  position: absolute;
  inset: 0;
  padding: 56px 20px 24px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.sp-photo {
  height: 46%;
  border-radius: 18px;
  background:
    radial-gradient(80% 80% at 30% 20%, rgba(130, 95, 210, 0.35), rgba(130, 95, 210, 0) 70%),
    linear-gradient(150deg, #2a1d44, #160e26);
  margin-bottom: 6px;
}

.sp-bar {
  height: 11px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.09);
}

.sp-bar.w40 { width: 40%; }
.sp-bar.w60 { width: 60%; }
.sp-bar.w70 { width: 70%; }
.sp-bar.w80 { width: 80%; }

.sp-chip-row { display: flex; gap: 8px; margin: 6px 0; }

.sp-chip-row i {
  width: 64px;
  height: 24px;
  border-radius: 999px;
  background: rgba(73, 44, 140, 0.5);
}

/* ── Interlude: full-bleed photo + scrubbed line ────────────────────────── */

.interlude {
  position: relative;
  min-height: 96vh;
  margin-top: clamp(60px, 9vw, 120px);
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}

.interlude-media {
  position: absolute;
  inset: 0;
  z-index: 0;
}

/* PHOTO SLOT — assets/photos/interlude.jpg · 2560×1440 (16:9), ≤ 500 KB.
   The line of copy sits dead centre, so favour calm imagery there. */
.interlude-bg {
  position: absolute;
  inset: -14% 0;
  background-color: #0c0714;
  background-image:
    url("assets/photos/interlude.jpg"),
    radial-gradient(60% 55% at 50% 45%, rgba(97, 61, 178, 0.22), rgba(97, 61, 178, 0) 72%);
  background-size: cover;
  background-position: center;
  will-change: transform;
}

/* Light scrim + eased full-height fades: the alpha follows a smooth
   curve from edge to centre with no flat segments or corner points, so
   the photo melts in and out with no perceptible band. Text legibility
   comes from its shadow rather than a heavy overlay. */
.interlude-veil {
  position: absolute;
  inset: 0;
  background:
    linear-gradient(180deg,
      var(--bg) 0%,
      rgba(10, 5, 17, 0.93) 8%,
      rgba(10, 5, 17, 0.78) 16%,
      rgba(10, 5, 17, 0.57) 24%,
      rgba(10, 5, 17, 0.35) 32%,
      rgba(10, 5, 17, 0.16) 40%,
      rgba(10, 5, 17, 0.04) 47%,
      rgba(10, 5, 17, 0) 50%,
      rgba(10, 5, 17, 0.04) 53%,
      rgba(10, 5, 17, 0.16) 60%,
      rgba(10, 5, 17, 0.35) 68%,
      rgba(10, 5, 17, 0.57) 76%,
      rgba(10, 5, 17, 0.78) 84%,
      rgba(10, 5, 17, 0.93) 92%,
      var(--bg) 100%),
    rgba(10, 5, 17, 0.34);
}

.scrub {
  position: relative;
  z-index: 2;
  max-width: 18ch;
  padding: 0 var(--pad);
  font-family: var(--font-head);
  font-weight: 700;
  font-size: clamp(2rem, 4.8vw, 3.8rem);
  line-height: 1.16;
  letter-spacing: -0.02em;
  text-align: center;
  text-shadow: 0 2px 34px rgba(10, 5, 17, 0.85), 0 1px 8px rgba(10, 5, 17, 0.6);
}

.scrub span {
  opacity: 0.16;
  transition: opacity 0.45s ease;
}

.scrub span.on { opacity: 1; }

/* ── Founder's note ─────────────────────────────────────────────────────── */

.note {
  position: relative;
  z-index: 2;
  max-width: 1080px;
  margin: 0 auto;
  padding: clamp(90px, 13vw, 160px) var(--pad);
  text-align: center;
}

.note p {
  font-family: var(--font-head);
  font-weight: 500;
  font-size: clamp(1.4rem, 3vw, 2.3rem);
  line-height: 1.36;
  letter-spacing: -0.015em;
  color: var(--text);
}

.note em {
  font-style: normal;
  color: var(--lavender);
}

.note-sign {
  margin-top: 30px;
  font-family: var(--font-head);
  font-weight: 500;
  font-size: 0.9rem;
  letter-spacing: 0.02em;
  color: var(--text-muted);
}

/* ── CTA ────────────────────────────────────────────────────────────────── */

.cta {
  position: relative;
  z-index: 2;
  max-width: 640px;
  margin: 0 auto;
  padding: clamp(80px, 11vw, 140px) var(--pad) clamp(100px, 13vw, 160px);
  text-align: center;
  background: radial-gradient(55% 55% at 50% 34%, rgba(97, 61, 178, 0.13), rgba(97, 61, 178, 0) 72%);
}

.cta-icon {
  margin: 0 auto 26px;
  border-radius: 20px;
  box-shadow: 0 14px 44px rgba(97, 61, 178, 0.35);
}

.cta p {
  margin-top: 16px;
  color: var(--text-muted);
}

/* Pre-launch state — a beta tag and a launch-date card. */
.cta-tag {
  display: inline-block;
  font-family: var(--font-head);
  font-weight: 500;
  font-size: 0.76rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--lavender);
  border: 1px solid var(--hairline-strong);
  border-radius: 999px;
  padding: 7px 15px;
  margin-bottom: 22px;
}

.launch {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  margin-top: 32px;
  padding: 24px clamp(36px, 8vw, 60px);
  border: 1px solid var(--hairline-strong);
  border-radius: 22px;
  background:
    radial-gradient(120% 120% at 50% 0%, rgba(130, 95, 210, 0.14), rgba(130, 95, 210, 0) 70%),
    var(--bg-raise);
}

.launch-label {
  font-family: var(--font-head);
  font-weight: 500;
  font-size: 0.76rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.launch-date {
  font-family: var(--font-head);
  font-weight: 700;
  font-size: clamp(2.1rem, 5.5vw, 3.1rem);
  letter-spacing: -0.02em;
  line-height: 1.05;
  color: var(--text);
}

.launch-plat {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin-top: 8px;
  font-family: var(--font-head);
  font-weight: 500;
  font-size: 0.86rem;
  color: var(--text-muted);
}

.launch-plat svg {
  width: 15px;
  height: 15px;
  opacity: 0.8;
}

.cta-fine {
  margin-top: 16px;
  font-size: 0.85rem;
  color: var(--text-dim);
}

/* ── Footer ─────────────────────────────────────────────────────────────── */

.site-footer {
  position: relative;
  z-index: 2;
  border-top: 1px solid var(--hairline);
}

.footer-inner {
  max-width: var(--maxw);
  margin: 0 auto;
  padding: clamp(48px, 7vw, 72px) var(--pad) 36px;
}

.footer-top {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 40px;
}

.footer-brand p {
  margin-top: 12px;
  font-size: 0.9rem;
  color: var(--text-muted);
}

.footer-cols {
  display: flex;
  flex-wrap: wrap;
  gap: clamp(32px, 5vw, 72px);
}

.footer-cols h4 {
  font-family: var(--font-head);
  font-weight: 500;
  font-size: 0.78rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-dim);
  margin-bottom: 14px;
}

.footer-cols a {
  display: block;
  font-size: 0.92rem;
  color: var(--text-muted);
  margin-bottom: 9px;
  transition: color 0.2s ease;
}

.footer-cols a:hover { color: var(--text); }

.footer-bottom {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  margin-top: 48px;
  padding-top: 22px;
  border-top: 1px solid var(--hairline);
}

.copy {
  font-size: 0.84rem;
  color: var(--text-dim);
}

/* ── Legal pages (terms.html / privacy.html / support.html) ─────────────── */

/* Short pages (support) would otherwise end mid-screen, leaving the footer
   floating with raw background below it — stretch the page to the viewport
   so the footer always sits at the bottom. */
.page-legal {
  min-height: 100vh;
  min-height: 100svh;
  display: flex;
  flex-direction: column;
}

.page-legal .legal { flex: 1 0 auto; }

.legal {
  /* Above the ambient blooms (z 1), same as the landing content wrappers —
     the light must never wash over copy. */
  position: relative;
  z-index: 2;
  max-width: 720px;
  margin: 0 auto;
  padding: 140px var(--pad) 90px;
}

.legal h1 {
  font-size: clamp(1.9rem, 4vw, 2.6rem);
  margin-bottom: 8px;
}

.legal .updated {
  color: var(--text-dim);
  font-size: 0.9rem;
  margin-bottom: 36px;
}

.legal h2 {
  font-size: 1.2rem;
  margin: 34px 0 10px;
}

.legal p, .legal ul {
  color: var(--text-muted);
  font-size: 0.98rem;
}

.legal ul { padding-left: 22px; }
.legal li { margin-bottom: 8px; }

.legal a { color: var(--lavender); }

/* ── Support page ───────────────────────────────────────────────────────── */

.support-page {
  max-width: 880px;
  text-align: center;
}

.support-page .updated { margin-bottom: 44px; }

/* The cards are <a> blocks — keep them body-coloured, not link-lavender. */
.support-card,
.support-topics a {
  color: var(--text);
  border: 1px solid var(--hairline);
  transition: border-color 0.25s ease, transform 0.25s var(--ease-out), box-shadow 0.25s ease;
}

.support-card:hover,
.support-topics a:hover {
  border-color: var(--hairline-strong);
  transform: translateY(-2px);
}

/* Big, obvious way to email us. */
.support-card {
  display: flex;
  align-items: center;
  gap: 18px;
  margin-bottom: 14px;
  padding: 22px 26px;
  text-align: left;
  border-radius: 20px;
  background:
    radial-gradient(120% 150% at 50% 0%, rgba(97, 61, 178, 0.16), rgba(97, 61, 178, 0) 64%),
    var(--bg-raise);
}

.support-card:hover { box-shadow: 0 14px 40px rgba(97, 61, 178, 0.18); }

.support-card-icon {
  flex: none;
  display: grid;
  place-items: center;
  width: 46px;
  height: 46px;
  border-radius: 14px;
  color: var(--lavender);
  background: rgba(130, 95, 210, 0.14);
  border: 1px solid var(--hairline);
}

.support-card-icon svg { width: 22px; height: 22px; }

.support-card-body {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.support-card-body b {
  font-family: var(--font-head);
  font-size: 1.05rem;
  letter-spacing: -0.01em;
}

.support-card-body span {
  color: var(--text-muted);
  font-size: 0.94rem;
  overflow-wrap: anywhere;
}

.support-card-arrow {
  margin-left: auto;
  color: var(--text-dim);
  transition: transform 0.25s var(--ease-out), color 0.25s ease;
}

.support-card:hover .support-card-arrow {
  color: var(--lavender);
  transform: translateX(3px);
}

/* Quick topics — each opens a mail draft with the subject prefilled. */
.support-topics {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 14px;
  text-align: left;
}

.support-topics a {
  display: block;
  padding: 20px 22px;
  border-radius: 18px;
  background: var(--bg-raise);
}

.support-topics h3 {
  font-size: 1rem;
  margin-bottom: 6px;
}

.legal .support-topics p {
  color: var(--text-muted);
  font-size: 0.9rem;
  line-height: 1.5;
}

.legal .back {
  display: inline-block;
  margin-top: 44px;
  color: var(--text-muted);
  font-size: 0.94rem;
  transition: color 0.2s ease;
}

.legal .back:hover { color: var(--text); }

.footer-legal {
  text-align: center;
  padding: 36px var(--pad) 44px;
}

.footer-legal-links {
  display: flex;
  justify-content: center;
  gap: 26px;
  margin-bottom: 14px;
  font-size: 0.92rem;
  color: var(--text-muted);
}

.footer-legal-links a:hover { color: var(--text); }

/* ── Responsive ─────────────────────────────────────────────────────────── */

@media (max-width: 880px) {
  /* Keep Support visible but centered, so the header reads
     Elsewhere · Support · Download (logo left, Download right). */
  .nav-links {
    display: flex;
    margin: 0 auto;
    gap: 0;
  }

  .showcase-grid {
    grid-template-columns: 1fr;
  }

  .trail { display: none; }

  .showcase-phone {
    position: static;
    height: auto;
    order: -1;
    justify-content: center;
  }

  .feature, html.js .feature {
    min-height: 0;
    opacity: 1;
    transform: none;
    padding: 34px 0;
    border-bottom: 1px solid var(--hairline);
  }

  .feature:last-child { border-bottom: 0; }

  .showcase-copy {
    align-items: stretch;
    padding: 26px 0 0;
  }

  .steps { grid-template-columns: 1fr; }

  .support-topics { grid-template-columns: 1fr; }

  .footer-bottom { flex-direction: column; }
}

@media (max-width: 520px) {
  .launch { padding: 22px 32px; }
  .hero-cta .btn, .hero-cta .btn-line { flex: 1; }
}

/* ── Reduced motion: everything static, everything visible ─────────────── */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  .hl-in, .hero-sub, .hero-cta, .hero-fine {
    animation: none;
    opacity: 1;
    transform: none;
  }

  html.js .reveal { opacity: 1; transform: none; transition: none; }

  .feature, html.js .feature { opacity: 1; transform: none; transition: none; }

  .trail { display: none; }

  .scrub span { opacity: 1; transition: none; }
}
