/* nuriapp.io landing page.
   Hand-written; see site/README.md for why there is no build step.

   Design note: the audience is explicitly neurodivergent, so motion is used
   sparingly and every animation is opt-out via prefers-reduced-motion. Nothing
   loops forever in the viewport, nothing autoplays, nothing flashes. The page
   should feel alive on arrival and then settle down. */

* { box-sizing: border-box; }

html {
  background: #FFF7F9;
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
  /* clip, not hidden: clipping without turning html into a scroll container,
     which would break position:sticky on the nav. */
  overflow-x: clip;
}

body {
  margin: 0;
  font: 17px/1.65 var(--font);
  color: var(--body);
  background: transparent;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

/* ---------- the aurora ----------
   Three soft colour fields drifting behind the hero. Blur does the work, so
   they read as light rather than as shapes.

   Fixed to the viewport on purpose: the wash stays put while the hero scrolls
   over it. The bands get the same treatment via background-attachment below, so
   every section behaves alike. */
.aurora {
  position: fixed;
  inset: 0;
  z-index: -1;
  overflow: hidden;
  pointer-events: none;
  background: #FFF7F9;
}
.aurora span {
  position: absolute;
  display: block;
  border-radius: 50%;
  filter: blur(110px);
  opacity: .30;
  will-change: transform;
}
.aurora .a1 {
  width: 52vmax; height: 52vmax; top: -8vmax; left: -6vmax;
  background: var(--purple);
  animation: drift-a 34s ease-in-out infinite alternate;
}
.aurora .a2 {
  width: 46vmax; height: 46vmax; top: 6vmax; right: -6vmax;
  background: var(--coral);
  animation: drift-b 40s ease-in-out infinite alternate;
}
.aurora .a3 {
  width: 40vmax; height: 40vmax; top: 34vmax; left: 24vmax;
  background: var(--orange);
  opacity: .22;
  animation: drift-c 46s ease-in-out infinite alternate;
}
@keyframes drift-a { to { transform: translate3d(6vmax, 4vmax, 0) scale(1.1); } }
@keyframes drift-b { to { transform: translate3d(-5vmax, 6vmax, 0) scale(1.08); } }
@keyframes drift-c { to { transform: translate3d(4vmax, -5vmax, 0) scale(.94); } }

/* Scrim: keeps body text on a near-white ground no matter where the blobs
   drift, so contrast never depends on the animation frame. */
.aurora::after {
  content: "";
  position: absolute; inset: 0;
  background:
    radial-gradient(120% 70% at 50% 0%, rgba(255,255,255,.72) 0%, rgba(255,255,255,.3) 45%, transparent 75%),
    linear-gradient(180deg, rgba(255,255,255,.35) 0%, rgba(255,255,255,.55) 100%);
}

/* A whisper of grain over the gradients — stops wide colour fields from
   banding on 8-bit displays, and adds a little texture. */
.grain {
  position: fixed; inset: 0; z-index: -1; pointer-events: none; opacity: .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='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E");
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .aurora span { animation: none !important; }
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
}

/* ---------- type ---------- */

h1, h2, h3 { color: var(--ink); letter-spacing: -.035em; line-height: 1.05; margin: 0; }
h1 { font-size: clamp(2.7rem, 7vw, 4.6rem); font-weight: 800; }
h2 { font-size: clamp(2rem, 4.6vw, 3.2rem); font-weight: 800; }
h3 { font-size: 1.1rem; font-weight: 700; letter-spacing: -.02em; }
p { margin: 0; }
/* height:auto is load-bearing — the width/height attributes on the <img> tags
   reserve layout space to stop scroll jump, but without this the attribute
   height wins and the screenshots render at full pixel height. */
img { max-width: 100%; height: auto; display: block; }

.gradient-text {
  background: var(--grad-hero);
  -webkit-background-clip: text; background-clip: text;
  color: transparent;
  /* The descender on "thrive." clips without this. */
  padding-bottom: .08em;
}

/* ---------- hero ---------- */

.hero { padding: clamp(3rem, 7vw, 5.5rem) 0 clamp(3rem, 6vw, 4.5rem); }
.hero .container { display: grid; grid-template-columns: 1.05fr .95fr; gap: 3rem; align-items: center; }
.hero-copy { display: flex; flex-direction: column; align-items: flex-start; gap: 1.6rem; max-width: 34rem; }

.badge {
  display: inline-flex; align-items: center; gap: .55rem;
  background: rgba(255, 255, 255, .72); color: var(--ink);
  padding: .5rem 1.1rem; border-radius: 999px;
  font-size: .9rem; font-weight: 650;
  border: 1px solid rgba(255, 255, 255, .9);
  backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
  box-shadow: var(--shadow-sm);
}
.badge svg { color: var(--coral); }

.hero p.lede { font-size: 1.18rem; max-width: 30rem; }
.hero-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 1rem 1.6rem; }

