/* NestUp — nestup.best
   Colours are copied verbatim from the app's src/theme/colors.ts so the site
   and the product are the same brand. Two rules carried over from the app:
   never pure white, never pure black. */

/* Type. See build-font.py — every face is subset to the glyphs actually used.
   A browser only fetches a face it needs to render, so the Hebrew page never
   downloads Fraunces and the English page never downloads the Hebrew faces,
   even though all of them are declared here.

   Paths are relative to this stylesheet, not to the page, so /en/ resolves
   them correctly without a second copy of the file. */

/* Display, both languages. Rubik carries Latin and Hebrew in one family, so
   the two pages speak with a single voice instead of pairing two unrelated
   faces. Rounded and geometric — young and warm, which is the register a
   consumer app for parents wants. */
@font-face {
  font-family: "Rubik Display";
  src: url("assets/rubik-display.woff2") format("woff2");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}

/* Body, both languages. Assistant carries Latin too, and the system Hebrew
   fallback varies wildly across devices — the difference between "designed"
   and "typed into a box". */
@font-face {
  font-family: "Assistant";
  src: url("assets/assistant-body.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Assistant";
  src: url("assets/assistant-bold.woff2") format("woff2");
  font-weight: 600 700;
  font-style: normal;
  font-display: swap;
}

:root {
  --rose-700: #A95F70;   /* the only rose that clears AA on the light ground */
  --rose-900: #8B4E5D;
  --rose-200: #F3B6C2;
  --rose-100: #F8DEE3;
  --sage-500: #7C9A82;
  --sand-100: #F1E4CE;
  --sky-100:  #E6EFF3;

  --bg:      #FAF8F4;
  --surface: #FEFDFB;
  --line:    #E3E0D6;
  --text:    #2B2B28;
  --text-2:  #726F65;
  --danger:  #9E4B4B;

  --display: "Rubik Display", "Rubik", -apple-system, BlinkMacSystemFont, "Segoe UI", Arial, sans-serif;
  --sans: "Assistant", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;

  /* One ratio-based scale, so no spacing value is arbitrary. The top of the
     scale is deliberately restrained: this is a three-section landing page,
     and editorial-sized section gaps just make it feel padded. */
  --s1: .5rem;  --s2: 1rem;  --s3: 1.5rem;  --s4: 2.5rem;
  --s5: 3rem;   --s6: 4rem;  --s7: 5rem;

  --shell: 1180px;
  --ease: cubic-bezier(.22, 1, .36, 1);
}

/* Both languages now share both families, so there is nothing to swap —
   which is the point: one product, two languages, one voice.

   Hebrew still wants its own line settings. It has no ascenders or
   descenders, so the same line-height reads tighter, and negative tracking
   closes counters that are already narrow. */
:lang(he) h1, :lang(he) h2, :lang(he) h3 {
  letter-spacing: 0;
  line-height: 1.2;
}

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* The hero halo is deliberately wider than the viewport so the colour bleeds
     off both edges. Clipping here — on html, not only body — is what stops
     that bleed from becoming a horizontal scrollbar. `clip` rather than
     `hidden` so it never creates a scroll container and breaks the sticky
     header. */
  overflow-x: clip;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--sans);
  font-size: 17px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  overflow-x: clip;
}

/* A barely-there grain. Flat colour fields read as digital; a little noise
   reads as printed, which is most of the "premium" impression here. */
body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 100;
  pointer-events: none;
  opacity: .035;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

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

h1, h2, h3 {
  margin: 0;
  font-family: var(--display);
  font-weight: 600;
  letter-spacing: -.015em;
  line-height: 1.06;
  text-wrap: balance;
}

p { margin: 0; }
a { color: inherit; }

.sr-only {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}

/* Clipped rather than parked at left:-9999px. Off-canvas negative offsets
   extend the scrollable area on an RTL page, where the inline origin is the
   right edge — which is a 10,000px horizontal scroll, not a hidden element. */
.skip {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  z-index: 110;
}
.skip:focus {
  width: auto; height: auto;
  margin: 0; overflow: visible;
  clip-path: none;
  inset-block-start: var(--s2);
  inset-inline-start: var(--s2);
  background: var(--surface);
  padding: var(--s2);
  border-radius: 12px;
}