@media (max-width: 920px) {
  .hero .container { grid-template-columns: 1fr; gap: 2.5rem; }
}

/* ---------- device frame ----------
   The screenshots are cropped app surfaces, not full phone captures, so this is
   a soft rounded slab rather than a bezel-and-notch phone. Honest about what it
   is showing, and it survives the screenshots being re-cropped later. */

/* The screenshots now carry the real iPhone bezel, cropped flush to the phone
   body. The corners are still square pixels — the source PNGs had transparent
   corners, but transparency costs 3x the file size in PNG, so the corners are
   clipped here instead. Measured off the alpha mask: the body is 757x1556 with
   a 103px corner, i.e. 13.61% of width and 6.62% of height. Rounded up a touch
   so the clip bites into the black bezel rather than leaving a grey sliver.
   All screenshots share this geometry; re-measure if the device changes. */
.device {
  position: relative; justify-self: center; max-width: 330px; width: 100%;
  /* Without a stacking context the z-index:-1 bloom below escapes and paints
     behind the *section* background, which is why it only ever showed in the
     hero — the one section with no background of its own. */
  isolation: isolate;
}
.device img {
  width: 100%;
  border-radius: 13.9% / 6.8%;
  box-shadow: 0 2px 4px rgba(20,21,26,.10), 0 30px 60px -18px rgba(20, 21, 26, .38);
}
/* A coloured bloom behind the slab so it sits in the page rather than on it. */
.device::before {
  content: ""; position: absolute; inset: 8% -12% -6%;
  background: var(--grad-hero); filter: blur(46px); opacity: .32; z-index: -1;
  border-radius: 50%;
}
.device.float { animation: bob 9s ease-in-out infinite alternate; }

/* The bands need a stronger bloom than the hero to read the same. The hero sits
   on near-white, where a purple-to-orange wash shows at .32; against saturated
   mint, sky and sand the same wash is partly cancelled by the band's own hue,
   so it gets lifted and spread wider. */
.band .device::before,
.band .device-pair::before {
  background: var(--band-bloom);
  opacity: .52;
  filter: blur(50px);
  inset: 6% -14% -8%;
}

/* A pair, for "see only what you need" — the filter menu over the month grid,
   which is what "switch views" actually means. */
.device-pair {
  position: relative; justify-self: center;
  width: 100%; max-width: 430px; aspect-ratio: 43 / 70;
  isolation: isolate;
}
.device-pair::before {
  content: ""; position: absolute; inset: 10% -6% 2%;
  background: var(--grad-hero); filter: blur(52px); opacity: .52; z-index: -1;
  border-radius: 50%;
}
.device-pair img {
  position: absolute; width: 62%;
  border-radius: 13.9% / 6.8%;
  box-shadow: 0 2px 4px rgba(20,21,26,.10), 0 26px 54px -16px rgba(20, 21, 26, .42);
}
.device-pair .back  { left: 0;  top: 0;     transform: rotate(-6deg); z-index: 1; }
.device-pair .front { right: 0; bottom: 0;  transform: rotate(4deg);  z-index: 2; }

@media (max-width: 520px) {
  /* Tilting two overlapping phones gets cramped on a narrow screen. */
  .device-pair { max-width: 340px; aspect-ratio: 34 / 62; }
  .device-pair img { width: 70%; }
  .device-pair .back { transform: rotate(-4deg); }
  .device-pair .front { transform: rotate(3deg); }
}
@keyframes bob { to { transform: translateY(-14px); } }