:focus-visible { outline: 2px solid var(--rose-700); outline-offset: 3px; border-radius: 6px; }

/* The authored line breaks are a desktop typesetting decision. On narrow
   screens they fight text-wrap:balance and produce a worse rag. */
.bp { display: none; }

/* ---------- buttons ---------- */

.btn {
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--rose-700);
  color: var(--surface);
  font-family: var(--sans);
  font-size: 1rem;
  text-decoration: none;
  font-weight: 620;
  letter-spacing: -.01em;
  border: 0;
  border-radius: 999px;
  cursor: pointer;
  /* 44px is the iOS minimum touch target; nothing here goes under it. */
  min-height: 44px;
  padding: 0 var(--s3);
  box-shadow: 0 1px 2px rgba(43, 43, 40, .12), 0 10px 26px -10px rgba(169, 95, 112, .6);
  transition: background .18s var(--ease), transform .18s var(--ease);
}
.btn:hover { background: var(--rose-900); transform: translateY(-1px); }
.btn:active { transform: translateY(0); }

.btn-sm { font-size: .95rem; padding: 0 1.15rem; }
.btn-lg { min-height: 56px; padding: 0 var(--s4); font-size: 1.08rem; }

.fine { color: var(--text-2); font-size: .9rem; }

/* ---------- header ---------- */

.bar {
  position: sticky; top: 0; z-index: 20;
  display: flex; align-items: center; justify-content: space-between; gap: var(--s2);
  max-width: var(--shell);
  margin: 0 auto;
  padding: .8rem var(--s3);
  background: color-mix(in srgb, var(--bg) 80%, transparent);
  backdrop-filter: saturate(160%) blur(14px);
}
@supports not (backdrop-filter: blur(1px)) { .bar { background: var(--bg); } }

.lockup {
  display: inline-flex; align-items: center; gap: .55rem;
  min-height: 44px;
  text-decoration: none; font-weight: 660; letter-spacing: -.02em; font-size: 1.08rem;
}
.lockup img { border-radius: 8px; }
/* The wordmark is a Latin logotype in both languages, so it keeps its own
   direction even on the RTL page. */
.lockup span { direction: ltr; unicode-bidi: isolate; }

.bar-end { display: flex; align-items: center; gap: .35rem; }

.lang {
  display: inline-flex; align-items: center;
  min-height: 44px; padding: 0 .7rem;
  border-radius: 999px;
  text-decoration: none;
  font-size: .92rem; font-weight: 600;
  color: var(--text-2);
}
.lang:hover { color: var(--text); background: color-mix(in srgb, var(--line) 45%, transparent); }

/* Names the pilot city without dressing it up as a badge of endorsement. */
.pill {
  /* Deliberately not a flex container. The label mixes text with a nowrap
     span, and flex makes each an anonymous item, trimming the whitespace
     between them — "Starting inTel Aviv-Yafo". Normal inline flow keeps the
     sentence a sentence. */
  display: inline-block;
  margin-bottom: var(--s2);
  padding: .3rem .8rem;
  border: 1px solid color-mix(in srgb, var(--rose-200) 70%, transparent);
  border-radius: 999px;
  background: color-mix(in srgb, var(--rose-100) 45%, transparent);
  color: var(--rose-900);
  font-size: .82rem; font-weight: 600;
  letter-spacing: .01em;
}
.pill::before {
  content: "";
  display: inline-block;
  width: 6px; height: 6px;
  margin-inline-end: .45rem;
  border-radius: 999px;
  background: var(--rose-700);
  vertical-align: middle;
}

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

.hero {
  max-width: var(--shell);
  margin: 0 auto;
  padding: var(--s3) var(--s3) var(--s5);
  display: grid;
  gap: var(--s3);
  justify-items: center;
  text-align: center;
}

/* The halo deliberately bleeds left across this column, so the type needs its
   own stacking context to sit above it. Without this the blurred colour field
   paints over the end of the headline and washes the letters out. */
.hero-type { position: relative; z-index: 2; }

/* Rubik sets wider than a serif at the same size, so the mobile step is a
   little smaller than it was — enough to keep the headline tight and leave
   the device visible in the first viewport. */
.hero h1 { font-size: clamp(2.15rem, 8.4vw, 3.1rem); }

.lede {
  margin-top: var(--s2);
  color: var(--text-2);
  font-size: clamp(1.05rem, 4.2vw, 1.18rem);
  max-width: 34ch;
  margin-inline: auto;
  text-wrap: pretty;
}

.join-fine { margin-top: var(--s2); }

/* A plain hyphen is a legal break point, so "Tel Aviv-Yafo" splits across
   lines without this. */
.nb { white-space: nowrap; }

/* The stage is the art direction: a soft brand field the device sits in front
   of, rather than a phone parked beside a column of text. */
.stage {
  position: relative;
  margin: 0;
  width: 100%;
  display: flex;
  justify-content: center;
  /* Distance matters: too little and the 3D tilt looks like a funhouse
     mirror instead of a phone held at a slight angle. */
  perspective: 2200px;
}

.halo {
  position: absolute;
  inset: 10% -24% 6%;
  background:
    radial-gradient(60% 50% at 30% 25%, var(--rose-100), transparent 70%),
    radial-gradient(55% 45% at 75% 60%, var(--sky-100), transparent 70%),
    radial-gradient(50% 40% at 50% 95%, var(--sand-100), transparent 72%);
  filter: blur(30px);
  z-index: 0;
}

/* ---------- device ----------
   Built to read as a photographed object: a rail that catches light along its
   edges, real side keys, a clipped screen, one soft glare, and a shadow cast
   in the direction the tilt implies. */

.device {
  position: relative;
  z-index: 1;
  width: 272px;
  flex: none;
  transform-style: preserve-3d;
}

.device-body {
  position: relative;
  padding: 9px;
  border-radius: 50px;
  /* The angled gradient is the titanium rail: bright where an edge would
     catch the light, dark across the flat of the frame. */
  background: linear-gradient(146deg,
      #5a5a63 0%, #24242a 9%, #101014 26%,
      #17171c 52%, #0d0d11 74%, #33333b 92%, #6b6b75 100%);
  box-shadow:
    inset 0 0 0 1px rgba(255, 255, 255, .14),
    inset 0 1px 1px rgba(255, 255, 255, .22),
    0 2px 6px rgba(43, 43, 40, .18),
    0 34px 64px -26px rgba(43, 43, 40, .5);
}

.device-screen {
  position: relative;
  /* The inner radius must be the outer radius minus the bezel, or the screen
     corners cut through the frame. */
  border-radius: 41px;
  overflow: hidden;
  background: var(--surface);
  /* Seats the glass slightly below the rail. */
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .55);
}

.device-shot { width: 100%; }

.device-island {
  position: absolute;
  top: 11px; left: 50%;
  transform: translateX(-50%);
  width: 78px; height: 23px;
  background: #08080a;
  border-radius: 999px;
}

/* A single soft sheen across the glass. More than one reads as decoration. */
.device-glare {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(104deg,
      transparent 26%,
      rgba(255, 255, 255, .10) 38%,
      rgba(255, 255, 255, .16) 44%,
      rgba(255, 255, 255, .03) 52%,
      transparent 66%);
}