/* ---------- the three promise cards ---------- */

.promises {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 1.25rem;
  padding: 0 0 clamp(3rem, 6vw, 5rem); margin: 0; list-style: none;
}
.promise {
  position: relative;
  background: rgba(255, 255, 255, .62);
  border: 1px solid rgba(255, 255, 255, .85);
  border-radius: var(--radius-lg);
  padding: 1.8rem;
  box-shadow: var(--shadow-sm);
  backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
  display: flex; flex-direction: column; gap: .6rem;
  transition: transform .25s cubic-bezier(.2,.8,.2,1), box-shadow .25s ease;
}
.promise:hover { transform: translateY(-4px); box-shadow: var(--shadow); }
.promise .icon {
  display: grid; place-items: center; width: 44px; height: 44px;
  border-radius: 14px; margin-bottom: .4rem; color: #fff;
  box-shadow: var(--shadow-sm);
}
.promise p { font-size: .98rem; }

@media (max-width: 880px) { .promises { grid-template-columns: 1fr; } }

/* ---------- alternating feature bands ---------- */

.band { padding: clamp(3.5rem, 8vw, 6rem) 0; position: relative; }
/* Each band gets the hero's aurora treatment in its own hue: a bright bloom
   over one side and two deeper tones of the same family on the other.

   Each band carries FOUR distinct hues from its family, not one hue at several
   opacities — a base that only varies in lightness reads as a single flat
   colour. Mint runs green / teal / lime / aqua, sky runs blue / indigo / cyan /
   violet, sand runs amber / peach / rose / cream.

   The tints are saturated but LIGHT on purpose. Contrast depends on luminance,
   so hue can vary freely while the background stays pale enough for body copy.

   The radials are also kept small (~45%) and spread to four corners: these are
   background-attachment: fixed, so the band only ever shows a slice of the
   gradient, and a few big radials would put a single colour in that slice. Layered radial-gradients rather than blurred elements —
   same look, but no filter cost and nothing extra in the DOM. Static on
   purpose: these sit below the fold, where drifting colour is a distraction
   rather than an entrance. */