.device-key {
  position: absolute;
  width: 2px;
  border-radius: 2px;
  background: linear-gradient(180deg, #4a4a53, #1b1b20 40%, #4a4a53);
}
.device-key-silent { left: -1px; top: 96px;  height: 26px; }
.device-key-up     { left: -1px; top: 138px; height: 46px; }
.device-key-down   { left: -1px; top: 196px; height: 46px; }
.device-key-power  { right: -1px; top: 164px; height: 70px; }

/* ---------- 02 proof ---------- */

.proof {
  max-width: var(--shell);
  margin: 0 auto;
  padding: 0 var(--s3) var(--s5);
}

/* Sized in rem, not ch: this element's own font is the 18px sans, so a ch
   measure here would constrain the display serif inside it to roughly half
   the intended width. */
.proof-head { max-width: 22rem; margin-bottom: var(--s3); }
.proof-head h2 { font-size: clamp(2rem, 7.4vw, 2.6rem); }

.kicker {
  font-family: var(--sans);
  /* rose-700 measures 4.34:1 here. At 12.5px this is not "large text", so it
     needs the full 4.5:1 — the darker rose clears it at 6.1:1. */
  color: var(--rose-900);
  font-size: .78rem; font-weight: 680;
  letter-spacing: .16em; text-transform: uppercase;
  margin-bottom: .8rem;
}

.duo { display: grid; gap: var(--s4); }

.duo-item { margin: 0; display: grid; gap: var(--s2); justify-items: center; text-align: center; }

.duo-item h3 { font-size: 1.4rem; margin-bottom: .55rem; }
.duo-item figcaption { max-width: 32ch; }
.duo-item figcaption p { color: var(--text-2); text-wrap: pretty; }

/* These two screens are content-dense at the top and quiet further down.
   Showing the whole device would put empty app space on the page, so the
   window crops to the part that carries the story and fades the device out
   rather than cutting it off with a hard line. */
.window {
  position: relative;
  width: 100%;
  height: 268px;
  display: flex;
  justify-content: center;
  overflow: hidden;
}

/* The fade is a gradient scrim painted on top, rather than a mask-image on
   .window. Over a flat background the two are visually identical, and the
   scrim avoids both the -webkit- prefix and creating a masked compositing
   layer around the transformed device inside. */
.window::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 34%;
  z-index: 2;
  pointer-events: none;
  background: linear-gradient(180deg, transparent, var(--bg) 92%);
}

.device-sm { width: 232px; align-self: start; }
.device-sm .device-body { padding: 8px; border-radius: 44px; }
.device-sm .device-screen { border-radius: 36px; }
.device-sm .device-island { top: 10px; width: 66px; height: 20px; }
.device-sm .device-key-silent { top: 82px;  height: 22px; }
.device-sm .device-key-up     { top: 118px; height: 40px; }
.device-sm .device-key-down   { top: 168px; height: 40px; }
.device-sm .device-key-power  { top: 140px; height: 60px; }

/* ---------- 03 close ---------- */

.close {
  display: grid;
  justify-items: center;
  gap: var(--s2);
  text-align: center;
  padding: var(--s5) var(--s3) var(--s4);
  background:
    radial-gradient(72% 100% at 50% 0%, var(--rose-100), transparent 72%),
    var(--bg);
  border-top: 1px solid var(--line);
}
.close-mark { border-radius: 15px; }
.close h2 { font-size: clamp(2rem, 8vw, 2.9rem); }
.close .lede { margin-top: 0; }

/* ---------- join ---------- */

.join { width: 100%; max-width: 26rem; margin-top: var(--s3); }
.join-wide { max-width: 30rem; }

.join[data-state="done"] .join-form,
.join[data-state="done"] .join-trigger { display: none; }
.join[data-state="open"] .join-trigger,
.join[data-state="sending"] .join-trigger { display: none; }

/* Signing up a partner or a friend is a normal thing to do, so the resolved
   state offers a way back to the field instead of being a dead end. Only
   shown once there is something to add another *to*. */
.join-again { display: none; }
.join[data-state="done"] .join-again { display: inline-flex; }

.join-again {
  align-items: center;
  min-height: 44px;
  margin-top: .25rem;
  padding: 0 .25rem;
  border: 0;
  background: none;
  font: inherit;
  font-size: .92rem;
  font-weight: 600;
  color: var(--rose-900);
  text-decoration: underline;
  text-underline-offset: 3px;
  cursor: pointer;
}
.join-again:hover { color: var(--text); }

/* The field and its submit are one object, so the pill reads as a single
   control rather than an input with a button stuck next to it. */
/* `display:flex` below would otherwise beat the user-agent rule for [hidden],
   leaving the form visible next to the trigger before it is opened. */
.join-form[hidden] { display: none; }

.join-form {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 6px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 999px;
  box-shadow: 0 1px 2px rgba(43, 43, 40, .05), 0 14px 30px -18px rgba(43, 43, 40, .3);
  transition: border-color .18s var(--ease), box-shadow .18s var(--ease);
}
.join-form:focus-within {
  border-color: var(--rose-200);
  box-shadow: 0 0 0 4px var(--rose-100), 0 14px 30px -18px rgba(43, 43, 40, .3);
}

.join-input {
  flex: 1 1 auto;
  min-width: 0;               /* lets the field shrink instead of overflowing */
  min-height: 44px;
  /* Logical, so the field's inner padding mirrors correctly in RTL. */
  padding-inline: 1rem .5rem;
  border: 0;
  background: transparent;
  font: inherit;
  /* 16px minimum, or iOS Safari zooms the page on focus. */
  font-size: max(16px, 1rem);
  color: var(--text);
}
.join-input::placeholder { color: color-mix(in srgb, var(--text-2) 70%, transparent); }
/* The field stays dir="ltr" because an email address is LTR text, but on the
   RTL page it is aligned to the reading edge so the address starts where the
   eye does instead of pressed up against the submit button. */
[dir="rtl"] .join-input { text-align: right; }
.join-input:focus { outline: none; }
.join-input[aria-invalid="true"] { color: var(--danger); }

.join-go {
  flex: none;
  display: inline-flex; align-items: center; justify-content: center; gap: .5rem;
  min-width: 44px; min-height: 44px;
  padding: 0;
  border: 0; border-radius: 999px;
  background: var(--rose-700);
  color: var(--surface);
  font: inherit; font-weight: 620;
  cursor: pointer;
  transition: background .18s var(--ease);
}
.join-go:hover { background: var(--rose-900); }
/* The arrow means "forward", which is leftward in Hebrew. */
[dir="rtl"] .join-arrow { transform: scaleX(-1); }
.join-go-wide { padding: 0 1.25rem; }
.join-go-label { display: none; }

.join[data-state="sending"] .join-go { pointer-events: none; opacity: .75; }
.join[data-state="sending"] .join-go svg { animation: pulse 1s ease-in-out infinite; }

@keyframes pulse { 50% { opacity: .35; } }

/* Clipped rather than display:none — a bot reading the DOM should still find
   something to fill in. Not parked off-canvas either: a negative offset would
   extend the scrollable area on the RTL page. */