.band-mint {
  --band-bloom: linear-gradient(100deg, #6EE7B0 0%, #2CC191 52%, #17A79E 100%);
  background:
    radial-gradient(48% 42% at 20% 14%, rgba(110,231,183,.42) 0%, rgba(110,231,183,0) 70%),
    radial-gradient(44% 40% at 78% 34%, rgba(45,212,191,.40) 0%, rgba(45,212,191,0) 70%),
    radial-gradient(46% 42% at 44% 78%, rgba(163,230,120,.34) 0%, rgba(163,230,120,0) 70%),
    radial-gradient(40% 38% at 92% 88%, rgba(94,234,212,.34) 0%, rgba(94,234,212,0) 70%),
    linear-gradient(150deg, #F0FDF6 0%, #DFF7EA 45%, #D6F3EE 100%);
}
.band-sky {
  --band-bloom: linear-gradient(100deg, #9BC8FD 0%, #4A8BF5 52%, #6366F1 100%);
  background:
    radial-gradient(48% 42% at 22% 16%, rgba(147,197,253,.44) 0%, rgba(147,197,253,0) 70%),
    radial-gradient(44% 40% at 80% 32%, rgba(165,180,252,.42) 0%, rgba(165,180,252,0) 70%),
    radial-gradient(46% 42% at 40% 80%, rgba(125,211,252,.38) 0%, rgba(125,211,252,0) 70%),
    radial-gradient(40% 38% at 90% 90%, rgba(196,181,253,.32) 0%, rgba(196,181,253,0) 70%),
    linear-gradient(150deg, #F2F7FF 0%, #E3EDFE 45%, #E6E9FD 100%);
}
.band-sand {
  --band-bloom: linear-gradient(100deg, #FBD08C 0%, #F2A06A 52%, #E5838C 100%);
  background:
    radial-gradient(48% 42% at 20% 14%, rgba(253,211,141,.46) 0%, rgba(253,211,141,0) 70%),
    radial-gradient(44% 40% at 80% 34%, rgba(249,168,134,.42) 0%, rgba(249,168,134,0) 70%),
    radial-gradient(46% 42% at 42% 80%, rgba(252,165,165,.34) 0%, rgba(252,165,165,0) 70%),
    radial-gradient(40% 38% at 92% 88%, rgba(253,224,171,.40) 0%, rgba(253,224,171,0) 70%),
    linear-gradient(150deg, #FEF8EF 0%, #FBEBDA 45%, #FAE7E2 100%);
}

.band-mint, .band-sky, .band-sand { background-attachment: fixed; }

.band .container { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(2rem, 5vw, 4.5rem); align-items: center; }
.band-copy { display: flex; flex-direction: column; gap: 1.2rem; max-width: 32rem; }
.band-copy .sub { font-size: clamp(1.2rem, 2.2vw, 1.55rem); font-weight: 700; color: var(--ink); letter-spacing: -.025em; line-height: 1.25; }
.band-reverse .device { order: -1; }

.eyebrow {
  align-self: flex-start;
  font-size: .82rem; font-weight: 750; letter-spacing: .09em; text-transform: uppercase;
  color: var(--coral-ink);
}

.pill {
  align-self: flex-start;
  background: rgba(255, 255, 255, .8);
  padding: .55rem 1.1rem; border-radius: 999px;
  font-size: .92rem; font-weight: 650; color: var(--ink);
  border: 1px solid rgba(255, 255, 255, .95);
  box-shadow: var(--shadow-sm);
}

/* Mobile stacks the copy full-width above the phone, so any hue transition in
   the gradient has nowhere to land except through the text — it cut across
   "Life is complicated..." in mint and sky. Desktop is fine because the copy
   only occupies half the width and the transitions fall in open space.

   So at narrow widths: near-white across the top where the copy sits, colour
   pooled low behind the phone, and much larger radials so what transition
   remains is gradual. Also switched to scroll attachment — fixed sweeps the
   gradient through the copy as you scroll, and iOS ignores it anyway. */
@media (max-width: 920px) {
  .band-mint, .band-sky, .band-sand { background-attachment: scroll; }

  .band-mint {
    background:
      radial-gradient(150% 40% at 32% 102%, rgba(45,212,191,.42) 0%, rgba(45,212,191,0) 76%),
      radial-gradient(140% 34% at 82% 84%, rgba(110,231,183,.38) 0%, rgba(110,231,183,0) 78%),
      radial-gradient(130% 30% at 12% 68%, rgba(163,230,120,.26) 0%, rgba(163,230,120,0) 80%),
      linear-gradient(180deg, #F5FDFA 0%, #EDFBF4 40%, #DCF6EE 100%);
  }
  .band-sky {
    background:
      radial-gradient(150% 40% at 32% 102%, rgba(165,180,252,.44) 0%, rgba(165,180,252,0) 76%),
      radial-gradient(140% 34% at 82% 84%, rgba(147,197,253,.40) 0%, rgba(147,197,253,0) 78%),
      radial-gradient(130% 30% at 12% 68%, rgba(125,211,252,.26) 0%, rgba(125,211,252,0) 80%),
      linear-gradient(180deg, #F7FAFF 0%, #EFF5FE 40%, #E4EAFD 100%);
  }
  .band-sand {
    background:
      radial-gradient(150% 40% at 32% 102%, rgba(249,168,134,.44) 0%, rgba(249,168,134,0) 76%),
      radial-gradient(140% 34% at 82% 84%, rgba(253,211,141,.42) 0%, rgba(253,211,141,0) 78%),
      radial-gradient(130% 30% at 12% 68%, rgba(252,165,165,.26) 0%, rgba(252,165,165,0) 80%),
      linear-gradient(180deg, #FFFBF4 0%, #FDF3E8 40%, #FAE9E0 100%);
  }
}

@media (max-width: 920px) {
  .band .container { grid-template-columns: 1fr; }
  .band-reverse .device { order: 0; }
}

/* ---------- about ---------- */

.about {
  padding: clamp(3.5rem, 8vw, 6rem) 0; text-align: center;
}
.about-intro { max-width: 44rem; margin: 0 auto; display: flex; flex-direction: column; gap: 1.2rem; }
.story {
  margin-top: 3rem; text-align: left;
  background: rgba(255, 255, 255, .7);
  border: 1px solid rgba(255, 255, 255, .9);
  border-radius: var(--radius-xl);
  padding: clamp(1.75rem, 4vw, 3.2rem);
  box-shadow: var(--shadow);
  backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
  display: flex; flex-direction: column; gap: 1.1rem;
  position: relative; overflow: hidden;
}
/* A gradient hairline along the top edge of the card. */
.story::before {
  content: ""; position: absolute; top: 0; left: 0; right: 0; height: 3px;
  background: var(--grad-hero);
}
.story h3 { font-size: 1.55rem; letter-spacing: -.03em; }

/* ---------- closing CTA ---------- */

.cta {
  padding: clamp(3.5rem, 8vw, 6rem) 0;
}
.cta-inner {
  position: relative; overflow: hidden;
  border-radius: var(--radius-xl);
  background: var(--grad-hero);
  padding: clamp(2.5rem, 6vw, 4.5rem) 1.5rem;
  text-align: center;
  display: flex; flex-direction: column; align-items: center; gap: 1.25rem;
  box-shadow: 0 30px 70px -25px rgba(221, 95, 164, .65);
}
.cta-inner h2, .cta-inner p { color: #fff; }
.cta-inner p { max-width: 36rem; opacity: .95; }
.cta-inner .btn-on-grad {
  background: #fff; color: var(--ink); box-shadow: 0 10px 30px -8px rgba(20,21,26,.35);
}
.cta-inner .btn-on-grad:hover { transform: translateY(-2px); background: #fff; }
.cta-note { font-size: .93rem; }
.cta-note a { color: #fff; }

/* ---------- scroll reveal ----------
   Added by landing.js only when IntersectionObserver exists and the visitor has
   not asked for reduced motion, so content is never hidden by a broken script. */
.reveal { opacity: 0; transform: translateY(18px); transition: opacity .7s ease, transform .7s cubic-bezier(.2,.8,.2,1); }
.reveal.is-in { opacity: 1; transform: none; }

/* ---------- waitlist dialog ---------- */

dialog.sheet {
  width: min(28rem, calc(100vw - 2rem));
  border: 0; border-radius: var(--radius-lg); padding: 0;
  box-shadow: var(--shadow-lg); color: var(--body); background: #fff;
}
dialog.sheet::backdrop { background: rgba(20, 21, 26, .5); backdrop-filter: blur(4px); }
.sheet-inner { padding: 1.9rem; display: flex; flex-direction: column; gap: 1.25rem; }
.sheet-head { display: flex; gap: .9rem; align-items: flex-start; }
.sheet-head .icon {
  display: grid; place-items: center; width: 36px; height: 36px;
  border-radius: 12px; background: var(--grad-hero); color: #fff; flex-shrink: 0;
}
.sheet-head p { font-size: .96rem; }

.field { display: flex; flex-direction: column; gap: .4rem; margin-bottom: .9rem; }
.field label { font-weight: 650; font-size: .92rem; color: var(--ink); }
.field input {
  font: inherit; font-size: 1rem; color: var(--ink);
  padding: .75rem .95rem; border: 1px solid var(--line); border-radius: var(--radius-sm);
  background: #fff; width: 100%;
  transition: border-color .15s ease, box-shadow .15s ease;
}
.field input:focus-visible {
  outline: none; border-color: var(--coral);
  box-shadow: 0 0 0 3px rgba(241, 99, 131, .18);
}

.sheet-actions { display: flex; flex-wrap: wrap; gap: .6rem; }
.sheet-actions .btn { flex: 1 1 auto; }

/* Announced to screen readers via aria-live in the markup. */
.status { font-size: .93rem; margin: 0 0 .25rem; }
.status[data-tone="ok"] { color: #12794F; }
.status[data-tone="error"] { color: #B3253F; }
.status:empty { display: none; }