.join-hp {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* Collapsed until it has something to say, otherwise the reserved line reads
   as a spacing mistake under the button. The shift when it appears is
   user-initiated, so it does not count against CLS. */
.join-msg:empty { display: none; }

.join-msg {
  margin-top: .85rem;
  font-size: .92rem;
  text-wrap: pretty;
}
.join-msg[data-tone="ok"]  { color: var(--rose-900); font-weight: 600; }
.join-msg[data-tone="bad"] { color: var(--danger); }

/* Resolved state: the pill is replaced by a mark, so success is a visual
   event rather than a line of text appearing. */
.join[data-state="done"] .join-msg::before {
  content: "";
  display: inline-block;
  vertical-align: -.28em;
  width: 1.2em; height: 1.2em;
  margin-right: .5rem;
  border-radius: 999px;
  background: var(--rose-700) no-repeat center / .7em .7em;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23FEFDFB' stroke-width='3.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 12.6l5.2 5.2L20 7'/%3E%3C/svg%3E");
}

/* Centred layouts need the pill and its message centred too. */
.hero .join, .close .join { margin-inline: auto; }
.close .join-msg, .hero .join-msg { text-align: center; }

/* ---------- footer ---------- */

.foot {
  max-width: var(--shell);
  margin: 0 auto;
  padding: var(--s3);
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: var(--s2);
  color: var(--text-2);
  font-size: .9rem;
}
.foot nav { display: flex; flex-wrap: wrap; gap: var(--s2); }
/* Inline text links would be ~23px tall. Padding brings every target up to
   the 44px floor without changing how they look. */
.foot a {
  text-decoration: none;
  display: inline-flex; align-items: center;
  min-height: 44px; padding: 0 .5rem;
}
.foot a:hover { color: var(--text); text-decoration: underline; }

/* ---------- motion ----------
   Entrance only, and only where supported. Nothing here is required to read
   the page: if it never runs, the end state is already the default. */

@media (prefers-reduced-motion: no-preference) {
  @supports (animation-timeline: view()) {
    .reveal {
      animation: rise linear both;
      animation-timeline: view();
      animation-range: entry 5% cover 32%;
    }
  }
  @keyframes rise {
    from { opacity: 0; transform: translateY(28px) scale(.975); }
    to   { opacity: 1; transform: none; }
  }
}

/* ---------- 430px and up ---------- */

@media (min-width: 430px) {
  .device { width: 300px; }
  .device-sm { width: 252px; }
  .join-go-label { display: inline; }
}

/* ---------- tablet ---------- */

@media (min-width: 760px) {
  body { font-size: 18px; }
  .duo { grid-template-columns: 1fr 1fr; gap: var(--s4); align-items: start; }
  .window { height: 290px; }
}

/* ---------- desktop ----------
   The hero becomes one overlapping composition: the type sits on the left of
   the stage and the halo bleeds past it, so the two read as a single frame
   rather than two columns parked side by side. */

@media (min-width: 1000px) {
  .bp { display: inline; }

  .hero {
    /* The type column has to hold "Your parent community" on one line at the
       display size; the device only needs its own width plus room to tilt. */
    grid-template-columns: 1.2fr .8fr;
    align-items: center;
    justify-items: start;
    text-align: start;
    gap: var(--s3);
    padding: var(--s3) var(--s3) var(--s6);
  }

  .hero h1 { font-size: clamp(3rem, 4.1vw, 3.8rem); }
  .hero .lede, .hero .join { margin-inline: 0; }
  .lede { max-width: 32ch; }
  .hero .join-msg { text-align: start; }

  /* Centred in its column rather than pushed to the far edge — hard-right
     alignment opened a wide dead gap between the headline and the device. */
  .stage { justify-content: center; }

  /* Held at a slight angle rather than lying flat on the page. Kept shallow
     so the UI inside stays legible — the point is depth, not spectacle. */
  .device-hero {
    width: 300px;
    transform: rotateY(-13deg) rotateX(3deg) rotate(-1.5deg);
    transition: transform .6s var(--ease);
  }
  .device-hero .device-body {
    /* Shadow falls away from the tilt, which is what sells the angle. */
    box-shadow:
      inset 0 0 0 1px rgba(255, 255, 255, .14),
      inset 0 1px 1px rgba(255, 255, 255, .22),
      0 2px 6px rgba(43, 43, 40, .18),
      44px 44px 80px -34px rgba(43, 43, 40, .55);
  }
  /* Straightens on hover — a small reward, not a requirement. */
  .stage:hover .device-hero { transform: rotateY(-4deg) rotateX(1deg) rotate(-.5deg); }

  /* Bleeds far past the type side so the colour field unifies the headline
     and the device. Logical insets, so it mirrors with the layout in RTL
     instead of bleeding off the wrong edge. */
  .halo {
    inset-block: -16%;
    inset-inline: -58% -32%;
    filter: blur(50px);
  }

  /* Narrower than the hero shell. The hero needs width for the two-column
     composition; this section is a heading and two phones, and at full shell
     width the pair drifted so far apart they stopped reading as a pair. */
  .proof { max-width: 940px; }
  .proof-head { max-width: 32rem; margin-bottom: var(--s4); }
  .proof-head h2 { font-size: 2.6rem; }

  /* Aligned, not staggered. Offsetting one column looked considered in a
     mockup, but it left a column of dead space under the shorter one and
     pushed the closing section down the page for no benefit. */
  .duo { gap: var(--s4); }
  .window { height: 320px; }
  .device-sm { width: 232px; }
  /* A slight tilt toward each other, so the pair still reads as two objects
     placed on the page rather than two rows of a table. */
  .duo-item:first-child .device-sm .device-body { transform: rotate(-2deg); }
  .duo-item:last-child .device-sm .device-body { transform: rotate(2deg); }
}

@media (min-width: 1240px) {
  .device-hero { width: 324px; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
  }
  .device-hero, .device-sm .device-body { transform: none !important; }
}
